汇编 - 寻址模式
大多数汇编语言指令都需要处理操作数。 操作数地址提供了存储要处理的数据的位置。 一些指令不需要操作数,而另一些指令可能需要一个、两个或三个操作数。
当一条指令需要两个操作数时,第一个操作数通常是目标,其中包含寄存器或内存位置中的数据,第二个操作数是源。 源包含要传送的数据(立即寻址)或数据的地址(在寄存器或内存中)。 一般情况下,操作后源数据不会发生变化。
三种基本的寻址模式是 −
- 寄存器寻址
- 立即寻址
- 内存寻址
寄存器寻址
在此寻址模式下,寄存器包含操作数。 根据指令的不同,寄存器可能是第一个操作数、第二个操作数或两者。
例如,
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] ; Effective Address of MY_TABLE in EBX 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