寄存器操作数
在本教程中,我们只关心整数寄存器和 xmm 寄存器。您应该已经知道什么是寄存器,但是这里是一个快速的回顾。16 个整数寄存器为 64 位宽,称为:
R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15RAX RCX RDX RBX RSP RBP RSI RDI
R0 = RAX, R1 = RCX, R2 = RDX, R3 = RBX, R4= RSP, R5 = RBP, R6 = RSI, R7 = RDI
(请注意,其中的最后 8 个寄存器具有备用名称)您可以将每个寄存器的最低 32 位视为寄存器本身,但可以使用以下名称:
R0D R1D R2D R3D R4D R5D R6D R7D R8D R9D R10D R11D R12D R13D R14D R15DEAX ECX EDX EBX ESP EBP ESI EDI
R0D = EAX, R1D = ECX, R2D = EDX, R3D = EBX, R4D = ESP, R5D = EBP, R6D = ESI, R7D = EDI
您可以使用以下名称将每个寄存器的最低 16 位看作一个寄存器:
R0W R1W R2W R3W R4W R5W R6W R7W R8W R9W R10W R11W R12W R13W R14W R15WAX CX DX BX SP BP SI DI
R0W = AX, R1W = CX, R2W = DX, R3W = BX, R4W = SP, R5W = BP, R6W = SI, R7W = DI
您可以使用以下名称将每个寄存器的最低 8 位看作一个寄存器:
R0B R1B R2B R3B R4B R5B R6B R7B R8B R9B R10B R11B R12B R13B R14B R15BAL CL DL BL SPL BPL SIL DIL
由于历史原因,R0...R3的第 8 至 15 位被命名为:
AH CH DH BH
最后,有 16 个 XMM 寄存器,每个 128 位宽,名为:
XMM0 ... XMM15
研究这张照片;希望它可以帮助:
内存操作数
这些是寻址的基本形式:
[ number ][ reg ][ reg + reg*scale ]小数位数只能是 1、2、4 或 8[ reg + number ][ reg + reg*scale + number ]
这个数字叫做位移 ; 普通寄存器称为基 ; 带有刻度的寄存器称为索引。
例子:
[750] ; 仅位移[rbp] ; 仅基址寄存器[rcx + rsi*4] ; 基数+指数*比例[rbp + rdx] ; scale is 1[rbx-8] ; 位移-8[rax + rdi*8 + 500] ; 所有四个组成部分[rbx + counter] ; 使用变量"counter"地址作为偏移
直接操作数
这些可以用多种方式编写。以下是官方文档中的一些示例。
200 ; 十进制数0200 ; 仍然是十进制-前导0不会使其变为八进制0200d ; 显式十进制-d后缀0d200 ; 也十进制-0d prefex,推荐0c8h ; 十六进制-h后缀,但是前导0是必需的,因为c8h看起来像var0xc8 ; hex-经典的0x前缀,推荐0hc8 ; 十六进制-由于某些原因,NASM偏爱0h写法,推荐310q ; 八进制-q后缀0q310 ; 八进制-0q前缀,推荐11001000b ; 二进制-b后缀0b1100_1000 ; 二进制-0b前缀,顺便说一下,允许使用下划线,推荐
具有两个内存操作数的指令非常少见
实际上,在本教程中我们将看不到任何此类说明。大多数基本说明只有以下几种形式:
addreg, reg |
|---|
addreg,mem |
addreg, imm |
addmem,reg |
addmem, imm |
定义数据并保留空间
这些示例来自 docs 的第 3 章。要将数据放入内存中:
db 0x55 ; 只是字节0x55db 0x55,0x56,0x57 ; 连续三个字节db 'a',0x55 ; 字符常量可以db 'hello',13,10,'$' ; 字符串常量也是如此dw 0x1234 ; 0x34 0x12dw 'a' ; 0x61 0x00(只是一个数字)dw 'ab' ; 0x61 0x62(字符常量)dw 'abc' ; 0x61 0x62 0x63 0x00(字符串)dd 0x12345678 ; 0x78 0x56 0x34 0x12dd 1.234567e20 ; 浮点常数dq 0x123456789abcdef0 ; 八字节常量dq 1.234567e20 ; 双精度浮点dt 1.234567e20 ; 扩展精度浮点
还有其他形式。请稍候自行查阅 NASM 文档。
要保留空间(无需初始化),可以使用以下伪指令。它们应该放在一个称为.bss的小节中(如果您试图在一个.text小节中使用它们,将会出现错误):
buffer: resb 64 ; 保留64个字节wordvar: resw 1 ; 保留一个字realarray: resq 10 ; 十个实数的数组
另一个例子
这是一个要研究的 macOS 程序:
triangle.asm
; ----------------------------------------------------------------------------------------; 这是一个OSX控制台程序,将星号的小三角形写成标准; 输出。仅在macOS上运行。;; nasm -fmacho64 triangle.asm && gcc hola.o && ./a.out; ----------------------------------------------------------------------------------------global _maindefault relsection .text_main:push rbx ; OSX必须,保存栈,Linux下删除该行mov rdx, output ; rdx holds address of next byte to writemov r8, 1 ; initial line lengthmov r9, 0 ; number of stars written on line so farline:mov byte [rdx], '*' ; write single starinc rdx ; advance pointer to next cell to writeinc r9 ; "count" number so far on linecmp r9, r8 ; did we reach the number of stars for this line?jne line ; not yet, keep writing on this linelineDone:mov byte [rdx], 10 ; write a new line charinc rdx ; and move pointer to where next char goesinc r8 ; next line will be one char longermov r9, 0 ; reset count of stars written on this linecmp r8, maxlines ; wait, did we already finish the last line?jng line ; if not, begin writing this linedone:mov rax, 0x02000004 ; system call for writemov rdi, 1 ; file handle 1 is stdoutmov rsi, output ; address of string to outputmov rdx, dataSize ; number of bytessyscall ; invoke operating system to do the write;exit(0)pop rbx ; OSX必须,弹出开头保存的栈,Linux下删除该行;mov rax, 0x02000001 ; system call for exit;xor rdi, rdi ; exit code 0;syscall ; invoke operating system to exitretsection .bssmaxlines equ 8dataSize equ 44output: resb dataSize
$ nasm -fmacho64 triangle.asm && ld triangle.o && ./a.out************************************
此示例中的新内容:
cmp做比较je如果先前的比较相等则跳转。jne(如果不等于则跳转)jl(如果不等于则跳转)jnl(如果不小于则跳转)jg(如果大于则跳转)jng(如果不大于则跳转)jle(如果小于或等于则跳转)jnle(如果不小于或等于则跳转)jge(如果大于或等于则跳转)jnge(如果不大于或等于则跳转)equ实际上不是真正的指令。它只是定义了供汇编程序本身使用的缩写。(这是一个意义深远的想法)- 本
.bss节适用于可写数据。
