汇编 - 寻址模式

大多数汇编语言指令都需要操作数才能处理。操作数地址提供要处理的数据存储的位置。有些指令不需要操作数,而其他一些指令可能需要一个、两个或三个操作数。

当一条指令需要两个操作数时,第一个操作数通常是目标,其中包含寄存器或内存位置中的数据,第二个操作数是源。源包含要传递的数据(立即寻址)或数据的地址(在寄存器或内存中)。通常,操作后源数据保持不变。

三种基本寻址模式是 −

  • 寄存器寻址
  • 立即寻址
  • 内存寻址

寄存器寻址

在此寻址模式下,寄存器包含操作数。根据指令,寄存器可能是第一个操作数、第二个操作数或两者兼而有之。

例如,

MOV DX, TAX_RATE   ; Register in first operand
MOV COUNT, CX	   ; Register in second operand
MOV EAX, EBX	   ; Both the operands are in registers

由于寄存器之间的数据处理不涉及内存,因此可以提供最快的数据处理速度。

立即寻址

立即操作数具有常数值或表达式。当具有两个操作数的指令使用立即寻址时,第一个操作数可能是寄存器或内存位置,第二个操作数是立即常数。第一个操作数定义数据的长度。

例如,

BYTE_VALUE  DB  150    ; A byte value is defined
WORD_VALUE  DW  300    ; A word value is defined
ADD  BYTE_VALUE, 65    ; An immediate operand 65 is added
MOV  AX, 45H           ; Immediate constant 45H is transferred to AX

直接内存寻址

在内存寻址模式下指定操作数时,需要直接访问主内存(通常是数据段)。这种寻址方式会导致数据处理速度变慢。要找到数据在内存中的确切位置,我们需要段起始地址(通常位于 DS 寄存器中)和偏移值。此偏移值也称为有效地址

在直接寻址模式下,偏移值直接作为指令的一部分指定,通常由变量名表示。汇编程序计算偏移值并维护一个符号表,该表存储程序中使用的所有变量的偏移值。

在直接内存寻址中,其中一个操作数引用内存位置,另一个操作数引用寄存器。

例如,

ADD	BYTE_VALUE, DL	; Adds the register in the memory location
MOV	BX, WORD_VALUE	; Operand from the memory is added to register

直接偏移寻址

此寻址模式使用算术运算符来修改地址。例如,查看以下定义数据表 − 的定义

BYTE_TABLE DB  14, 15, 22, 45      ; Tables of bytes
WORD_TABLE DW  134, 345, 564, 123  ; Tables of words

以下操作将内存表中的数据访问到寄存器中 −

MOV CL, BYTE_TABLE[2]	; Gets the 3rd element of the BYTE_TABLE
MOV CL, BYTE_TABLE + 2	; Gets the 3rd element of the BYTE_TABLE
MOV CX, WORD_TABLE[3]	; Gets the 4th element of the WORD_TABLE
MOV CX, WORD_TABLE + 3	; Gets the 4th element of the WORD_TABLE

间接内存寻址

此寻址模式利用了计算机的段:偏移寻址能力。通常,基址寄存器 EBX、EBP(或 BX、BP)和索引寄存器(DI、SI)用于此目的,这些寄存器用方括号括起来用于内存引用。

间接寻址通常用于包含多个元素的变量,例如数组。数组的起始地址存储在 EBX 寄存器中。

以下代码片段显示了如何访问变量的不同元素。

MY_TABLE TIMES 10 DW 0  ; Allocates 10 words (2 bytes) each initialized to 0
MOV EBX, [MY_TABLE]     ; Effective Address of MY_TABLE in EBX
MOV [EBX], 110          ; MY_TABLE[0] = 110
ADD EBX, 2              ; EBX = EBX +2
MOV [EBX], 123          ; MY_TABLE[1] = 123

MOV 指令

我们已经使用了 MOV 指令,该指令用于将数据从一个存储空间移动到另一个存储空间。 MOV 指令需要两个操作数。

语法

MOV 指令的语法是 −

MOV  destination, source

MOV 指令可能有以下五种形式之一 −

MOV  register, register
MOV  register, immediate
MOV  memory, immediate
MOV  register, memory
MOV  memory, register

请注意 −

  • MOV 操作中的两个操作数应具有相同的大小
  • 源操作数的值保持不变

MOV 指令有时会引起歧义。例如,查看语句 −

MOV EBX, [MY_TABLE] ; EBX 中 MY_TABLE 的有效地址
MOV [EBX], 110 ; MY_TABLE[0] = 110

不清楚您是否要移动数字 110 的字节等价物或字等价物。在这种情况下,最好使用类型说明符

下表显示了一些常见的类型说明符 −

类型说明符 字节寻址
BYTE 1
WORD 2
DWORD 4
QWORD 8
TBYTE 10

示例

以下程序说明了上面讨论的一些概念。它将名称"Zara Ali"存储在内存的数据部分,然后以编程方式将其值更改为另一个名称"Nuha Ali",并显示这两个名称。

section	.text
   global _start     ;must be declared for linker (ld)
_start:             ;tell linker entry point
	
   ;writing the name 'Zara Ali'
   mov	edx,9       ;message length
   mov	ecx, name   ;message to write
   mov	ebx,1       ;file descriptor (stdout)
   mov	eax,4       ;system call number (sys_write)
   int	0x80        ;call kernel
	
   mov	[name],  dword 'Nuha'    ; Changed the name to Nuha Ali
	
   ;writing the name 'Nuha Ali'
   mov	edx,8       ;message length
   mov	ecx,name    ;message to write
   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
name db 'Zara Ali '

当上述代码被编译并执行时,它会产生以下结果−

Zara Ali Nuha Ali