LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software
User Name
Password
Linux - Software This forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.

Notices


Reply
  Search this Thread
Old 09-14-2011, 09:37 PM   #1
ludwig
Member
 
Registered: Jun 2002
Location: Orange County, CA
Distribution: Debian (squeeze), kernel 2.6.30-2-amd64
Posts: 32

Rep: Reputation: 15
C Programming: How to link with glibc using "ld"?


Hi All,

I'm experimenting with separate compilation and have tried to get down to "the basics" of the build process. I've created a main module called foo.c that has a main function calling printf to write "Hello world" to stdout.

If I compile only (without linking) using "gcc -c foo.c", I see no warnings or errors and the result is a file new called foo.o.

I know I could link with "gcc foo.o" and get a.out, but I'm trying to do it using the linker using "ld foo.o". However, here's what happens:

----------------------------------------
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048074
foo.o: In function `main':
foo.c.text+0x19): undefined reference to `printf'
----------------------------------------

My question is: what does one need to do to get ld to find the printf function? I think its object code is in glibc, but I haven't been able to find the command to tell ld how to grab that code.

Thanks in advance!

Last edited by ludwig; 09-14-2011 at 09:40 PM.
 
Old 09-15-2011, 02:10 AM   #2
rigor
Member
 
Registered: Sep 2003
Location: 19th moon ................. ................Planet Covid ................Another Galaxy;............. ................Not Yours
Posts: 705

Rep: Reputation: Disabled
It's not exactly that simple.

In addition to the compiled version of the code you write, and the functions in libraries such as glibc, there are other pieces that get combined together to provide a context of sorts that the system expects to be present in an executable file.

In some environments, if you start with your foo.o and run this command:

Code:
gcc -v foo.o
you will get a.out as usual, but in principle, you will also be shown:

* something of the configuration of gcc.
* related environment variables.
* a list of directories in which libraries will be sought.
* the names of the standard files, those other pieces I mentioned, that are combined with foo.o.
* a whole collection of options to specify exactly what the linking step is to do.
* with the -l options, a portion of the name of the libraries to be used to link your particular program.


Generally, if you see an option such as -labc that says that the linker should try to find a library that is conceptually named libabc. In the case of your foo.o file you should see options such as -lc which tells the linkage procedure to look for a library conceptually named libc, and another option -lgcc says to look for a library conceptually named libgcc.

I'm speaking about the conceptual name of the library to distinguish that name from the specific name of the file containing the library.

In the system I'm using, the library conceptually known as libgcc actually has a full file name of:

Quote:
/usr/lib64/gcc/x86_64-suse-linux/4.5/libgcc.a
The extension .a on the name of the file containing the library, relates to the form of the library file. Library files can have various forms. On the system I'm using, the -v shows me a list of directories in which libraries can be sought during linking, the directory /usr/lib64/gcc/x86_64-suse-linux/4.5 is just one of several on the list.

Typically, by default, the printf function won't actually be included in a.out. Instead an indication of where to find printf will be included in a.out, printf will be loaded from the library when a.out is run. That's dynamic linking.

If you supply the right options to gcc, a.out could be statically linked, in which case the printf function would be copied into a.out when a.out is created.

I create a foo.c with the contents you describe, then allow gcc to create a.out from it.

The file command can display the conceptual type of a file. if I run the file command on a.out:

Code:
file a.out
the file command displays this output:

Quote:
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.4, not stripped
from which you can see that the file is dynamically linked. When the ldd command is run on a.out:

Code:
ldd a.out
it produces this output:

Quote:
linux-vdso.so.1 => (0x00007fff396ef000)
libc.so.6 => /lib64/libc.so.6 (0x00007fe086bd5000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe086f42000)
which shows what libraries and other components will be accessed when a.out is run.

I let gcc compile a file foo.c which contains this code:

Code:
# include <stdio.h>


int main(  int argc ,  char *argv[]  )
{
    printf(  "Hello World!\n"  ) ;
}
At first I do what you mentioned:

Code:
gcc -c foo.c
The nm command can display names/symbols from inside object modules such as foo.o, or executable files such as a.out.

If I run this command:

Code:
nm foo.o
I get just this output:

Code:
0000000000000000 T main
                 U puts
There's no mention of printf. If I change the line in foo.c containing printf to look like this:

Code:
    printf(  "%s %s\n" ,  "Hello" ,  "World!"  ) ;
and have gcc recreate foo.o, now the nm command shows this output:

Code:
0000000000000000 T main
                 U printf

that's because "optimization" built into the procedures handled by gcc, is smart enough to know that a printf without a format string can really just be handled by the puts function. I mention this as a complication to linking, because sometimes you don't necessarily need to link the function you think you do. A reference to a different function from a library, might have been substituted for you.

So then to put it altogether, to go back to what I mentioned earlier "gcc -v", if I grab the last command line from that output, on the system I'm using, this is the command to link foo.o:

Quote:
/usr/lib64/gcc/x86_64-suse-linux/4.5/collect2 --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64/crt1.o /usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64/crti.o /usr/lib64/gcc/x86_64-suse-linux/4.5/crtbegin.o -L/usr/lib64/gcc/x86_64-suse-linux/4.5 -L/usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../x86_64-suse-linux/lib -L/usr/lib64/gcc/x86_64-suse-linux/4.5/../../.. foo.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib64/gcc/x86_64-suse-linux/4.5/crtend.o /usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64/crtn.o
Simple, isn't it?!

Included in that simple command you will find things such as:

* a specification of the architecture of the machine I'm using x86, 64-bit, represented as "x86_64" ( not really that simple, but it's close enough for this purpose ).
* /lib64/ld-linux-x86-64.so.2 the jumping off point to the actual "dynamic" linker itself for an "x86_64" type machine.
* files with names ending in patterns like crt*.o are those added pieces I mentioned, some people think of the "crt" as representing the phrase "C Run Time".
* an indication of where to look for libraries, the arguments to the -L options.
* an indication of what libraries to find, the arguments to the -l ( lower case ) options.

From the lower case -l options, you can see that here the linking procedure would be looking for the libraries libc, libgcc, and libgcc_s.

From the upper case -L options, you can see that here the linking procedure would be looking for those libraries in these directories:

Quote:
/usr/lib64/gcc/x86_64-suse-linux/4.5
/usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64
/lib/../lib64
/usr/lib/../lib64
/usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../x86_64-suse-linux/lib
/usr/lib64/gcc/x86_64-suse-linux/4.5/../../..
which simplifies to this list:

Quote:
/usr/lib64/gcc/x86_64-suse-linux/4.5
/usr/lib64
/lib64
/usr/lib64
/usr/x86_64-suse-linux/lib
/usr/lib64
which is in turn just:

Quote:
/usr/lib64/gcc/x86_64-suse-linux/4.5
/usr/lib64
/lib64
/usr/x86_64-suse-linux/lib

AFAIK, all the backtracking in the paths, with the ".." stuff, is effectively from the procedure mechanically dealing with file system links. Even then, on the system I'm using, I believe the fourth path really just houses "scripts", prototypes of a sort, used by the linker, not libraries, per se.

These things are all either for the system I'm using, and/or for this program. Your system could be different. But if you really want to delve into all the details, you can try "gcc -v" or check the man page for gcc to see if the option is different for the system you are using.

Some of the commands I just touched on in passing, file, ldd, and nm, can be helpful for making the contents of object files and executable files more tangible.

Also, on some systems, the manual page for a function will tell you if there are options you need to pass to gcc to allow it to find the library which contains the function.

Personally, even though I understand it a little, I'm still going to let gcc link my files for me. Even if, I first have gcc separately compile a whole collection of object modules and then link them altogether in one last step to create one executable program.

If this all seems confusing, then I probably have at least succeeded in conveying the complexity of the thing.

Seriously, I do hope this helps.

Last edited by rigor; 09-15-2011 at 05:07 AM.
 
1 members found this post helpful.
Old 09-17-2011, 12:51 AM   #3
ludwig
Member
 
Registered: Jun 2002
Location: Orange County, CA
Distribution: Debian (squeeze), kernel 2.6.30-2-amd64
Posts: 32

Original Poster
Rep: Reputation: 15
Hello kakaka,

Thank you soooo much for the informative reply! Under normal circumstances I too plan to use gcc to do all my linking for me, but after hearing that the linker "ld" was actually being invoked by the gcc command, I was curious as to whether I could get ld to do the linking. It's far more complicated than I'd imagined, but that makes it all the more interesting. This is one of the things I just love about linux, it makes all the details available if you're willing to dig a little. You've just provided a tremendous sinkhole for me, and I'm looking forward to jumping in head first! Really, thanks again for taking the time to answer my question so completely!
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Socket Programming making use of "select()" and "writefds" johncsl82 Programming 10 11-13-2011 12:27 PM
"creating symbolic link" "operation not permitted" wheni Linux - Newbie 3 05-08-2011 01:36 AM
What is the difference between a "link" and a "symlink"? 4X1EG Linux - Newbie 5 04-02-2010 05:07 AM
glibc 2.9 "make check" fails on rt/tst-cputimer with "timer sig[12] invoked to soon" shachter Linux - Software 2 02-14-2009 01:24 PM
Can't exec "firefox 1.5", "prompts glibc detected" SPo2 Linux - General 1 06-04-2006 11:02 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software

All times are GMT -5. The time now is 04:14 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration