Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 加载程序是否在程序启动时修改重新定位信息?_Linux_Compilation_Linker_Loader_Virtual Memory - Fatal编程技术网

Linux 加载程序是否在程序启动时修改重新定位信息?

Linux 加载程序是否在程序启动时修改重新定位信息?,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。然后,

我一直认为解析绝对地址完全是链接器的工作。也就是说,链接器将所有对象文件合并到一个可执行文件中后,它将修改所有绝对地址以反映可执行文件中的新位置。但是在阅读了加载器不必将程序文本放在链接器指定的地址之后,我真的很困惑

以这段代码为例

Main.c

 void printMe();
int main(){
    printMe();

    return 0;

}
富科


假设链接后,
main
的代码被放置在地址0x00000010,
printMe
的代码被放置在地址0x00000020。然后,当程序启动时,加载程序确实会将main和
printMe
加载到链接器指定的虚拟地址。但是,如果加载程序没有以这种方式加载程序,那么这不会破坏所有绝对地址引用。

据我所知,这里不是这样

如果它是静态链接的,那么函数的地址由th链接器静态计算。因为相对地址是已知的,所以会发出一个相对函数调用,一切都会很好

如果它是动态链接的,那么ld.so将进入并加载库。符号为resolve by或by(这两篇文章不是我写的)

简言之

  • 加载时重定位是通过重写代码来为它们提供正确的地址来完成的,这将禁用wirte保护并在不同进程之间共享

  • PIC是通过添加两个称为GOT和PLT的部分来完成的,这两个部分都位于链接时可以知道的特定地址。在动态库中调用函数将首先调用…@plt函数(E.x。printf@plt)然后它将
    跳转*GOT[offset]
    。在第一次调用时,这实际上是下一条指令的地址,它将调用动态加载程序来加载函数。在第二次调用时,这将是函数的地址。如您所见,与普通代码相比,这需要额外的内存和时间


  • 程序通常由链接器创建的几个模块组成。有可执行文件,通常有许多共享库。在某些系统上,一个可执行文件可以加载另一个可执行文件,并将其作为函数调用启动例程

    如果所有这些编译的使用都有固定的地址,那么在加载时可能会有冲突。如果两个链接模块使用相同的地址,则应用程序无法加载

    几十年来,可重定位代码一直是这个问题的解决方案。模块可以在任何地方加载。一些系统会将此操作进行到下一步,并随机将模块放入内存中以确保安全

    有些情况下,代码不能完全重新定位

    如果你有这样的东西:

    static int b, *a = &b ;
    
    初始化取决于模型在内存中的位置(以及“b”的位置)。链接器通常会生成此类构造的信息,以便加载程序可以修复它们

    因此,这是不正确的:

    我一直认为解析绝对地址完全是链接器的工作


    如果加载程序不处理修复,绝对地址引用将中断。修复这一问题是重新定位数据存在的全部原因。那么这是否意味着链接所有静态库后,链接器生成的地址将被忽略?否,链接器创建相对地址。因此,从本质上讲,链接器地址仅用作偏移量,而绝对地址由加载程序确定?通常就是这样。有时,操作系统工作需要绝对地址,而链接器通常通过正确的汇编语言指令支持绝对地址。
    static int b, *a = &b ;