汇编语言 寻址模式

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

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

寻址的三种基本模式是:

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

寄存器寻址

在这种寻址模式下,寄存器包含操作数。根据指令,寄存器可以是第一个操作数,第二个操作数或两者。

例如,

  1. MOV DX, TAX_RATE ; 寄存器是第一个操作数
  2. MOV COUNT, CX ; 寄存器是第二个操作数
  3. MOV EAX, EBX ; 两个操作数都是寄存器

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


立即寻址

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

例如,

  1. BYTE_VALUE DB 150 ; 一个字节值被定义
  2. WORD_VALUE DW 300 ; 一个字值被定义
  3. ADD BYTE_VALUE, 65 ; BYTE_VALUE 加一个立即操作数 65
  4. MOV AX, 45H ; 立即常数 45H 转移到 AX

直接内存寻址

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

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

例如,

  1. ADDBYTE_VALUE, DL; 将寄存器添加到存储位置
  2. MOVBX, WORD_VALUE; 将内存中的操作数添加到寄存器中

直接偏移寻址

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

  1. BYTE_TABLE DB 14, 15, 22, 45 ; 字节表
  2. WORD_TABLE DW 134, 345, 564, 123 ; 字表

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

  1. MOV CL, BYTE_TABLE[2]; 获取 BYTE_TABLE 的第 3 个元素
  2. MOV CL, BYTE_TABLE + 2; 获取 BYTE_TABLE 的第 3 个元素
  3. MOV CX, WORD_TABLE[3]; 获取 WORD_TABLE 的第 4 个元素
  4. MOV CX, WORD_TABLE + 3; 获取 WORD_TABLE 的第 4 个元素

间接内存寻址

此寻址模式利用计算机的 Segment:Offset 寻址功能。通常,在方括号内编码的基址寄存器 EBXEBP(或 BXBP)和索引寄存器(DISI)用于内存引用。

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

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

  1. MY_TABLE TIMES 10 DW 0 ; 分配 10 个字(2 个字节),每个字都初始化为 0
  2. MOV EBX, [MY_TABLE] ; EBXMY_TABLE的有效地址
  3. MOV [EBX], 110 ; MY_TABLE[0] = 110
  4. ADD EBX, 2 ; EBX = EBX +2
  5. MOV [EBX], 123 ; MY_TABLE[1] = 123

MOV 指令

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

语法

MOV 指令的语法为:

  1. MOV destination, source

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

  1. MOV register, register
  2. MOV register, immediate
  3. MOV memory, immediate
  4. MOV register, memory
  5. MOV memory, register

注意

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

MOV 指令有时会引起歧义。例如,

  1. MOV EBX, [MY_TABLE] ; Effective Address of MY_TABLE in EBX
  2. MOV [EBX], 110 ; MY_TABLE[0] = 110

目前尚不清楚是要移动等于 110 的字节等效值还是等效于字的字符。在这种情况下,使用 类型说明符 是明智的。

下表是一些常见的类型说明符:

类型说明符寻址字节
BYTE1
WORD2
DWORD4
QWORD8
TBYTE10
实例

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

  1. section .text
  2. global _start ;必须声明为链接器(ld
  3. _start: ;告诉链接器入口点
  4. ;写名字“Alex Mo
  5. mov edx,9 ;消息长度
  6. mov ecx, name ;消息内容
  7. mov ebx,1 ;文件描述 (stdout)
  8. mov eax,4 ;系统调用号 (sys_write)
  9. int 0x80 ;调用内核
  10. mov [name], dword 'Feng' ; 将名称修改为 Feng Mo
  11. ;writing the name 'Feng Mo'
  12. mov edx,8 ;消息长度
  13. mov ecx,name ;消息内容
  14. mov ebx,1 ;文件描述 (stdout)
  15. mov eax,4 ;系统调用号 (sys_write)
  16. int 0x80 ;调用内核
  17. mov eax,1 ;系统调用号 (sys_exit)
  18. int 0x80 ;调用内核
  19. section .data
  20. name db 'Alex Mo '

结果如下:

  1. Alex Mo Feng Mo