Linux 加载程序是否在程序启动时修改重新定位信息?
我一直认为解析绝对地址完全是链接器的工作。也就是说,链接器将所有对象文件合并到一个可执行文件中后,它将修改所有绝对地址以反映可执行文件中的新位置。但是在阅读了加载器不必将程序文本放在链接器指定的地址之后,我真的很困惑 以这段代码为例 Main.cLinux 加载程序是否在程序启动时修改重新定位信息?,linux,compilation,linker,loader,virtual-memory,Linux,Compilation,Linker,Loader,Virtual Memory,我一直认为解析绝对地址完全是链接器的工作。也就是说,链接器将所有对象文件合并到一个可执行文件中后,它将修改所有绝对地址以反映可执行文件中的新位置。但是在阅读了加载器不必将程序文本放在链接器指定的地址之后,我真的很困惑 以这段代码为例 Main.c void printMe(); int main(){ printMe(); return 0; } 富科 假设链接后,main的代码被放置在地址0x00000010,printMe的代码被放置在地址0x00000020。然后,
void printMe();
int main(){
printMe();
return 0;
}
富科
假设链接后,
main
的代码被放置在地址0x00000010,printMe
的代码被放置在地址0x00000020。然后,当程序启动时,加载程序确实会将main和printMe
加载到链接器指定的虚拟地址。但是,如果加载程序没有以这种方式加载程序,那么这不会破坏所有绝对地址引用。据我所知,这里不是这样
如果它是静态链接的,那么函数的地址由th链接器静态计算。因为相对地址是已知的,所以会发出一个相对函数调用,一切都会很好
如果它是动态链接的,那么ld.so将进入并加载库。符号为resolve by或by(这两篇文章不是我写的)
简言之
跳转*GOT[offset]
。在第一次调用时,这实际上是下一条指令的地址,它将调用动态加载程序来加载函数。在第二次调用时,这将是函数的地址。如您所见,与普通代码相比,这需要额外的内存和时间程序通常由链接器创建的几个模块组成。有可执行文件,通常有许多共享库。在某些系统上,一个可执行文件可以加载另一个可执行文件,并将其作为函数调用启动例程 如果所有这些编译的使用都有固定的地址,那么在加载时可能会有冲突。如果两个链接模块使用相同的地址,则应用程序无法加载 几十年来,可重定位代码一直是这个问题的解决方案。模块可以在任何地方加载。一些系统会将此操作进行到下一步,并随机将模块放入内存中以确保安全 有些情况下,代码不能完全重新定位 如果你有这样的东西:
static int b, *a = &b ;
初始化取决于模型在内存中的位置(以及“b”的位置)。链接器通常会生成此类构造的信息,以便加载程序可以修复它们
因此,这是不正确的:
我一直认为解析绝对地址完全是链接器的工作
如果加载程序不处理修复,绝对地址引用将中断。修复这一问题是重新定位数据存在的全部原因。那么这是否意味着链接所有静态库后,链接器生成的地址将被忽略?否,链接器创建相对地址。因此,从本质上讲,链接器地址仅用作偏移量,而绝对地址由加载程序确定?通常就是这样。有时,操作系统工作需要绝对地址,而链接器通常通过正确的汇编语言指令支持绝对地址。
static int b, *a = &b ;