ELF可执行文件具有固定的加载地址(32位x86 Linux二进制文件为0x804800,64位x86_64二进制文件为0x40000)。
我阅读了有关这些特定地址的历史原因的SO答案(例如,this one)。我仍然不明白为什么使用固定的加载地址而不是随机的地址(给定一些范围随机化)?
答案 0 :(得分:4)
为什么要使用固定加载地址而不是随机加载地址
PIE
构建-fPIE
二进制文件(实际上是包含启动代码的共享库的特殊情况),并链接-pie
标记。< / LI>
-fPIE
构建会导致运行时开销,在某些情况下会导致10%的性能下降,如果您拥有大型集群或者需要最后一点性能,则可能无法容忍。答案 1 :(得分:3)
不确定我是否理解你的问题是正确的,但我说我做了,那就是对#34;遗产&#34; /历史问题,ELF是UNIX派生操作系统使用的文件格式,包括POSIX(IOS)和类Unix(Linux)。
并且elf格式只是声明必须有一些解析的和绝对的虚拟地址,代码被加载到并开始运行... 简单地说就是文件格式是怎样的,并且在历史原因不能改变的情况下...你不可能只是&#34;抛出&#34;任何内存地址中的可执行文件,并使其成功运行,回到90年代,当引入ELF格式时出现问题,例如调用带有虚拟表的函数我们已经提出并且决定elf格式会有其中的绝对地址。
还要考虑一下,看看精灵格式 - https://en.wikipedia.org/wiki/Executable_and_Linkable_Format 你将如何设计一个能够处理可执行文件的操作系统可执行加载程序将其加载到任何所需的虚拟地址,并使代码成功运行而无需实际更改二进制文件...如果你想做类似的事情您需要大幅更改输出编译器生成的内容或格式本身,这也是不可能的
随着时间的推移,位置无关执行(PIE / PIC)的要求已经提出并共享了我们引入的对象以便允许和ASLR (地址空间布局随机化) - 这意味着代码可以抛出任何内存地址并且仍然能够执行,这可以通过确保代码本身内的所有调用都与执行指令的当前地址相关来实现,并且当加载共享对象时,OS加载器将不得不改变二进制内的一些数据,因为改变的数据不是可执行指令(RE)而是实际数据(RW,例如.data段),这也是由调用某些&#34;跳转表中的函数&#34; (这将在加载时更改)例如PLT / GOT ....这些共享对象允许加载代码的地址的绝对随机化,如果你想再执行一些&#34; secure&#34;代码您必须将其编译为共享对象并动态链接它并加载时间或运行时间..
(希望我已经清除了一些东西:))