【问题标题】:relocation R_X86_64_32 against `.data' can not be used when making a shared object;重定位 R_X86_64_32 对 `.data' 在制作共享对象时不能使用;
【发布时间】:2018-09-01 05:38:22
【问题描述】:

我写了下面的汇编代码,它可以通过as和ld直接构建。

as cpuid.s -o cpuid.o
ld cpuid.o -o cpuid

但是当我使用 gcc 来完成整个过程时。我遇到了以下错误。

$ gcc cpuid.s -o cpuid
/tmp/cctNMsIU.o: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o:(.text+0x0): first defined here
/usr/bin/ld: /tmp/cctNMsIU.o: relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
/usr/bin/ld: final link failed: Invalid operation
collect2: error: ld returned 1 exit status

然后我将_start修改为main,并将-fPIC添加到gcc参数中。但它不能解决我的 ld 错误。错误消息更改为以下内容。

$ gcc cpuid.s -o cpuid
/usr/bin/ld: /tmp/ccYCG80T.o: relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

由于我没有创建共享对象,因此我不明白其含义。我只想制作一个可执行的二进制文件。

    .section .data
output:

    .ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"

    .section .text

    .global _start

_start:

    movl $0, %eax

    cpuid

    movl $output, %edi
    movl %ebx, 28(%edi)
    movl %edx, 32(%edi)
    movl %ecx, 36(%edi)

    movl $4, %eax
    movl $1, %ebx
    movl $output, %ecx
    movl $42, %edx
    int $0x80

    movl $1, %eax
    movl $0, %ebx
    int $0x80

如果我将上面的代码修改为下面,它是否正确或对 64 位 asm 编程有一些副作用?

         .section .data
 output:
         .ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"

         .section .text

         .global main
 main:
         movq $0, %rax
         cpuid

         lea output(%rip), %rdi
         movl %ebx, 28(%rdi)
         movl %edx, 32(%rdi)
         movl %ecx, 36(%rdi)
         movq %rdi, %r10

         movq $1, %rax
         movq $1, %rdi
         movq %r10, %rsi
         movq $42, %rdx
         syscall

【问题讨论】:

  • 您的编译器默认配置为 PIE。使用gcc -no-pie。此外,您似乎正在创建 64 位输出,但您的代码是 32 位的,稍后您可能会遇到问题。推荐你也加-m32
  • 为什么 gcc 默认将您的可执行文件设为共享对象:stackoverflow.com/questions/43367427/…。 “使用-fPIC”建议只对编译器生成的代码有意义;在您的情况下,这意味着将 asm 手动重写为与位置无关的代码。 (或者改为使用gcc -no-pie -m32 构建)。
  • @Jester 你能帮我知道真正的问题是什么吗?如果我使用 rax、rbx、rcx 和 rdi 而不是上述寄存器。那正确吗 ?因为我是 ia32 的新人
  • movl $output, %rcx 甚至不应该汇编,因为 64 位寄存器与 l 操作数大小后缀不匹配。如果您想制作 IA-32 代码而不是 x86-64,请使用 gcc -m32 构建。您正在使用the 32-bit int $0x80 ABI, so that's another sign you didn't intend to write 64-bit code。你不需要movl $1, %rbxmovl $1, %ebx 相比浪费空间。写入 32 位寄存器零扩展到 64 位寄存器。
  • 只需制作 32 位位置相关代码,这样您就可以继续使用 mov $output。我不同意@R. 的说法,即 PIC 更适合 32 位代码;这很不方便,并且会使您的代码显着变慢,并且更复杂(因此对初学者不利)。只有 x86-64 自然支持它,使用 RIP 相对寻址,如 lea output(%rip), %rsi

标签: c assembly ld


【解决方案1】:

正如 cmets 所指出的,您可以通过将程序链接为非 PIE 来解决此问题,但最好将您的 asm 修复为与位置无关。如果是 32 位 x86 代码,那就有点难看。这条指令:

    movl $output, %edi

会变成:

    call 1f
1:  pop %edi
    add $output-1b, %edi

对于 64 位,它更干净。而不是:

    movq $output, %rdi

你会写:

    lea output(%rip), %rdi

【讨论】:

  • call/pop 不推荐,它会破坏多达 16 条未来 ret 指令的分支预测。 (备份调用树)。真正的答案是,这是使用 32 位 int $0x80 ABI 的 32 位代码,因此除非您真的需要,否则您绝对应该将其设为 PIC,即将其放入共享图书馆。如果是 64 位代码,我会将其标记为 stackoverflow.com/questions/43367427/… 的副本。
  • @PeterCordes:我不同意。这显然是一个 asm 学习练习,任何在 2018 年编写 asm 的人都应该始终学习以与位置无关的方式编写它。 call/pop 方法是否会破坏现代微架构上的分支预测是一个我不知道答案的问题,但如果您不喜欢它,您可以随时用 call/mov/ret 方法替换它。在任何情况下,如果您正在进行系统调用,那么成本将主要由系统调用决定。
  • 就个人而言,我会在每次程序迭代或每次“大成本操作”发生少量/有限次数的任何地方编写 call/pop 习惯用法,仅仅是因为它在空间上是孤立且明显的,而且只会打扰如果在性能可能很重要的地方使用它可以表现更好的东西。
  • 嗯?手工编写 asm 的主要原因之一是性能。不利用位置相关的可执行文件来获得性能是没有意义的,因为在许多情况下它是一种选择。 (回复:预测:stackoverflow.com/questions/22442766/…,规范问答建议调用/mov/ret:stackoverflow.com/questions/599968/…)但是是的,理想情况下避免在调用树的深处进行,或者经常,如果由于某种原因你确实需要 32 位 PIC代码。
  • @PeterCordes:为提高性能而编写独立的 asm 文件(而不是可以集成到 asm 中的内联 asm)通常是一种倒退的做法。如果您正在编写内联 asm,则没有理由手动执行 pic;将地址操作数传递给 asm 块。是的,无论如何,有些人仍然会以倒退的方式做事,在这种情况下,他们应该为他们将针对的相关 cpu 模型研究最有效的 PC 相对寻址形式。他们不应该编写与 PIC 不兼容的代码。我发现 pic-incompatible asm 的自动反应是 --disable-asm
【解决方案2】:

使用 NASM,我通过在源文件中添加“DEFAULT REL”行来解决此问题(检查nasmdoc.pdf p.76)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 2013-10-22
    相关资源
    最近更新 更多