文章目录
- 写在前面
- 寄存器使用
- 语法
- 指令后缀
- 寻址方式
- 系统调用
- 示例程序
写在前面
x86汇编有intel和AT&T两种语法,网上资料使用intel语法的相对多一些,但是在linux平台的GNU汇编器用的是AT&T语法,本篇记录一下AT&T格式汇编程序的hello world
寄存器使用
64位模式和32位模式的寄存器用途是不太一样的,网上的有些资料比较老,讲的还是32位模式下的寄存器用法
可以参考这篇文章
x86汇编通用寄存器用途一览
语法
intel语法是源操作数在后,目的操作数在前,AT&T语法是源操作数在前,目的操作数在后
指令后缀
AT&T格式的汇编指令有不同的后缀
其中
b表示byte,字节
w表示word,字/两字节
l表示long,32位系统下的long是4字节
q表示quad,意味四重,表示4个字/8字节
寻址方式
立即数寻址无非就是movq $1, %rax这样,主要的差异在于寄存器寻址:
指针寄存器rsp可以用-8(%rsp)这种方式来寻址,rax等寄存器则不能
想寻址的偏移量保存在寄存器里:
(%rsp, %rax) # 偏移rax寄存器里保存的值
(%rsp, %rax, 2) # 取rsp偏移rax2处的值,上行实际上是缺省了1
2(%rsp, %rax, 2) # 取rsp偏移rax2+2处的值
如下图所示
通过gdb调试查看,符合
系统调用
c库封装的系统调用API的声明在↑这个文件,在这里我们可以了解到系统调用需要的参数↓
write系统调用,参数1:文件描述符,参数2:字符串地址,参数3:输出长度
x86平台的系统调用号在这个文件,在这里我们可以找到目标系统调用对应的调用号
64位下,write的系统调用号是1
32位下,write的系统调用号是4
需要注意的是,64位下的系统调用指令是syscall,int $0x80是32位下的系统调用指令,使用syscall会去匹配64位下的系统调用号,使用int $0x80会去匹配32位的系统调用号
示例程序
64位模式下
.data
strr: .string "hello world~\n"
len = .-strr
.text
.global _start
_start:
movq $1, %rax # syscall number of write
movq $1, %rdi # param1: stdout
movq $strr, %rsi # param2: str address
movq $len, %rdx # param3: out length
syscall
movq $60, %rax # syscall number of exit
syscall
32位模式下
.data
strr: .string "hello world~\n"
len = .-strr
.text
.global _start
_start:
movl $4, %eax # syscall number of write in i386
movl $1, %ebx # param1: stdout
movl $strr, %ecx # param2: str address
movl $len, %edx # param3: out length
int $0x80
movl $1, %eax # syscall number of exit in i386
int $0x80
编译和运行