汇编 - 算术指令


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 中。

算术1

2

当两个单字值相乘时 -

被乘数应该在AX寄存器中,乘数是内存或另一个寄存器中的一个字。例如,对于像 MUL DX 这样的指令,必须将乘数存储在 DX 中,将被乘数存储在 AX 中。

生成的结果是一个双字,需要两个寄存器。高位(最左边)部分存储在 DX 中,低位(最右边)部分存储在 AX 中。

算术2

3

当两个双字值相乘时 -

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

算术3

例子

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 寄存器。

算术4

2

当除数为 1 个字时 -

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

算术5

3

当除数为双字时 -

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

算术6

例子

以下示例将 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