在x86_64 linux中将程序重新定位在2GB以上时出现连接器错误? [英] Linker error on relocating a program above 2GB in x86_64 linux?

查看:785
本文介绍了在x86_64 linux中将程序重新定位在2GB以上时出现连接器错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用户程序,通常编译的入口点位于 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 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):重定位0具有无效的符号索引10
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位1具有无效的符号索引11
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位2具有无效的符号索引2
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位3有无效的符号索引2
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位4有无效的符号索引10
/ usr / bin / ld:/ usr /lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位5具有无效的符号索引12
/ usr / bin / ld:/ usr / lib / debug / usr / lib / x86_64-linux-gnu / crt1.o(.debug_info):重定位6具有无效的符号索引12
/ usr / bin / ld:/ usr / lib / debug / usr / lib / x86_64-linux-gnu /crt1.o(.debug_info):重定位7具有无效的符号索引12
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info ):重定位8具有无效的符号索引2
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位9具有无效符号索引2
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位10具有无效的符号索引11
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重新定位11有无效的符号索引12
/ usr / bin / ld:/ usr / bin / usr / lib中/调试/ usr / lib目录/ x86_64的-1 inux-gnu / crt1.o(.debug_info):重定位12具有无效的符号索引12
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o (.debug_info):重定位13具有无效的符号索引12
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位14具有无效的符号索引12
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位15具有无效的符号索引12
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位16有无效的符号索引12
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位17有无效的符号索引12
/ usr / bin / ld:/ usr / lib / debug / usr / lib / x86_64-linux-gnu / crt1.o(.debug_info):重定位18具有无效的符号索引12
/ usr / bin / ld:/ usr / lib / debug / usr / lib / x86_64 -linux-gnu / crt1.o(.debug_info):重定位19具有无效的符号索引12
/ usr / bin / ld:/ usr / lib / debug / usr / lib / x86_64-linux-gnu / crt1。 o(.debug_info):re位置20具有无效的符号索引20
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line):重定位0具有无效的符号索引2
/usr/lib/x86_64-linux-gnu/crt1.o:函数`_start':
(.text + 0x12):重定位被截断为适合:R_X86_64_32S针对符号`__libc_csu_fini'定义。 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)中的文本部分
/usr/lib/x86_64-linux-gnu/crt1.o:函数`_start':
(.text + 0x19):重定位被截断为适合:R_X86_64_32S针对/usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS).text中的.text节中定义的符号__libc_csu_init $ b /usr/lib/x86_64-linux-gnu/crt1.o:函数`_start':
(.text + 0x20):重定位被截断为适合:R_X86_64_32S针对在.text部分中定义的符号`main'在/tmp/ccFshK69.o
/ var / services / homes / adabral / elider / gc / a1 / lib / gcc / x86_64-unknown-linux- gnu / 4.8.2 / crtbegin.o:在函数`deregister_tm_clones ':
crtstuff.c :(。tex t + 0x8):重定位被截断为适合:R_X86_64_32S针对`.tm_clone_table'
/ var / services / homes / adabral / elider / gc / a1 / lib / gcc / x86_64-unknown-linux- gnu / 4.8.2 /crtbegin.o:函数`register_tm_clones':
crtstuff.c :(。text + 0x38):重定位被截断为适合:R_X86_64_32S针对`.tm_clone_table'
collect2:错误:ld返回1退出状态

:之所以这样做,是因为我可以在通过几个SO问题和论坛之后做出决定因为某些部分仍然映射到低 2GB 地址空间。

这是 readelf -a 的输出,对于使用文本段低于<$ c $编译的二进制文件c> 2GB (at 0x79990000 )。

 偏移量为0x190310的动态部分包含24个条目:
标签类型名称/值
0x0000000000000001(需要)共享库:[libc.so.6]
0x000000000000000c(INIT)0x4003f0 $ b $ (FINI)0x79990204
0x0000000000000019(INIT_ARRAY)0x79b902f8
0x000000000000001b(INIT_ARRAYSZ)8(字节)
0x000000000000001a(FINI_ARRAY)0x79b90300
0x000000000000001c(FINI_ARRAYSZ)8(字节)
0x0000000000000004(HASH)0x400278
0x0000000000000005(STRTAB)0x400318
0x0000000000000006(SYMTAB)0x4002a0
0x000000000000000a(STRSZ)72(字节)
0x000000000000000b(SYMENT)24(字节)
0x00000000 00000015(DEBUG)0x0
0x0000000000000003(PLTGOT)0x79b904e8
0x0000000000000002(PLTRELSZ)72(字节)
0x0000000000000014(PLTREL)RELA
0x0000000000000017(JMPREL)0x4003a8
0x0000000000000007( RELA)0x400390
0x0000000000000008(RELASZ)24(字节)
0x0000000000000009(RELAENT)24(字节)
0x000000006ffffffe(VERNEED)0x400370
0x000000006fffffff(VERNEEDNUM)1
0x000000006ffffff0 (VERSYM)0x400360
0x0000000000000000(NULL)0x0

您可以看到 INIT ,而其他一些部分仍然以低 2GB 地址空间开始。因此,由于重定位类型为 R_X86_64_32



    $ b,因此动态链接程序无法在运行时抵消重定位地址$ b
  • 所以我试着用 gcc -mcmodel = 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:函数`_start': 
(.text + 0x20):重定位被截断为适合:R_X86_64_32S针对/tmp/ccFshK69.o中的.text节中定义的符号`main'定义

发生的事情是 crt1.o 重新定位了 main main 是在共享库中定义的,而不是在可执行文件中定义的,作为可执行文件中的PLT条目,并且此PLT条目的地址将是 main 的正式地址,重定位将被解决。)



为了解决这个问题,你需要一个 crt1.o 来处理完整的64位地址。一种方法是使用 Scrt1.o ,它通常只用于PIE可执行文件,而不是 crt1.o 。你可以用 -nostartfiles 来实现,并在链接命令行中手动指定所有的启动文件。可能值得向glibc提交一个错误报告,要求将x86_64 crt1.o 转换为大型模式,以便它可以与未在32位版本中链接的主要程序一起使用。请注意,您可能还需要 -mcmodel = large (或者 -fPIE 可以工作),以便让你的代码在高地址上链接并正常工作。这可能会使其变得更大更慢。你可能想重新考虑你为什么这样做,以及你是否真的需要。


I have a user program which normally compiles to have an entry point at 0x400460 which I have to relocate to have an entry point starting at within 2GB of the shared libraries loaded in Linux. e.g 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)

I am using gcc command line argument -Wl,-Ttext=0x80000000 to specify the start address for the .text segemnt.

The issue is that when I am giving an address above 2GB in this argument I am getting a linker error which is:

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

: The reason for this as far as I can make out after going through several SO questions and forums can be that some of the sections are still mapped to low 2GB address space.

This is the output of the readelf -a for a binary compiled with text segment just below 2GB (at 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

You can see that the INIT and some other sections still starts at the low 2GB address space. So the dynamic linker can not offset the relocation address at run time since the relocation type is R_X86_64_32.

  • So I tried compiling my code with gcc -mcmodel=large flag but I am still getting the same linker error. Using the large model should have rectified this error but it is not.

  • I am stuck at this point, any help is highly appreciated.

(I am working on x86_64 ubuntu machine. gcc versio 4.8.2) Thanks

解决方案

You should first understand that the ABI for x86_64 has several different "models": small, kernel, medium, and large. These are described under the GCC -mcmodel option here: http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86-64-Options.html

What you're experiencing is that crt1.o, the startup code that gets linked into every program that's responsible for taking the initial ELF register/stack state and passing them into the libc startup code which eventually calls main, seems to be using the small model. You can see here:

/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

What's happening is that crt1.o has a relocation for the address of main that only allows for a 32-bit address to be filled in. (Note: Even if main were defined in a shared library rather than the executable, there would be a PLT entry in the executable, and the address of this PLT entry would be the official address of main to which the relocation would be resolved.)

To solve this problem, you would need a crt1.o that can handle full 64-bit addresses. One way to get this might be by using Scrt1.o, which is normally only used for PIE executables, instead of crt1.o. You could probably achieve this with -nostartfiles and manually specifying all the start files on the link command line. It might be worth filing a bug report against glibc requesting that the x86_64 crt1.o be converted to "large model" so that it works with main programs not linked in the 32-bit range.

Note that you'll probably also need -mcmodel=large (or perhaps -fPIE would work) for all of your own code to make it link and work correctly at high addresses. This could make it considerably larger and slower. You might want to rethink why you're doing this and whether you really need to.

这篇关于在x86_64 linux中将程序重新定位在2GB以上时出现连接器错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆