汇编语言
配置安装
1
2
3
4
| apt install nasm gdb # 安装
# vscode 插件 The Netwide Assembler (NASM) 后缀改成nas或者asm
nasm -f elf -o hello.o hello.s # 编译
ld -m elf_i386 -o hello.out hello.o # 链接
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| ASM = nasm
LD = ld
ASM_FLAGS = -f elf
LD_FLAGS = -m elf_i386
# Source and output files
TARGETS = code01
SRCS = $(wildcard *.s)
OBJS = $(patsubst %.s, %.o, $(SRCS))
# Targets
all: $(TARGETS)
$(TARGETS): %: %.o
$(LD) -o $@ $^ $(LD_FLAGS)
%.o: %.s
$(ASM) $(ASM_FLAGS) $< -o $@
.PHONY: clean
clean:
rm -f *.o $(TARGETS)
|
gdb
1
2
3
4
5
6
7
8
9
10
| # 启动配置文件 .gdbinit,需要设置安全设置生效
cat ~/.config/gdb/gdbinit
add-auto-load-safe-path /home/username/compiler_test/lab01/
# .gdbinit
break _start
run
set disassembly-flavor intel # 默认att, 设置intel风格
# set disassemble-next-line on
layout asm
layout reg
|
常用gdb调试
1
2
3
4
5
6
7
8
| # nm 查看符号表
# x /选项 地址 查看各个变量内存信息
const char* str = "test";
x str # 默认16进制显示,内存存储内容和“test"相反(小端存储) 0x74736574
x /s str # 直接显示内容 ”test"
x /d str # 十进制显示
x /4d str # 十进制显示,显示宽度为4
# 变量非指针类型,如int, 先p &value_name, 使用x查看
|
X86体系结构
寄存器
分类 | 英文全称 | 16 位 | 32 位 | 64 位 |
---|
通用寄存器 | Accumulator | ax | eax | rax |
通用寄存器 | Base | bx | ebx | rbx |
通用寄存器 | Counter | cx | ecx | rcx |
通用寄存器 | Data | dx | edx | rdx |
指针寄存器:栈指针,指向当前栈顶 | Stack Pointer | sp | esp | rsp |
指针寄存器:基址指针,通常用于访问栈帧中的局部变量 | Base Pointer | bp | ebp | rbp |
变地址寄存器:源变址寄存器 | Source Index | si | esi | rsi |
变地址寄存器:目的变址寄存器 | Destination Index | di | edi | rdi |
控制寄存器:指令指针,指向下一条要执行的指令 | Instruction Pointer | ip | eip | rip |
控制寄存器:标志寄存器,存储 CPU 的状态标志 | Flag | flag | eflag | rflag |
段寄存器 | Code Segment | cs | cs | cs |
段寄存器 | Data Segment | ds | ds | ds |
段寄存器 | Stack Segment | ss | ss | ss |
段寄存器 | Extra Segment | es | es | es |
基本汇编语法
Basic Instruction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| mov dest, src ; move src to desc
mov eax, 4 ; 将立即数 (immidiate) 存入到 eax 寄存器中
mov bx, ax ; bx = ax
add eax, 4 ; eax = eax + 4
sub ebx, edi ; ebx = ebx - edi
inc ecx ; ecx++
mov eax, 10
mov ebx, 20
mul ebx ; edx:eax = eax * ebx mul无符号,imul有符号 edx:eax 表示 64 位的值
mov eax, 100
mov ebx, 20
div ebx ; eax = 5 (商), edx = 0 (余数) div无符号,idiv有符号
|
Directive Instruction
定义常量
1
2
3
| symbol equ 128
aaa equ 8
%define SIZE 128
|
定义内存
1
2
3
4
| L1 db 0 ; 定义一个字节, 并初始化为 0
L2 dw0 ; 定义一个字 (word), 并初始化为 0
L3 resb 4 ; 预留 4 个字节
L4 times 100 db 1 ; 100 次定义字节, 初始化成 1
|
寻址模式
立即寻址
1
| mov eax, 10 ; 将立即数 10 加载到 eax
|
寄存器寻址
1
| mov eax, ebx ; 将 ebx 的值加载到 eax
|
直接寻址
1
| mov eax, [0x1000] ; 将地址 0x1000 处的值加载到 eax
|
寄存器间接寻址
1
| mov eax, [ebx] ; 将 ebx 指向的内存地址的值加载到 eax
|
基址加变址寻址
1
| mov eax, [ebx+ecx*4] ; 将 ebx + ecx * 4 处的值加载到 eax
|
控制流
比较指令
Bit | Label | Description |
---|
0 | CF | Carry Flag(进位标志):运算结果的最高有效位有进位(加法)或借位(减法)时,进位标志置1 |
2 | PF | Parity Flag(奇偶标志):运算结果的所有位中1的个数是偶数置1 |
4 | AF | Auxiliary Carry flag(辅助进位标志位):第3位向第4位发生了进位,那么AF标志位置1 |
6 | ZF | Zero Flag:结果为0,置1 |
7 | SF | Sign Flag:结果为负数(最高位为1),置1 |
8 | TF | Trap Flag:陷阱标志位 ,用于调试,置 1 时单步执行。 |
9 | IF | Interrupt enable Flag:是否响应中断 |
10 | DF | Direction Flag(方向标志位)控制字符串操作的方向(0:递增,1:递减) |
11 | OF | Overflow Flag(溢出标志位) |
12-13 | IOPL | I/O privilege level:控制 I/O 指令的执行权限 |
14 | NT | Nested task |
16 | RF | Resume Flag 用于调试,控制是否忽略断点 |
17 | VM | Virtual-8086 mode:置 1 时进入虚拟 8086 模式 |
18 | AC | Alignment check / Access Control:置 1 时启用对齐检查 |
19 | VIF | Virtual Interrupt Flag:虚拟模式下的中断标志 |
20 | VIP | Virtual Interrupt Pending:虚拟模式下的中断挂起状态。 |
21 | ID | ID Flag :支持 CPUID 指令的标志 |
1
| cmp a, b ;计算 a-b 的值,并设置标志寄存器
|
对于无符号数字计算,存在以下场景: ZF(Zero Flag), CF(Carry Flag)
- a=b => ZF=1, CF=0
- a>b => ZF=0, CF=0
- a<b => ZF=0, CF=1
对于有符号数字计算,存在以下场景: ZF(Zero Flag), OF(Overflow Flag), SF(Sign Flag)
- a=b => ZF=1
- a>b => ZF=0, OF = SF
- a<b => ZF=0, OF != SF
跳转指令
指令 | 条件 |
---|
JZ | branch only if ZF=1 |
JNZ | branch only if ZF=0 |
JO | branch only if OF=1 |
JNO | branch only if OF=0 |
JS | branch only if SF=1 |
JNS | branch only if SF=0 |
JC | branch only if CF=1 |
JNC | branch only if CF=0 |
JP | branch only if PF=1 |
JNP | branch only if PF=0 |
循环指令
1
2
3
| loop label ; ecx--,如果 ecx != 0,跳转到 label
loope label ; ecx--,如果 ecx != 0 且 ZF=1,跳转到 label
loopne label ; ecx--,如果 ecx != 0 且 ZF=0,跳转到 label
|
函数调用
1
2
| call func01 ;调用函数
ret ;函数返回
|
参考阅读
汇编语言-B站
Arch Linux - v86 (copy.sh)