C语言 Linux何时/如何将共享库加载到地址空间?

dba5bblo  于 2022-12-17  发布在  Linux
关注(0)|答案(5)|浏览(176)

什么时候在程序中指定共享对象的地址?在链接时?加载时?如果我想在程序的libc中找到system命令的内存地址,我可以在gdb中很容易地找到它,但是如果我不想把程序带到调试器中呢?
这个地址会随着运行而改变吗?是否有其他静态分析工具允许查看库或函数在运行时加载到程序内存空间的位置?
我希望在程序之外获得此信息(即使用objdump等实用程序收集信息)

tmb3ates

tmb3ates1#

库由ld.so(动态链接器或运行时链接器,在Linux中称为rtld、ld-linux.so.2ld-linux.so.*)加载; glibc的一部分)。它被声明为“解释器”(INTERP; .interp部分)。因此,当您启动程序时,Linux将启动一个ld.so(加载到内存中并跳转到其入口点),然后ld.so将您的程序加载到内存中,准备它,然后运行它。

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

ld.so执行所有需要的ELF文件的实际openmmap,包括程序的ELF文件和所有需要的库的ELF文件。此外,它填充GOT和PLT表,并执行重定位解析(它将函数的地址从库写入调用点,在许多情况下使用间接调用)。
使用ldd实用程序可以获得某个库的典型加载地址。它实际上是一个bash脚本,它设置了一个调试环境变量ld.so(在glibc的rtld中实际上是LD_TRACE_LOADED_OBJECTS=1)并启动一个程序。您甚至可以自己完成,而不需要脚本,例如使用bash轻松更改单次运行的环境变量:

LD_TRACE_LOADED_OBJECTS=1 /bin/echo

ld.so将看到这个变量,并将解析所有需要的库和打印它们的加载地址。(不确定程序或库的静态构造函数)。如果ASLR feature被禁用,加载地址大多数时候都是相同的。现代Linux经常启用ASLR,所以要禁用它,使用echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
你可以用binutils的nm实用程序在libc.so中找到system函数的偏移量。我认为,你应该使用nm -D /lib/libc.soobjdump -T /lib/libc.so和grep输出。

qlvxas9a

qlvxas9a2#

“直奔源头问马......”
Drepper - How To Write Shared Libraries
Linux库编写者必读的文档。详细解释了加载的机制。

wgmfuz8q

wgmfuz8q3#

如果你只需要函数的地址而不需要硬编码函数名,你可以dlopen()主程序:

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

如果只需要在编译时知道名称的函数的地址,只需使用void *addr = &system;

pod7payv

pod7payv4#

libc.so上使用的nm命令将显示system符号在libc.so中的位置。但是,如果启用了ASLR,则加载地址libc.so,因此每次运行程序时,system的最终地址将随机变化。即使没有ASLR,您需要确定libc.so加载的地址,并将system的地址偏移该值。

相关问题