汇编 - 算术指令
INC 指令
INC 指令用于将操作数加一。它适用于可以位于寄存器或内存中的单个操作数。
句法
INC 指令具有以下语法 -
INC destination
操作数目标可以是 8 位、16 位或 32 位操作数。
例子
INC EBX ; Increments 32-bit register INC DL ; Increments 8-bit register INC [count] ; Increments the count variable
DEC 指令
DEC指令用于将操作数减1。它适用于可以位于寄存器或内存中的单个操作数。
句法
DEC 指令具有以下语法 -
DEC destination
操作数目标可以是 8 位、16 位或 32 位操作数。
例子
segment .data count dw 0 value db 15 segment .text inc [count] dec [value] mov ebx, count inc word [ebx] mov esi, value dec byte [esi]
ADD 和 SUB 指令
ADD和SUB指令用于执行字节、字和双字大小的二进制数据的简单加法/减法,即分别用于8位、16位或32位操作数的加或减。
句法
ADD 和 SUB 指令具有以下语法 -
ADD/SUB destination, source
ADD/SUB 指令可以发生在 -
- 注册即可注册
- 注册内存
- 注册到内存
- 寄存器到常量数据
- 内存到常量数据
然而,与其他指令一样,无法使用 ADD/SUB 指令进行内存到内存操作。ADD 或 SUB 操作设置或清除溢出和进位标志。
例子
下面的示例将询问用户两个数字,分别将数字存储在 EAX 和 EBX 寄存器中,将值相加,将结果存储在内存位置“ res ”中,最后显示结果。
SYS_EXIT equ 1 SYS_READ equ 3 SYS_WRITE equ 4 STDIN equ 0 STDOUT equ 1 segment .data msg1 db "Enter a digit ", 0xA,0xD len1 equ $- msg1 msg2 db "Please enter a second digit", 0xA,0xD len2 equ $- msg2 msg3 db "The sum is: " len3 equ $- msg3 segment .bss num1 resb 2 num2 resb 2 res resb 1 section .text global _start ;must be declared for using gcc _start: ;tell linker entry point mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, msg1 mov edx, len1 int 0x80 mov eax, SYS_READ mov ebx, STDIN mov ecx, num1 mov edx, 2 int 0x80 mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, msg2 mov edx, len2 int 0x80 mov eax, SYS_READ mov ebx, STDIN mov ecx, num2 mov edx, 2 int 0x80 mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, msg3 mov edx, len3 int 0x80 ; moving the first number to eax register and second number to ebx ; and subtracting ascii '0' to convert it into a decimal number mov eax, [num1] sub eax, '0' mov ebx, [num2] sub ebx, '0' ; add eax and ebx add eax, ebx ; add '0' to to convert the sum from decimal to ASCII add eax, '0' ; storing the sum in memory location res mov [res], eax ; print the sum mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, res mov edx, 1 int 0x80 exit: mov eax, SYS_EXIT xor ebx, ebx int 0x80
当上面的代码被编译并执行时,它会产生以下结果 -
Enter a digit: 3 Please enter a second digit: 4 The sum is: 7
带有硬编码变量的程序 -
section .text global _start ;must be declared for using gcc _start: ;tell linker entry point mov eax,'3' sub eax, '0' mov ebx, '4' sub ebx, '0' add eax, ebx add eax, '0' mov [sum], eax mov ecx,msg mov edx, len mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov ecx,sum mov edx, 1 mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel section .data msg db "The sum is:", 0xA,0xD len equ $ - msg segment .bss sum resb 1
当上面的代码被编译并执行时,它会产生以下结果 -
The sum is: 7
MUL/IMUL 指令
有两条指令用于将二进制数据相乘。MUL(乘法)指令处理无符号数据,IMUL(整数乘法)指令处理有符号数据。两条指令都会影响进位和溢出标志。
句法
MUL/IMUL 指令的语法如下 -
MUL/IMUL multiplier
在这两种情况下,被乘数都将位于累加器中,具体取决于被乘数和乘数的大小,并且生成的乘积也取决于操作数的大小存储在两个寄存器中。以下部分解释了三种不SymPy况下的 MUL 指令 -
先生。 | 应用场景 |
---|---|
1 | 当两个字节相乘时 - 被乘数在AL寄存器中,乘数是内存中或另一个寄存器中的一个字节。该产品在 AX 中。乘积的高 8 位存储在 AH 中,低 8 位存储在 AL 中。 |
2 | 当两个单字值相乘时 - 被乘数应该在AX寄存器中,乘数是内存或另一个寄存器中的一个字。例如,对于像 MUL DX 这样的指令,必须将乘数存储在 DX 中,将被乘数存储在 AX 中。 生成的结果是一个双字,需要两个寄存器。高位(最左边)部分存储在 DX 中,低位(最右边)部分存储在 AX 中。 |
3 | 当两个双字值相乘时 - 当两个双字值相乘时,被乘数应位于 EAX 中,乘数是存储在内存或另一个寄存器中的双字值。生成的乘积存储在 EDX:EAX 寄存器中,即高位 32 位存储在 EDX 寄存器中,低位 32 位存储在 EAX 寄存器中。 |
例子
MOV AL, 10 MOV DL, 25 MUL DL ... MOV DL, 0FFH ; DL= -1 MOV AL, 0BEH ; AL = -66 IMUL DL
例子
以下示例将 3 乘以 2,并显示结果 -
section .text global _start ;must be declared for using gcc _start: ;tell linker entry point mov al,'3' sub al, '0' mov bl, '2' sub bl, '0' mul bl add al, '0' mov [res], al mov ecx,msg mov edx, len mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov ecx,res mov edx, 1 mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel section .data msg db "The result is:", 0xA,0xD len equ $- msg segment .bss res resb 1
当上面的代码被编译并执行时,它会产生以下结果 -
The result is: 6
DIV/IDIV 指令
除法运算生成两个元素 -商和余数。在乘法的情况下,不会发生溢出,因为使用双倍长度寄存器来保存乘积。然而,在除法的情况下,可能会发生溢出。如果发生溢出,处理器会生成中断。
DIV(除法)指令用于无符号数据,IDIV(整数除法)指令用于有符号数据。
句法
DIV/IDIV 指令的格式 -
DIV/IDIV divisor
股息位于累加器中。这两个指令都可以使用 8 位、16 位或 32 位操作数。该操作影响所有六个状态标志。以下部分解释了具有不同操作数大小的除法的三种情况 -
先生。 | 应用场景 |
---|---|
1 | 当除数为 1 字节时 - 假定被除数位于 AX 寄存器(16 位)中。除法后,商存入 AL 寄存器,余数存入 AH 寄存器。 |
2 | 当除数为 1 个字时 - 假设被除数为 32 位长,位于 DX:AX 寄存器中。高16位在DX中,低16位在AX中。除法后,16 位商进入 AX 寄存器,16 位余数进入 DX 寄存器。 |
3 | 当除数为双字时 - 假设被除数为 64 位长并位于 EDX:EAX 寄存器中。高阶 32 位在 EDX 中,低阶 32 位在 EAX 中。除法后,32 位商进入 EAX 寄存器,32 位余数进入 EDX 寄存器。 |
例子
以下示例将 8 除以 2。被除数 8存储在16 位 AX 寄存器中,除数 2存储在8 位 BL 寄存器中。
section .text global _start ;must be declared for using gcc _start: ;tell linker entry point mov ax,'8' sub ax, '0' mov bl, '2' sub bl, '0' div bl add ax, '0' mov [res], ax mov ecx,msg mov edx, len mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov ecx,res mov edx, 1 mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel section .data msg db "The result is:", 0xA,0xD len equ $- msg segment .bss res resb 1
当上面的代码被编译并执行时,它会产生以下结果 -
The result is: 4