【发布时间】: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-bitint $0x80ABI, so that's another sign you didn't intend to write 64-bit code。你不需要movl $1, %rbx与movl $1, %ebx相比浪费空间。写入 32 位寄存器零扩展到 64 位寄存器。 -
只需制作 32 位位置相关代码,这样您就可以继续使用
mov $output。我不同意@R. 的说法,即 PIC 更适合 32 位代码;这很不方便,并且会使您的代码显着变慢,并且更复杂(因此对初学者不利)。只有 x86-64 自然支持它,使用 RIP 相对寻址,如lea output(%rip), %rsi