照着例子抄写了一下,直接用的 gcc 编译,源码如下,因为不支持 pushl,所以改成了 pushq
#cpuid.s View the CPUID Vendor ID string using C library calls
.section .data
output:
.asciz "The processor Vendor ID is %s \n"
.section .bss
.lcomm buffer, 12
.section .text
.global main
main:
MOVL $0, %eax
cpuid
MOVL $buffer, %edi
MOVL %ebx, (%edi)
MOVL %edx, 4(%edi)
MOVL %ecx, 8(%edi)
pushq $buffer
pushq $output
call printf
addl $8, %esp
pushq $0
call exit
如果使用 pushl 的话,在x86_64 位下不支持,如下错误信息:
网上搜索到解决办法有 2 种,一种是在源码开头添加.code32 告诉编译器按照32位进行编译,另外一种是使用 pushq,q 即为 quad word 表示 8 字节长度的,即 64 位。编译通过后,运行时出现 segmentation fault。网上搜了很多,没有一样的,但很多相似的在调用 printf 的时候出现 segmentation fault,这个跟调用约定有关系,64 位和32 位还不一样,64 位下是通过寄存器和栈来传递参数的,而 32 位下则是通过栈来传递参数的。看上面的代码 pushq $buffer 和 pushq $output 就是入栈操作,而在 64 位下:整数参数(包含指针)依次放在 %rdi, %rsi, %rdx, %rcx, %r8, 和 %r9 寄存器中,如果调用的是可变参数的函数(比如printf), 寄存器%eax需记录下浮点参数的个数,找到一段可用的代码,修改如下:
.section .data
output:
.string "The processor Vendor ID is %s \n"
.section .bss
.lcomm buffer, 32
.section .text
.global main
main:
MOVL $0, %eax
cpuid
MOVL $buffer, %edi
MOVL %ebx, (%edi)
MOVL %edx, 4(%edi)
MOVL %ecx, 8(%edi)
MOVQ $output, %rdi #需要用MOVQ 来操作64bit寄存器
MOVQ $buffer, %rsi #同上
MOVQ $0, %rax #同上
pushq %r10
pushq %r11
call printf
popq %r11
popq %r10
ret