我有一个用户程序,它通常编译为在0x400460
有一个入口点,我必须重新定位,以便在Linux中加载的共享库的2GB
内有一个入口点。例如linux-vdso.so.1 => (0x00007fff109cd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcd195e6000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcd199af000)
我使用gcc
命令行参数-Wl,-Ttext=0x80000000
来指定.text
segemnt的起始地址。
问题在于,当我在此参数中给出2GB
以上的地址时,我收到链接器错误:
gcc test.c -ggdb -Wl,-Ttext=0x80000000 -o test1
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 10
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 11
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 10
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 11
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 20 has invalid symbol index 20
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2
/usr/lib/x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x12): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_fini' defined in .text section in /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
/usr/lib/x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x19): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_init' defined in .text section in /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
/usr/lib/x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): relocation truncated to fit: R_X86_64_32S against symbol `main' defined in .text section in /tmp/ccFshK69.o
/var/services/homes/adabral/elider/gc/a1/lib/gcc/x86_64-unknown-linux- gnu/4.8.2/crtbegin.o: In function `deregister_tm_clones':
crtstuff.c:(.text+0x8): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
/var/services/homes/adabral/elider/gc/a1/lib/gcc/x86_64-unknown-linux- gnu/4.8.2/crtbegin.o: In function `register_tm_clones':
crtstuff.c:(.text+0x38): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
collect2: error: ld returned 1 exit status
:在经过几个SO问题和论坛之后,我可以得出的原因可能是某些部分仍然映射到低2GB
地址空间。
这是使用readelf -a
下方2GB
下方的文字段编译的二进制文件0x79990000
的输出。
Dynamic section at offset 0x190310 contains 24 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x4003f0
0x000000000000000d (FINI) 0x79990204
0x0000000000000019 (INIT_ARRAY) 0x79b902f8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x79b90300
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x0000000000000004 (HASH) 0x400278
0x0000000000000005 (STRTAB) 0x400318
0x0000000000000006 (SYMTAB) 0x4002a0
0x000000000000000a (STRSZ) 72 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x79b904e8
0x0000000000000002 (PLTRELSZ) 72 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x4003a8
0x0000000000000007 (RELA) 0x400390
0x0000000000000008 (RELASZ) 24 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x400370
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x400360
0x0000000000000000 (NULL) 0x0
您可以看到INIT
和其他一些部分仍然位于低2GB
地址空间。因此,动态链接器无法在运行时偏移重定位地址,因为重定位类型为R_X86_64_32
。
所以我尝试用gcc -mcmodel=large
标志编译我的代码,但我仍然得到相同的链接器错误。使用large
模型应该已经纠正了这个错误,但事实并非如此。
我被困在这一点上,非常感谢任何帮助。
(我正在使用x86_64 ubuntu机器.gcc versio 4.8.2) 感谢
答案 0 :(得分:6)
您应该首先了解x86_64的ABI有几个不同的“模型”:小型,内核,中型和大型。这些在GCC -mcmodel
选项下进行了描述:http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86-64-Options.html
您遇到的是crt1.o
,启动代码链接到负责获取初始ELF寄存器/堆栈状态并将其传递到最终调用{{1}的libc启动代码的每个程序中似乎是在使用小模型。你可以在这里看到:
main
正在发生的事情是/usr/lib/x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): relocation truncated to fit: R_X86_64_32S against symbol `main' defined in .text section in /tmp/ccFshK69.o
对crt1.o
的地址进行了重定位,只允许填写32位地址。(注意:即使定义了main
在共享库而不是可执行文件中,可执行文件中会有一个PLT条目,该PLT条目的地址将是要解析重定位的main
的官方地址。)
要解决此问题,您需要一个可以处理完整64位地址的main
。获得此功能的一种方法可能是使用crt1.o
,通常仅用于PIE可执行文件,而不是Scrt1.o
。您可以使用crt1.o
实现此目的,并在链接命令行上手动指定所有启动文件。可能值得提交针对glibc的错误报告,请求将x86_64 -nostartfiles
转换为“大型模型”,以便它可以与未在32位范围内链接的主程序一起使用。
请注意,对于您自己的所有代码,您可能还需要crt1.o
(或者-mcmodel=large
可能会工作),以使其在高地址处正常链接并正常工作。这可能会使它变得更大更慢。您可能想重新考虑为什么要这样做以及是否真的需要。