汇编语言简易教程(8):寻址模式
汇编语言简易教程(8):寻址模式
寻址模式是使用正在访问(读取或写入)的数据项的地址来访问内存中的值的受支持方法。这可能包括变量的名称或数组中的位置。
基本的寻址模式包含:
- 寄存器
- 立即数
- 内存
寻址注意事项
使用[]
需要注意: 访问内存的唯一方法是使用方括号([]'s)。省略括号将不会访问内存,而是获取项目的地址.
如上所示, 由于省略括号不是错误,因此汇编器不会生成错误消息或警告
当访问内存时,很多情况下操作数的大小是明确的。例如,指令
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
其内存分布如下图:
第一个元素的访问可以使用:
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)
- mov eax, dword [lst + 8]
- mov eax, dword [rbx + 8]
- mov eax, dword [lst + rsi]
在每种情况下,都会访问起始地址加 8,并将值 105 放入 eax 寄存器中。添加位移并访问内存位置,同时不更改任何源操作数寄存器(rbx、rsi)。具体使用什么方法由程序员决定
位移计算
此外,位移可以用更复杂的方式计算
[ baseAddr + (indexReg * scaleValue ) + displacement ]
- 其中baseAddr是寄存器或变量名。
- indexReg 必须是一个寄存器。
- ThescaleValue 是立即值 1, 2, 4, 8(1 是合法的,但没有用)。
-
displacement
必须是立即值。- 结果代表一个64位地址
元素可以任意组合使用,但必须合法并产生有效地址
一些示例:
由于地址始终是 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]
完全相同。