- NASM是基于英特尔 x86 架构的汇编与反汇编工具。
- syscall是x86_64架构中专门做系统调用的指令,可参考syscall
1、示例
foo.nasm内容
global _start
section .text
_start:
mov rax, 1 ; sys_write的系统调用编号为1
mov rdi, 1 ; 文件句柄1对应stdout
mov rsi, msg ; 要输出的字符串地址
mov rdx, msglen ; 要输出的字符串长度
syscall ; 系统调用
mov rax, 60 ; sys_exit的系统调用编号为60
xor rdi, rdi ; exit 0
syscall
section .data
msg: db "Hello, World!", 10 ; ascii表中10对应换行符
msglen: equ $ - msg ; $ 等于当前行开头的地址
编译
nasm -felf64 foo.asm && ld -o foo foo.o
运行结果
[root@localhost nasm]# ./foo
Hello, World!
2、代码解释
2.1、syscall
x86平台syscall指令的参数、返回值与寄存器的对应关系
Syscall # | Param 1 | Param 2 | Param 3 | Param 4 | Param 5 | Param 6 |
---|---|---|---|---|---|---|
rax | rdi | rsi | rdx | r10 | r8 | r9 |
Return value |
---|
rax |
各平台系统调用指令和返回值对应寄存器
系统调用参数对应寄存器
在linux平台write函数对应系统调用为sys_write,对应的syscall编号可在
arch/x86/entry/syscalls/syscall_64.tbl中查看
1 common write sys_write
60 common exit sys_exit
sys_write和sys_exit的定义为
asmlinkage long sys_write(unsigned int fd, const char __user *buf,
size_t count);
asmlinkage long sys_exit(int error_code);
2.2、sys_exit
mov rax, 60 ; sys_exit的系统调用编号为60
xor rdi, rdi ; exit 0
syscall
语句
xor rdi, rdi 将rdi寄存器值设置为0,至于为什么不使用
mov rdi, 0 可参考
Does using xor reg, reg give advantage over mov reg, 0?,程序运行效果为
[root@localhost nasm]# nasm -felf64 foo.asm && ld -o foo foo.o
[root@localhost nasm]# ./foo
Hello, World!
[root@localhost nasm]# echo $?
0
如果修改sys_exit系统调用的参数,那么程序运行的退出结果也会发生变化,如修改为
mov rdi, rax
mov rax, 60 ; sys_exit的系统调用编号为60
syscall
则程序退出码为sys_write的返回值,因为字符串msg长度为14,所以程序运行的退出码也为14
[root@localhost nasm]# nasm -felf64 foo.asm && ld -o foo foo.o
[root@localhost nasm]# ./foo
Hello, World!
[root@localhost nasm]# echo $?
14
2.3、字符串长度计算
在nasm中
$ 等于当前行开头的地址,
$$ 等于当前section的开头地址,可参考 https://www.nasm.us/doc/nasmdoc3.html 的3.5 Expressions内容
NASM supports two special tokens in expressions, allowing calculations to involve the current assembly position: the $ and $$ tokens. $ evaluates to the assembly position at the beginning of the line containing the expression; so you can code an infinite loop using JMP $. $$ evaluates to the beginning of the current section; so you can tell how far into the section you are by using ($-$$).