寄存器操作数

在本教程中,我们只关心整数寄存器和 xmm 寄存器。您应该已经知道什么是寄存器,但是这里是一个快速的回顾。16 个整数寄存器为 64 位宽,称为:

  1. R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15
  2. RAX 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 位视为寄存器本身,但可以使用以下名称:

  1. R0D R1D R2D R3D R4D R5D R6D R7D R8D R9D R10D R11D R12D R13D R14D R15D
  2. EAX ECX EDX EBX ESP EBP ESI EDI

R0D = EAX, R1D = ECX, R2D = EDX, R3D = EBX, R4D = ESP, R5D = EBP, R6D = ESI, R7D = EDI
您可以使用以下名称将每个寄存器的最低 16 位看作一个寄存器:

  1. R0W R1W R2W R3W R4W R5W R6W R7W R8W R9W R10W R11W R12W R13W R14W R15W
  2. AX CX DX BX SP BP SI DI

R0W = AX, R1W = CX, R2W = DX, R3W = BX, R4W = SP, R5W = BP, R6W = SI, R7W = DI
您可以使用以下名称将每个寄存器的最低 8 位看作一个寄存器:

  1. R0B R1B R2B R3B R4B R5B R6B R7B R8B R9B R10B R11B R12B R13B R14B R15B
  2. AL CL DL BL SPL BPL SIL DIL

由于历史原因,R0...R3的第 8 至 15 位被命名为:

  1. AH CH DH BH

最后,有 16 个 XMM 寄存器,每个 128 位宽,名为:

  1. XMM0 ... XMM15

研究这张照片;希望它可以帮助:

nasm语法3-操作数类型 - 图1

内存操作数

这些是寻址的基本形式:

  • [ number ]
  • [ reg ]
  • [ reg + reg*scale ] 小数位数只能是 1、2、4 或 8
  • [ reg + number ]
  • [ reg + reg*scale + number ]

这个数字叫做位移 ; 普通寄存器称为 ; 带有刻度的寄存器称为索引

例子:

  1. [750] ; 仅位移
  2. [rbp] ; 仅基址寄存器
  3. [rcx + rsi*4] ; 基数+指数*比例
  4. [rbp + rdx] ; scale is 1
  5. [rbx-8] ; 位移-8
  6. [rax + rdi*8 + 500] ; 所有四个组成部分
  7. [rbx + counter] ; 使用变量"counter"地址作为偏移

直接操作数

这些可以用多种方式编写。以下是官方文档中的一些示例。

  1. 200 ; 十进制数
  2. 0200 ; 仍然是十进制-前导0不会使其变为八进制
  3. 0200d ; 显式十进制-d后缀
  4. 0d200 ; 也十进制-0d prefex,推荐
  5. 0c8h ; 十六进制-h后缀,但是前导0是必需的,因为c8h看起来像var
  6. 0xc8 ; hex-经典的0x前缀,推荐
  7. 0hc8 ; 十六进制-由于某些原因,NASM偏爱0h写法,推荐
  8. 310q ; 八进制-q后缀
  9. 0q310 ; 八进制-0q前缀,推荐
  10. 11001000b ; 二进制-b后缀
  11. 0b1100_1000 ; 二进制-0b前缀,顺便说一下,允许使用下划线,推荐

具有两个内存操作数的指令非常少见

实际上,在本教程中我们将看不到任何此类说明。大多数基本说明只有以下几种形式:

add
reg, reg
add
reg,mem
add
reg, imm
add
mem,reg
add
mem, imm

定义数据并保留空间

这些示例来自 docs 的第 3 章。要将数据放入内存中:

  1. db 0x55 ; 只是字节0x55
  2. db 0x55,0x56,0x57 ; 连续三个字节
  3. db 'a',0x55 ; 字符常量可以
  4. db 'hello',13,10,'$' ; 字符串常量也是如此
  5. dw 0x1234 ; 0x34 0x12
  6. dw 'a' ; 0x61 0x00(只是一个数字)
  7. dw 'ab' ; 0x61 0x62(字符常量)
  8. dw 'abc' ; 0x61 0x62 0x63 0x00(字符串)
  9. dd 0x12345678 ; 0x78 0x56 0x34 0x12
  10. dd 1.234567e20 ; 浮点常数
  11. dq 0x123456789abcdef0 ; 八字节常量
  12. dq 1.234567e20 ; 双精度浮点
  13. dt 1.234567e20 ; 扩展精度浮点

还有其他形式。请稍候自行查阅 NASM 文档。

要保留空间(无需初始化),可以使用以下伪指令。它们应该放在一个称为.bss的小节中(如果您试图在一个.text小节中使用它们,将会出现错误):

  1. buffer: resb 64 ; 保留64个字节
  2. wordvar: resw 1 ; 保留一个字
  3. realarray: resq 10 ; 十个实数的数组

另一个例子

这是一个要研究的 macOS 程序:

triangle.asm

  1. ; ----------------------------------------------------------------------------------------
  2. ; 这是一个OSX控制台程序,将星号的小三角形写成标准
  3. ; 输出。仅在macOS上运行。
  4. ;
  5. ; nasm -fmacho64 triangle.asm && gcc hola.o && ./a.out
  6. ; ----------------------------------------------------------------------------------------
  7. global _main
  8. default rel
  9. section .text
  10. _main:
  11. push rbx ; OSX必须,保存栈,Linux下删除该行
  12. mov rdx, output ; rdx holds address of next byte to write
  13. mov r8, 1 ; initial line length
  14. mov r9, 0 ; number of stars written on line so far
  15. line:
  16. mov byte [rdx], '*' ; write single star
  17. inc rdx ; advance pointer to next cell to write
  18. inc r9 ; "count" number so far on line
  19. cmp r9, r8 ; did we reach the number of stars for this line?
  20. jne line ; not yet, keep writing on this line
  21. lineDone:
  22. mov byte [rdx], 10 ; write a new line char
  23. inc rdx ; and move pointer to where next char goes
  24. inc r8 ; next line will be one char longer
  25. mov r9, 0 ; reset count of stars written on this line
  26. cmp r8, maxlines ; wait, did we already finish the last line?
  27. jng line ; if not, begin writing this line
  28. done:
  29. mov rax, 0x02000004 ; system call for write
  30. mov rdi, 1 ; file handle 1 is stdout
  31. mov rsi, output ; address of string to output
  32. mov rdx, dataSize ; number of bytes
  33. syscall ; invoke operating system to do the write
  34. ;exit(0)
  35. pop rbx ; OSX必须,弹出开头保存的栈,Linux下删除该行
  36. ;mov rax, 0x02000001 ; system call for exit
  37. ;xor rdi, rdi ; exit code 0
  38. ;syscall ; invoke operating system to exit
  39. ret
  40. section .bss
  41. maxlines equ 8
  42. dataSize equ 44
  43. output: resb dataSize
  1. $ nasm -fmacho64 triangle.asm && ld triangle.o && ./a.out
  2. *
  3. **
  4. ***
  5. ****
  6. *****
  7. ******
  8. *******
  9. ********

此示例中的新内容:

  • cmp 做比较
  • je如果先前的比较相等则跳转。
  • jne(如果不等于则跳转)
  • jl(如果不等于则跳转)
  • jnl(如果不小于则跳转)
  • jg(如果大于则跳转)
  • jng(如果不大于则跳转)
  • jle(如果小于或等于则跳转)
  • jnle(如果不小于或等于则跳转)
  • jge(如果大于或等于则跳转)
  • jnge(如果不大于或等于则跳转)
  • equ实际上不是真正的指令。它只是定义了供汇编程序本身使用的缩写。(这是一个意义深远的想法)
  • .bss节适用于可写数据。