汇编语言 算术指令

INC 指令

INC 指令用于将操作数加 1。它对可以在寄存器或内存中的单个操作数起作用。

语法

INC 指令的语法如下:

  1. INC destination

目标操作数 可以是 8 位,16 位或 32 位操作数。

实例
  1. INC EBX ; 32 位寄存器 自增 1
  2. INC DL ; 8 位寄存器 自增 1
  3. INC [count] ; 变量 count 自增 1

DEC 指令

DEC 指令用于将操作数减 1。它对可以在寄存器或内存中的单个操作数起作用。

语法

DEC 指令的语法如下:

  1. DEC destination

目标操作数 可以是 8 位,16 位或 32 位操作数。

实例
  1. segment .data
  2. count dw 0
  3. value db 15
  4. segment .text
  5. inc [count]
  6. dec [value]
  7. mov ebx, count
  8. inc word [ebx]
  9. mov esi, value
  10. dec byte [esi]

ADD 和 SUB 指令

ADDSUB 指令用于对字节,字和双字大小的二进制数据进行简单的 加/减,即分别用于加或减去 8 位,16 位或 32 位操作数。

语法

ADDSUB 指令的语法如下:

  1. ADD/SUB destination, source

ADD / SUB 指令可以发生在:

  • 寄存器 到 寄存器
  • 内存 到 寄存器
  • 寄存器 到 内存
  • 寄存器 到 常量数据
  • 内存 到 常量数据

但是,像其他指令一样,使用 ADD / SUB 指令也无法进行存储器到存储器的操作。ADDSUB 操作设置或清除溢出和进位标志。

实例

下面的实例将要求用户输入两位数字,分别将这些数字存储在 EAXEBX 寄存器中,将这些值相加,将结果存储在 "res" 存储位置中,最后显示结果:

  1. SYS_EXIT equ 1
  2. SYS_READ equ 3
  3. SYS_WRITE equ 4
  4. STDIN equ 0
  5. STDOUT equ 1
  6. segment .data
  7. msg1 db "Enter a digit ", 0xA,0xD
  8. len1 equ $- msg1
  9. msg2 db "Please enter a second digit", 0xA,0xD
  10. len2 equ $- msg2
  11. msg3 db "The sum is: "
  12. len3 equ $- msg3
  13. segment .bss
  14. num1 resb 2
  15. num2 resb 2
  16. res resb 1
  17. section .text
  18. global _start ;必须声明 gcc
  19. _start: ;告诉链接器入口
  20. mov eax, SYS_WRITE
  21. mov ebx, STDOUT
  22. mov ecx, msg1
  23. mov edx, len1
  24. int 0x80
  25. mov eax, SYS_READ
  26. mov ebx, STDIN
  27. mov ecx, num1
  28. mov edx, 2
  29. int 0x80
  30. mov eax, SYS_WRITE
  31. mov ebx, STDOUT
  32. mov ecx, msg2
  33. mov edx, len2
  34. int 0x80
  35. mov eax, SYS_READ
  36. mov ebx, STDIN
  37. mov ecx, num2
  38. mov edx, 2
  39. int 0x80
  40. mov eax, SYS_WRITE
  41. mov ebx, STDOUT
  42. mov ecx, msg3
  43. mov edx, len3
  44. int 0x80
  45. ; 将第一个数字移动到 eax 寄存器,将第二个数字移动至 ebx
  46. ; 并减去 ascii 0 将其转换为十进制数
  47. mov eax, [num1]
  48. sub eax, '0'
  49. mov ebx, [num2]
  50. sub ebx, '0'
  51. ; 添加 eax ebx
  52. add eax, ebx
  53. ; 0 添加到以将十进制和转换为 ASCII
  54. add eax, '0'
  55. ; 将总和存储在内存位置 res
  56. mov [res], eax
  57. ; 打印总和
  58. mov eax, SYS_WRITE
  59. mov ebx, STDOUT
  60. mov ecx, res
  61. mov edx, 1
  62. int 0x80
  63. exit:
  64. mov eax, SYS_EXIT
  65. xor ebx, ebx
  66. int 0x80

结果如下:

  1. Enter a digit:
  2. 3
  3. Please enter a second digit:
  4. 4
  5. The sum is:
  6. 7

具有硬编码变量的程序:

  1. section .text
  2. global _start ;必须声明 gcc
  3. _start: ;告诉链接器入口
  4. mov eax,'3'
  5. sub eax, '0'
  6. mov ebx, '4'
  7. sub ebx, '0'
  8. add eax, ebx
  9. add eax, '0'
  10. mov [sum], eax
  11. mov ecx,msg
  12. mov edx, len
  13. mov ebx,1 ;文件描述 (stdout)
  14. mov eax,4 ;系统调用号 (sys_write)
  15. int 0x80 ;调用内核
  16. mov ecx,sum
  17. mov edx, 1
  18. mov ebx,1 ;文件描述 (stdout)
  19. mov eax,4 ;系统调用号 (sys_write)
  20. int 0x80 ;调用内核
  21. mov eax,1 ;系统调用号 (sys_exit)
  22. int 0x80 ;调用内核
  23. section .data
  24. msg db "The sum is:", 0xA,0xD
  25. len equ $ - msg
  26. segment .bss
  27. sum resb 1

结果如下:

  1. The sum is:
  2. 7

MUL/IMUL 指令

二进制数据相乘有两条指令。MUL(乘法)指令处理无符号数据,IMUL(整数乘法)处理有符号数据。这两条指令都会影响进位和溢出标志。

语法

MUL/IMUL 指令的语法如下:

  1. MUL/IMUL multiplier

在这两种情况下,被乘数都将在一个累加器中,具体取决于被乘数和乘数的大小,并且根据操作数的大小,生成的乘积还将存储在两个寄存器中。

以下部分说明了 3 种不同情况下的 MUL 指令:

编号情景
1

当两个字节相乘时:

被乘数在 AL 寄存器中,而乘数在存储器或另一个寄存器中为一个字节。该产品使用 AX。乘积的高 8 位存储在 AH 中,低 8 位存储在 AL 中。

Arithmetic1

2

当两个单字值相乘时:

被乘数应位于 AX 寄存器中,并且乘数是内存或其他寄存器中的一个字。例如,对于 MUL DX 之类的指令,必须将乘数存储在 DX 中,将被乘数存储在 AX 中。

结果乘积是一个双字,将需要两个寄存器。高阶(最左侧)部分存储在 DX 中,而低阶(最右侧)部分存储在 AX 中。

Arithmetic2

3

当两个双字值相乘时:

当两个双字值相乘时,被乘数应位于 EAX 中,并且该乘数是存储在存储器或另一个寄存器中的双字值。生成的乘积存储在 EDX:EAX 寄存器中,即,高 32 位存储在 EDX 寄存器中,低 32 位存储在 EAX 寄存器中。

Arithmetic3

实例
  1. MOV AL, 10
  2. MOV DL, 25
  3. MUL DL
  4. ...
  5. MOV DL, 0FFH; DL= -1
  6. MOV AL, 0BEH; AL = -66
  7. IMUL DL
实例

以下实例将 3 乘以 2,并显示结果:

  1. section .text
  2. global _start ;必须声明 gcc
  3. _start: ;告诉链接器入口点
  4. mov al,'3'
  5. sub al, '0'
  6. mov bl, '2'
  7. sub bl, '0'
  8. mul bl
  9. add al, '0'
  10. mov [res], al
  11. mov ecx,msg
  12. mov edx, len
  13. mov ebx,1 ;文件描述 (stdout)
  14. mov eax,4 ;系统调用号 (sys_write)
  15. int 0x80 ;调用内核
  16. mov ecx,res
  17. mov edx, 1
  18. mov ebx,1 ;文件描述 (stdout)
  19. mov eax,4 ;系统调用号 (sys_write)
  20. int 0x80 ;调用内核
  21. mov eax,1 ;系统调用号 (sys_exit)
  22. int 0x80 ;调用内核
  23. section .data
  24. msg db "The result is:", 0xA,0xD
  25. len equ $- msg
  26. segment .bss
  27. res resb 1

结果如下:

  1. The result is:
  2. 6

DIV/IDIV 指令

除法运算生成两个元素 —— 余数。在乘法的情况下,不会发生溢出,因为使用双长度寄存器来保存乘积。然而,在除法的情况下,可能会发生溢出。如果发生溢出,处理器将生成中断。DIV(Divide)指令用于无符号数据,IDIV(整数除法)用于有符号数据。

DIV(Divide)指令用于无符号数据,IDIV(整数除法)用于有符号数据。

语法

DIV / IDIV 指令的格式:

  1. DIV/IDIV divisor

被除数在累加器中。两条指令都可以使用 8 位,16 位或 32 位操作数。该操作影响所有 6 个状态标志。

以下部分说明了 3 种操作数大小不同的除法情况:

编号情景
1

当除数为 1 个字节时:

假设被除数在 AX 寄存器中(16 位)除法后,商进入 AL 寄存器,余数进入 AH 寄存器

Arithmetic4

2

当除数为 1 个单字时:

假设被除数为 32 位长,并且在 DX:AX 寄存器中高位 16 位在 DX 中,低位 16 位在 AX 中除法后,16 位商进入 AX 寄存器,16 位余数进入 DX 寄存器。

Arithmetic5

3

当除数是双字:

假设被除数为 64 位长,并且在 EDX:EAX 寄存器中高位 32 位在 EDX 中,低位 32 位在 EAX 中除法后,32 位商进入 EAX 寄存器,32 位余数进入 EDX 寄存器。

Arithmetic6

实例

以下实例将 8 除以 2。被除数 8 存储在 16 位 AX 寄存器中,除数 2 存储在 8 位 BL 寄存器 中。

  1. section .text
  2. global _start ;必须声明 gcc
  3. _start: ;告诉链接器入口点
  4. mov ax,'8'
  5. sub ax, '0'
  6. mov bl, '2'
  7. sub bl, '0'
  8. div bl
  9. add ax, '0'
  10. mov [res], ax
  11. mov ecx,msg
  12. mov edx, len
  13. mov ebx,1 ;文件描述 (stdout)
  14. mov eax,4 ;系统调用号 (sys_write)
  15. int 0x80 ;调用内核
  16. mov ecx,res
  17. mov edx, 1
  18. mov ebx,1 ;文件描述 (stdout)
  19. mov eax,4 ;系统调用号 (sys_write)
  20. int 0x80 ;调用内核
  21. mov eax,1 ;系统调用号 (sys_exit)
  22. int 0x80 ;调用内核
  23. section .data
  24. msg db "The result is:", 0xA,0xD
  25. len equ $- msg
  26. segment .bss
  27. res resb 1

结果如下:

  1. The result is:
  2. 4