本文所述的是64位汇编。

环境搭建

安装nasm:

macOS

我假设你已经装好了brew和xcode-dev-tools。

1
brew install nasm

就结束了。

linux,以ubuntu为例

1
apt install nasm

就好了,如果你需要调试,请自行了解安装gdb。

代码

nasm和masm语法大部分地方是相似的,但部分语法上还是略有不同的。

另外,64位汇编和实模式汇编虽然大部分指令相同,但寻址(取消分段,改为分页)等方面有很大的差异。

这些语法上的差异可以上网自行查询1,在此略过不提,在此仅提供例程,例程功能是打印ASCII码表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
global _start

section .data
char : db 97
crlf : db 10
section .bss

section .text

_start:
mov bl, 0
loop_start:
mov byte [rel char], bl
mov rax, 0x2000004 ; (macOS) call write,on linux, change 0x2000004 to 0x1
mov rdi, 1 ; fd = 1, aka stdout
mov rsi, char ; cbuf = char
mov rdx, 1 ; nbyte = 1
syscall

add bl, 1

mov ah, 0
mov al, bl

mov cx, 0xa
div byte cl

cmp ah, 0x9
jne skip

mov rax, 0x2000004 ; (macOS) call write,on linux, change 0x2000004 to 0x1
mov rdi, 1 ; fd = 1, aka stdout
mov rsi, crlf ; cbuf = crlf
mov rdx, 1 ; nbyte = 2
syscall

skip:
cmp bl, 128
jne loop_start

mov rax, 0x2000001 ; (macOS) call exit,on linux, change 0x2000001 to 60
mov rdi, 0 ; rval = 0
syscall

另附macOS2linux syscall列表。

编译运行

macOS:

macOS上需要出的是macho64格式:

1
2
nasm -f macho64 文件名.asm
ld -e _start -lSystem -no_pie 文件名.o -o 输出文件名

linux:

linux一般使用elf64格式:

1
2
nasm 文件名.asm -f elf64
ld -e _start 文件名.o -o 输出文件名

调试

lldb为例,gdb等应该与此相似:

假设输出文件为a.out

1
lldb a.out

b start在开始执行你写的代码暂停(实际上是在”start”处戳一个断点)。

然后用n来单步执行,或者在b 地址在相应地址处戳断点。

1. 真相是我也不太懂……
2. macOS调用时要在表中的数字基础上加上0x2000000,别问我为啥,这是魔法