汇编语言 寻址模式

  • 寻址模式

    大多数汇编语言指令都需要处理操作数。操作数地址提供了要处理的数据存储的位置。有些指令不需要操作数,而另一些指令则需要一个,两个或三个操作数。当一条指令需要两个操作数时,第一个操作数通常是目的地,它在寄存器或存储器位置中包含数据,第二个操作数是源。源包含要传递的数据(立即寻址)或数据的地址(在寄存器或存储器中)。通常,操作后源数据保持不变。
    寻址的三种基本模式是-
    • 寄存器寻址
    • 立即寻址
    • 内存寻址
  • 寄存器寻址

    在这种寻址模式下,寄存器包含操作数。根据指令,寄存器可以是第一个操作数,第二个操作数或两者。
    例如,
    
    MOV DX, TAX_RATE   ; 寄存器是第一个操作数
    MOV COUNT, CX      ; 寄存器是第二个操作数
    MOV EAX, EBX       ; 两个操作数都是寄存器
    
    由于寄存器之间的数据处理不涉及内存,因此可以最快地处理数据。
  • 立即寻址

    立即数操作数具有常量值或表达式。当具有两个操作数的指令使用立即寻址时,第一个操作数可以是寄存器或存储器位置,而第二个操作数是立即数。第一个操作数定义数据的长度。
    例如,
    
    BYTE_VALUE  DB  150    ; 一个字节值被定义
    WORD_VALUE  DW  300    ; 一个字值被定义
    ADD  BYTE_VALUE, 65    ; BYTE_VALUE加一个立即操作数65
    MOV  AX, 45H           ; 立即常数45H转移到AX
    
  • 直接内存寻址

    在存储器寻址模式下指定操作数时,通常需要直接访问主存储器,通常是数据段。这种寻址方式导致数据处理变慢。为了找到数据在内存中的确切位置,我们需要段起始地址(通常在DS寄存器中找到)和偏移值。此偏移值也称为有效地址。在直接寻址模式下,偏移量值直接作为指令的一部分指定,通常由变量名指示。汇编器计算偏移值并维护一个符号表,该表存储程序中使用的所有变量的偏移值。在直接存储器寻址中,一个操作数引用一个存储器位置,另一个操作数引用一个寄存器。
    例如,
    
    ADD     BYTE_VALUE, DL  ; 将寄存器添加到存储位置
    MOV     BX, WORD_VALUE  ; 将内存中的操作数添加到寄存器中
    
  • 直接偏移寻址

    此寻址模式使用算术运算符修改地址。例如,查看以下定义数据表的定义-
    
    BYTE_TABLE DB  14, 15, 22, 45      ; 字节表
    WORD_TABLE DW  134, 345, 564, 123  ; 字表
    
    以下操作将数据从内存中的表访问到寄存器中-
    
    MOV CL, BYTE_TABLE[2]   ; 获取BYTE_TABLE的第三个元素
    MOV CL, BYTE_TABLE + 2  ; 获取BYTE_TABLE的第三个元素
    MOV CX, WORD_TABLE[3]   ; 获取WORD_TABLE的第4个元素
    MOV CX, WORD_TABLE + 3  ; 获取WORD_TABLE的第4个元素
    
  • 间接内存寻址

    此寻址模式利用计算机的Segment:Offset寻址功能。通常,在方括号内编码的基址寄存器EBX,EBP(或BX,BP)和索引寄存器(DI,SI)用于内存引用。
    间接寻址通常用于包含多个元素(如数组)的变量。阵列的起始地址存储在EBX寄存器中。
    以下代码段显示了如何访问变量的不同元素。
    
    MY_TABLE TIMES 10 DW 0  ; 分配10个字(2个字节),每个字都初始化为0
    MOV EBX, [MY_TABLE]     ; EBX中MY_TABLE的有效地址
    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  寄存器, 寄存器
    MOV  寄存器, 立即数
    MOV  寄存器, 内存
    MOV  内存, 立即数
    MOV  内存, 寄存器
    
    请注意-
    • 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
    下面的程序说明了上面讨论的一些概念。它在存储器的数据部分中存储名称“Alex Mo”,然后以编程方式将其值更改为另一个名称“Feng Mo”并显示这两个名称。
    
    section .text
       global _start     ;必须声明为链接器(ld)
    _start:             ;告诉链接器入口点
            
       ;写名字“Alex Mo”
       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 'Feng'    ; Changed the name to Feng Mo
            
       ;writing the name 'Feng Mo'
       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 'Alex Mo '
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    Alex Mo Feng Mo