我有一个用户程序,通常编译后在 0x400460
处有一个入口点我必须重新定位以拥有一个从 2GB
开始的入口点在 Linux 中加载的共享库。例如
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
的起始地址段。
问题是,当我在 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 版本 4.8.2
最佳答案
您应该首先了解 x86_64 的 ABI 有几种不同的“模型”:小型、内核、中型和大型。这些在此处的 GCC -mcmodel
选项下进行了描述:http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86-64-Options.html
您遇到的是 crt1.o
,启动代码链接到每个程序,负责获取初始 ELF 寄存器/堆栈状态并将它们传递到 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
对 main
的地址进行了重定位,只允许填充 32 位地址。(注意:即使如果 main
定义在共享库而不是可执行文件中,那么可执行文件中就会有一个 PLT 入口,这个 PLT 入口的地址就是 main
的官方地址> 将解决搬迁问题。)
要解决这个问题,您需要一个可以处理完整 64 位地址的 crt1.o
。一种方法是使用 Scrt1.o
,它通常只用于 PIE 可执行文件,而不是 crt1.o
。您可以使用 -nostartfiles
并在链接命令行上手动指定所有启动文件来实现此目的。可能值得针对 glibc 提交错误报告,要求将 x86_64 crt1.o
转换为“大型模型”,以便它可以与未在 32 位范围内链接的主程序一起工作。
请注意,对于您自己的所有代码,您可能还需要 -mcmodel=large
(或者可能 -fPIE
会起作用)以使其链接并正常工作在高地址。这可能会使它变得更大和更慢。您可能需要重新考虑为什么要这样做以及是否真的需要这样做。
关于c - 在 x86_64 linux 中重定位超过 2GB 的程序时出现链接器错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21143771/