c - 在 x86_64 linux 中重定位超过 2GB 的程序时出现链接器错误?

标签 c linux gcc linker x86-64

我有一个用户程序,通常编译后在 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.omain 的地址进行了重定位,只允许填充 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/

相关文章:

c - BST中序遍历中的Seg Fault

gcc - 预取示例?

c - 为什么 `accept(2)` 需要 `sockaddr` 长度作为单独的指针?

linux - 如何使用 cURL 将文件内容作为 POST 参数发送?

c - 套接字在函数调用之间是否持续存在?

linux - 如何在 linux-shell 中使用 `amp;` 和 `gt;` 命令?

java - Apache tomcat - 如何在远程机器上打开浏览器

c - __STDC_IEC_559__ 与现代 C 编译器的状态

c++ - 使用 glDrawPixels 时遇到问题

c - 声明另一个函数时使用函数名和昵称(由 typedef 制成)有什么区别?