换了64 位的系统,然后最近用了一下as,发现调用C 库直接不行了。
查了下貌似64 位的AT&T 汇编和32 位的已经有很大的不同。
下面是一些主要的不同之处,如果不怕麻烦可以自己看看文档System V Application Binary Interface AMD64 Architecture Processor Supplement。“这也是汇编语言不可移植的明证。” ——御坂0x4e27 如此说道。
1. 函数调用不再采用单纯压栈的方式:
下面的内容摘自WikiPedia:
Parameters in registers:RDI, RSI, RDX, RCX, R8, R9, XMM0–7
Parameter order on stack:RTL (C)
Stack cleanup by:Caller(调用者清理)
Notes:Stack aligned on 16 bytes boundary.Red zone below stack.
下面的内容摘自WikiPedia:
The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments.
additional arguments are passed on the stack and the return value is stored in RAX.
2. 系统调用的改变:
首先,int 0x80 指令被syscall 取代。
再者,系统调用编号已经改变,把下面的代码加入你的~/.bashrc
alias igrepsyscall_32='cat /usr/include/asm/unistd_32.h | grep -e '
alias igrepsyscall_64='cat /usr/include/asm/unistd_64.h | grep -e '
例如最常用的write 系统调用,32 位下是4,64 位下是1:
最后一点:系统调用的参数传递不再使用32 位下的寄存器,而是和函数调用使用的寄存器一致。
(摘自WikiPedia)
The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments.
For system calls, R10 is used instead of RCX.
下面是一段很简短的代码,演示了这些不同:
# only for as x86_64
.section .data
strFormat:
.asciz "%s\n"
strUseLibc:
.asciz "Hi, If you see me, you called c lib :)"
strUseSyscall:
.asciz "And if you see me, you called syscall.\n"
endOfStrUseSyscall:
.section .text
.globl _start
_start:
# 函数调用的传参已经不再单纯使用压栈的方式
movq $strFormat, %rdi
movq $strUseLibc, %rsi
call printf
# 系统调用的寄存器已经改变,int 0x80 也被syscall 替代
movq $1, %rdi
movq $strUseSyscall, %rsi
movq $(endOfStrUseSyscall-strUseSyscall), %rdx
movq $1, %rax
syscall
# 另外系统调用的编号也不同了
movq $127, %rdi # 故意返回一个非0 值
movq $60, %rax
syscall
不同大约就是这样,祝你愉快 :D
当然你仍然使用64 位开发环境来写32 位程序,只需要给编译器和链接器传递对应的参数,例如:
# as --32 -o file.o file.s
# ld -m elf_i386 --oformat elf32-i386 -o file file.o
另外--oformat 不加貌似也可以正常工作。