汇编语言简易教程(8):寻址模式

汇编语言简易教程(8):寻址模式

寻址模式是使用正在访问(读取或写入)的数据项的地址来访问内存中的值的受支持方法。这可能包括变量的名称或数组中的位置。

基本的寻址模式包含:

  1. 寄存器
  2. 立即数
  3. 内存

寻址注意事项

使用[]

需要注意: 访问内存的唯一方法是使用方括号([]'s)。省略括号将不会访问内存,而是获取项目的地址.

image

如上所示, 由于省略括号不是错误,因此汇编器不会生成错误消息或警告

当访问内存时,很多情况下操作数的大小是明确的。例如,指令mov eax, [rbx]

从内存中移动一个双字。然而,对于某些指令来说,大小可能不明确, 例如 inc [rbx]​是不明确的,因为不清楚正在访问的内存是字节、字还是双字。在这种情况下,必须使用字节、字或双字、四字大小限定符指定操作数大小. 所以我们需要使用

inc		byte [rbx]
inc		word [rbx]
inc		dword [rbx]

在这种情况下,必须使用字节、字或双字、四字大小限定符指定操作数大小.

寄存器寻址

寄存器模式寻址指的是操作对象是一个寄存器(eax, ebx, etc.)

例如: mov eax, ebx​, 其中 eax​, ebx​都是寄存器模式寻址.

立即数寻址

寄存器模式寻址指的是操作对象是一个立即数.

例如: mov eax, 123​, 其中 eax​是寄存器模式寻址, 123是立即数寻址

内存寻址

内存寻址意味着操作数是内存中的一个位置(通过地址访问)。这称之为间接引用 或者 解引用.

内存模式寻址的最基本形式已在前一章中广泛使用。

例如: mov rax, qword [qNum]

将访问变量 qNum 的内存位置并检索存储在那里的值。

这要求 CPU 在完成操作之前等待直到检索到该值,因此可能比使用立即值的类似操作花费稍长的时间来完成。

访问数组时,需要更通用的方法。具体来说,地址可以放置在寄存器中,并使用寄存器(而不是变量名称)执行间接寻址

举例

lst dd 101, 103, 105, 107

其内存分布如下图:

image

第一个元素的访问可以使用: mov eax, dword [lst]

除此之外, 还可以通过: mov rbx, lst mov eax, dword [rbx]

在此示例中,列表的起始地址或基地址被放置在 rbx(第一行)中,然后访问该地址处的值并将其放置在 rax 寄存器(第二行)中。这使我们可以轻松访问数组中的其他元素

回想一下,内存是“字节可寻址的”,这意味着每个地址都是一个字节的信息。双字变量为 32 位或 4 个字节,因此每个数组元素使用 4 个字节的内存。这样,下一个元素(103)就是起始地址(lst)加4,下一个元素(105)就是起始地址(lst)8

对于每个连续元素,将偏移量增加 4。字节列表将增加 1,字列表将增加 2,双字列表将增加 4,四字列表将增加 8。

偏移量是添加到基地址的量。索引是高级语言中使用的数组元素号。

有多种方法可以访问数组元素。一种是使用基地址并添加位移。例如,给定初始化:

mov		rbx, lst
mov		rsi, 8

以下每条指令都访问第三个元素(上面列表中的 105)

  1. mov eax, dword [lst + 8]
  2. mov eax, dword [rbx + 8]
  3. mov eax, dword [lst + rsi]

在每种情况下,都会访问起始地址加 8,并将值 105 放入 eax 寄存器中。添加位移并访问内存位置,同时不更改任何源操作数寄存器(rbx、rsi)。具体使用什么方法由程序员决定

位移计算

此外,位移可以用更复杂的方式计算

[ baseAddr + (indexReg * scaleValue ) + displacement ]

  1. 其中baseAddr是寄存器或变量名。
  2. indexReg 必须是一个寄存器。
  3. ThescaleValue 是立即值 1, 2, 4, 8(1 是合法的,但没有用)。
  4. displacement ​必须是立即值。
  5. 结果代表一个64位地址

元素可以任意组合使用,但必须合法并产生有效地址

一些示例:

image

由于地址始终是 qword(在 64 位架构上),因此使用 64 位寄存器进行内存模式寻址(即使在访问双字值时也是如此)。这使得寄存器的使用更像是数组索引(来自高级语言)。

例如,内存操作数[lst+rsi*4]​类似于高级语言中的 lst[rsi]​。 rsi 寄存器乘以数据大小(本例中为 4,因为每个元素都是 4 字节)

示例程序

计算列表之和

section .data; -----
;  Define constants
EXIT_SUCCESS    equ    0; successful operation
SYS_exit        equ    60; call code for terminate
; -----
; Define Data.
section .data
    lst dd  1002, 1004, 1006, 1008, 10010
    len dd  5
    sum dd  0
; ********************************************************
section .text
global_start
_start:
; -----
; Summation loop.
    mov ecx, dword [len]; get length value
    mov rsi, 0; index=0

sumLoop:
    mov eax, dword [lst+(rsi*4)]; get lst[rsi]
    add dword [sum], eax; update sum
    inc rsi; next item
    loop    sumLoop
    ; -----
    ;  Done, terminate program.
last:
    mov rax, SYS_exit; call code for exit
    mov rdi, EXIT_SUCCESS; exit with successsyscall

[ ]内的 () 不是必需的,添加只是为了清楚起见。因此,[lst+(rsi*4)] [lst+rsi*4]​ 完全相同。

posted @ 2024-04-12 12:00  pDJJq  阅读(22)  评论(0编辑  收藏  举报