51

When is the address of shared objects specified in programs? During linking? Loading? If I wanted to find the memory address of the system command inside of libc inside of my program I could find it easily in gdb, but what if I don't want to bring the program into a debugger?

Could this address change from run to run? Are there any other static analysis tool that will allow be to view where libraries or functions will be loaded into this program's memory space when run?

I want this information outside of the program (ie. using utilities like objdump to gather information)

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Ryan
  • 3,579
  • 9
  • 47
  • 59
  • and then there's [`prelink`](http://people.redhat.com/jakub/prelink.pdf), which changes the order considerably. – Ben Voigt Feb 27 '11 at 01:16

5 Answers5

83

Libraries are loaded by ld.so (dynamic linker or run-time linker aka rtld, ld-linux.so.2 or ld-linux.so.* in case of Linux; part of glibc). It is declared as "interpreter" (INTERP; .interp section) of all dynamic linked ELF binaries. So, when you start program, Linux will start an ld.so (load into memory and jump to its entry point), then ld.so will load your program into memory, prepare it and then run it. You can also start dynamic program with

 /lib/ld-linux.so.2 ./your_program your_prog_params

ld.so does an actual open and mmap of all needed ELF files, both ELF file of your program and ELF files of all neeeded libraries. Also, it fills GOT and PLT tables and does relocations resolving (it writes addresses of functions from libraries to call sites, in many cases with indirect calls).

The typical load address of some library you can get with ldd utility. It is actually a bash script, which sets a debug environment variable of ld.so (actually LD_TRACE_LOADED_OBJECTS=1 in case of glibc's rtld) and starts a program. You even can also do it yourself without needs of the script, e.g. with using bash easy changing of environment variables for single run:

 LD_TRACE_LOADED_OBJECTS=1 /bin/echo

The ld.so will see this variable and will resolve all needed libraries and print load addresses of them. But with this variable set, ld.so will not actually start a program (not sure about static constructors of program or libraries). If the ASLR feature is disabled, load address will be the same most times. Modern Linuxes often has ASLR enabled, so to disable it, use echo 0 | sudo tee /proc/sys/kernel/randomize_va_space.

You can find offset of system function inside the libc.so with nm utility from binutils. I think, you should use nm -D /lib/libc.so or objdump -T /lib/libc.so and grep output.

Community
  • 1
  • 1
osgx
  • 90,338
  • 53
  • 357
  • 513
  • 2
    wonderful information, thank you. Do you know of any good articles that explain how this process works (generating GOT / PLT tables), or would googling yield sufficient results? – Ryan Feb 27 '11 at 01:07
  • If you want to call a `system` with absolute address, you can do it without using a GOT and PLT tables. In my point, the best googling for `ld.so` is codesearch: http://google.com/codesearch?hl=en&lr=&q=rtld_start+package%3Aglibc&sbtn=Search – osgx Feb 27 '11 at 01:14
  • Yes, I know you can do it without using GOT and PLT, it was mere curiosity on my part! :) – Ryan Feb 27 '11 at 01:17
  • may be,... the book on linkers will help? http://www.iecc.com/linker/linker10.html Also there is a blog of author of `gold` linker and elf part of binutils ld linker www.airs.com/blog/archives/41 – osgx Feb 27 '11 at 01:21
  • pdf of some blogposts from airs.com www.cs.pitt.edu/~abraham/CS0449/slides/Linking.pdf – osgx Feb 27 '11 at 01:23
  • 1
    This was very informative! I didn't know that much about ld.so and ldd! – Matt Joiner Feb 28 '11 at 02:20
  • 4
    This answer is incorrect in that `ld.so` does *not* load the main program, the kernel does. The kernel also doesn't look at any *sections* (which could be stripped completely), it finds the interpreter in `PT_INTERP` *segment*. – Employed Russian May 28 '17 at 15:48
  • @EmployedRussian, Can you post more correct answer? I'm not expert in this and you is. – osgx May 28 '17 at 15:55
13

"Go right to the source and ask the horse..."

Drepper - How To Write Shared Libraries

Must-read documentation for Linux library writers. Explains the mechanics of loading in some detail.

Dipstick
  • 9,854
  • 2
  • 30
  • 30
10

If you just want the address of a function while not hardcoding the name, you could dlopen() the main program:

void *self = dlopen(NULL, RTLD_NOW);
dlsym(self, "system"); // returns the pointer to the system() function

If you just want the address of a function of which you know the name at compile-time, simply use void *addr = &system;

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • please see edit in OP, but definitely leave this answer as it is helpful for another variation of the potentially vague title. (how you answered it) – Ryan Feb 27 '11 at 00:54
  • 1
    It's possible that neither will do what OP wants, since `system` is probably resolved to a PLT entry in the main program image that performs the actual jump into the shared library. – R.. GitHub STOP HELPING ICE Feb 27 '11 at 00:54
10

The nm command, used on libc.so, will show you the location of the system symbol in libc.so. However, if ASLR is enabled, the address libc.so is loaded at, and thus the final address of system will vary randomly each time your program is run. Even without ASLR, you'll need to determine the address libc.so gets loaded at and offset the address of system by that amount.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • This is pretty much exactly what I wanted - I'm assuming the best way to determine the offset of system within libc.so is to use nm again with the debugging symbols installed? Or is there an easier / more robust manner to do this. – Ryan Feb 27 '11 at 01:01
  • @Ryan, nm needs no debug symbols, it can read a symbol table directly (which is used by `ld.so`). – osgx Feb 27 '11 at 01:05
  • @osgx so then would my original question be correct, subtracting the debugging symbols? – Ryan Feb 27 '11 at 01:08
0

Id recommend that your environment have the LD_LIBRARY_PATH path. This defines where the shared libraries are to be found. You may also have to look into /etc/ld.so.conf Look at this posting http://www.google.com/url?sa=t&source=web&cd=3&ved=0CCQQFjAC&url=http%3A%2F%2Fubuntuforums.org%2Fshowthread.php%3Ft%3D324660&ei=KqJpTey7JofEsAPE9_imBA&usg=AFQjCNEIbGGrTHp4fufRuj4Yfc58RTHcag&sig2=_9tdlyadMbPc-FcOdCko-w

mozillanerd
  • 568
  • 4
  • 9