我有一个嵌入式应用程序,它将有一个引导加载程序,它将决定直接从内部闪存运行两个应用程序中的一个。我试图使这些应用程序位置独立,以便它们都可以编译为相同的基地址。没有操作系统,因此没有可用的动态链接器。到目前为止,我尝试使用-fpie选项(使用gcc)构建并没有太大的成功。函数调用似乎是正确的,但全局数据没有正确的地址。本地定义的全局数据似乎使其地址偏移了应用程序偏离其原始基址的数量。在其他文件中声明的全局数据具有完全错误的地址(如果我使用-fpic构建,则本地声明的全局数据和其他文件中的全局数据都是完全错误的)。我怀疑当我的应用程序启动时我需要对GOT部分进行一些操作,但我不确定。
答案 0 :(得分:8)
我终于开始工作了。看起来我需要执行以下操作: 所有代码都需要符合-fpic(之前我在尝试-fpie)
此外,我的链接器脚本需要修改。我强迫GOT进入sram部分,它位于flash中的动态部分之后。如果GOT部分位于闪存中动态部分之前,看起来一切正常。不确定为什么这很重要,但它似乎解决了所有问题 - 在此之前,好像代码没有正确定位GOT,因为GOT中存储了正确的值但是我所有变量的地址都不正确。
答案 1 :(得分:5)
PIE(和PIC)代码在加载某个地址(与默认值不同)之后和运行之前需要重定位进程。我建议你查阅ld.so
的代码。此外,您应该检查二进制文件中的重定位表(例如,使用readelf -r
)。
这是关于PIE的一个很好的演示文稿(它与OpenBSD有关,但过程相同)。 http://www.openbsd.org/papers/nycbsdcon08-pie/或http://www.dcbsdcon.org/speakers/slides/miller_dcbsdcon2009.pdf
我想你不仅要改变GOT,还要找到所有重定位并进行改编。
基本上,ld.so对PIE二进制文件的处理与处理带有PIC的动态库几乎相同,不是重定位库,而是重定位可执行映像本身。
您看到的“错误地址”是一个地方,其中实际值将通过重新定位解决来写入。对于i386 http://books.google.com/books?id=Id9cYsIdjIwC&pg=PA174,有重定位:
链接器应该在代码可以访问全局数据之前解决所有这些问题。
Readelf -r示例:
动态链接一个
$ readelf -r fdyn
Relocation section '.rel.dyn' at offset 0x27c contains 1 entries:
Offset Info Type Sym.Value Sym. Name
08049ff0 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
Relocation section '.rel.plt' at offset 0x284 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0804a000 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
0804a004 00000207 R_386_JUMP_SLOT 00000000 __libc_start_main
PIE:
$ readelf -r fPIE
Relocation section '.rel.dyn' at offset 0x388 contains 6 entries:
Offset Info Type Sym.Value Sym. Name
00001fe8 00000008 R_386_RELATIVE
00001ff0 00000008 R_386_RELATIVE
00002010 00000008 R_386_RELATIVE
00001fe0 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
00001fe4 00000206 R_386_GLOB_DAT 00000000 _Jv_RegisterClasses
00001fec 00000406 R_386_GLOB_DAT 00000000 __cxa_finalize
Relocation section '.rel.plt' at offset 0x3b8 contains 3 entries:
Offset Info Type Sym.Value Sym. Name
00002000 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
00002004 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main
00002008 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize