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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5130654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:02:31  来源:igfitidea点击:

When / How does Linux load shared libraries into address space?

clinuxcompiler-constructionlinkershared-libraries

提问by Ryan

My question is the following:

我的问题如下:

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

程序中什么时候指定共享对象的地址?在链接期间?正在加载?如果我想在我的程序system内部找到命令的内存地址,libc我可以很容易地在gdb.

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?

这个地址会随着运行而改变吗?是否有任何其他静态分析工具可以查看运行时库或函数将在哪里加载到该程序的内存空间中?

EDIT: I want this information outside of the program (ie. using utilities like objdumpto gather information)

编辑:我想要程序之外的这些信息(即使用实用程序objdump来收集信息)

采纳答案by osgx

Libraries are loaded by ld.so(dynamic linker or run-time linker aka rtld, ld-linux.so.2or ld-linux.so.*in case of Linux; part of glibc). It is declared as "interpreter" (INTERP; .interpsection) 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.sowill load your program into memory, prepare it and then run it. You can also start dynamic program with

库由ld.so(动态链接器或运行时链接器又名 rtld,ld-linux.so.2或者ld-linux.so.*在 Linux 的情况下;glibc 的一部分)加载。它被声明为.interp所有动态链接的 ELF 二进制文件的“解释器”(INTERP;部分)。所以,当你启动程序时,Linux 会启动一个ld.so(加载到内存并跳转到它的入口点),然后ld.so将你的程序加载到内存中,准备它然后运行它。您还可以启动动态程序

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

ld.sodoes an actual openand mmapof 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).

ld.so执行实际的openmmap所有需要的 ELF 文件,包括程序的 ELF 文件和所有需要的库的 ELF 文件。此外,它还填充 GOT 和 PLT 表并进行重定位解析(它将函数地址从库写入调用站点,在许多情况下使用间接调用)。

The typical load address of some library you can get with lddutility. It is actually a bash script, which sets a debug environment variable of ld.so (actually LD_TRACE_LOADED_OBJECTS=1in 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:

您可以使用ldd实用程序获得的某些库的典型加载地址。它实际上是一个bash脚本,它设置了一个ld.so的调试环境变量(实际上LD_TRACE_LOADED_OBJECTS=1是glibc的rtld)并启动一个程序。您甚至可以在不需要脚本的情况下自己完成,例如使用 bash 轻松更改单次运行的环境变量:

 LD_TRACE_LOADED_OBJECTS=1 /bin/echo

The ld.sowill see this variable and will resolve all needed libraries and print load addresses of them. But with this variable set, ld.sowill not actually start a program (not sure about static constructors of program or libraries). If the ASLR featureis 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.

ld.so会看到这个变量,将解决所有需要的库,并打印出来的加载地址。但是设置这个变量后,ld.so实际上不会启动程序(不确定程序或库的静态构造函数)。如果禁用ASLR 功能,则加载地址大多数时候将是相同的。现代 Linux 通常启用 ASLR,因此要禁用它,请使用echo 0 | sudo tee /proc/sys/kernel/randomize_va_space.

You can find offset of systemfunction inside the libc.sowith nmutility from binutils. I think, you should use nm -D /lib/libc.soor objdump -T /lib/libc.soand grep output.

您可以system在binutils的libc.sowithnm实用程序中找到函数的偏移量。我认为,您应该使用nm -D /lib/libc.soorobjdump -T /lib/libc.so和 grep 输出。

回答by ThiefMaster

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

如果您只想要函数的地址而不是对名称进行硬编码,则可以dlopen()在主程序中:

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;

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

回答by R.. GitHub STOP HELPING ICE

The nmcommand, used on libc.so, will show you the location of the systemsymbol in libc.so. However, if ASLR is enabled, the address libc.sois loaded at, and thus the final address of systemwill vary randomly each time your program is run. Even without ASLR, you'll need to determine the address libc.sogets loaded at and offset the address of systemby that amount.

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

回答by mozillanerd

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

我建议您的环境具有 LD_LIBRARY_PATH 路径。这定义了共享库的位置。您可能还需要查看 /etc/ld.so.conf 查看此帖子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

回答by Dipstick

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

“直接去源头问问马……”

Drepper - How To Write Shared Libraries

Drepper - 如何编写共享库

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

Linux 库编写者的必读文档。详细解释了加载机制。