我有一个嵌入式应用程序,它有一个引导加载程序,它将决定直接从内部闪存运行两个应用程序中的一个。我正在尝试使这些应用程序位置独立,以便它们都可以针对相同的基地址进行编译。没有操作系统,所以没有动态链接器可用。到目前为止,我已经尝试使用 -fpie 选项(使用 gcc)进行构建,但没有取得太大的成功。函数调用似乎是正确的,但全局数据没有正确的地址。本地定义的全局数据的地址偏移量似乎是应用程序与其原始基地址的偏移量。在其他文件中声明的全局数据具有完全错误的地址(如果我使用 -fpic 构建,那么本地声明的全局数据和其他文件中的全局数据都是完全错误的)。
2 回答
我终于让它工作了。看起来我需要执行以下操作:所有代码都需要遵守 -fpic(之前我正在尝试 -fpie)
此外,我的链接器脚本需要修改。我强迫 GOT 进入 sram 部分,它位于 flash 中的动态部分之后。如果 GOT 部分位于闪存中的动态部分之前,则看起来一切正常。不知道为什么这很重要,但它似乎解决了所有问题——在此之前,就好像代码没有正确定位 GOT,因为 GOT 中存储了正确的值,但我所有变量的地址都不正确。
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有搬迁:
- R_386_GOTPC
- R_386_GOT32
- R_386_GOTOFF
- R_386_RELATIVE
链接器应该在代码访问全局数据之前解决所有这些问题。
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
馅饼:
$ 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