汇编程序 - 间接内存寻址

时间:2017-03-04 16:25:22

标签: assembly x86 nasm low-level-code

我是大会的新手,之前做了一些Java / C ..所以它就像在飞行后学会爬行一样。

我目前正在学习“教程指南”。因为它似乎非常友好。

我遇到过这段代码:

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
  1. 将MY_TABLE的有效地址分配给EBX,有点像指针到表格的第一个值? (我知道它不能与 C 相提并论......但我必须以某种方式理解它:))

  2. 它说ADD EBX,2(这意味着 inc EBX寄存器为2,但是当下一行被提到它时,不应该向[2]提供再次......把它想象成 C 的阵列。

  3. 希望这个问题在现场。 我想提前感谢大家。

1 个答案:

答案 0 :(得分:2)

MOV EBX, [MY_TABLE]将从地址MY_TABLE的内存中读取4个字节(即"数组"的前两个元素)。

根据评论,我猜猜作者打算使用LEA EBX, [MY_TABLE]

LEA是"加载有效地址"的缩写,它基本上是具有内存引用变体的指令MOV的前半部分。它将计算最终地址,这样MOV将加载数据,但不是联系内存芯片,而是加载数据,地址本身被加载到目标寄存器中。同样可以通过MOV ebx,MY_TABLE在MASM中实现,也可以通过MOV ebx,OFFSET MY_TABLE在MASM / TASM中实现。

所以是的,它就像指向表中第一个值的指针,但要完全理解汇编的原始性,你应该记住,它就像指向表中第一个BYTE的指针,作为指针在程序集中没有任何类型,在32b保护模式下,平面内存模型(Win32,linux32)地址为uint32_t,内存可通过字节寻址,因此每个这样的数字都指向内存(在哪里物理RAM芯片/设备I / O被映射,或者进入空的无效区域)。这将简单的平面存储器32b模式限制为4GiB的存储空间(x86允许在32b模式下实现更复杂的存储器映射方案,这允许寻址超过4GiB的存储器地址空间,但不能使用单个32b寄存器地址疗程)。

2)因为该指针指向BYTES,并且您的表来自WORDS,所以每个字的大小为2个字节。该表的第一个元素位于偏移量0,但在偏移量1处也占据了下一个字节。第二个值的第一个字节(C中的表[1])位于偏移2。因此add ebx,2用于获取第二个值的地址。 add ebx,1会让您指向第一个my_table[0]值的中间位置。

尽量不要像C语言那样引用这些东西,数组本身也是低级别的,所以它经常匹配,但任何更高级别的C构造通常只会让它更加混乱。 C数组已经隐藏了指针算术,使用元素类型为您计算正确的地址。在没有发生的装配中。

其他变体32b x86如何处理类似C的值my_table[1]

lea  ebx,[my_table]
mov  esi,1
mov  ax,[ebx + esi*2]  ; by index register scaled by 2

lea  ebx,[my_table]
mov  esi,2
mov  ax,[ebx + esi]    ; by offset

lea  ebx,[my_table]
mov  ax,[ebx + 2]      ; by immediate offset

mov  ax,[my_table + 2] ; by absolute address

编辑:现在我终于注意到你实际使用ebx做了什么。我认为MOV [EBX], 110"马虎"编程风格,因为从这个mov的两个参数都不清楚数据大小是什么。

如果执行mov [ebx],axax的大小将此类操作的数据宽度定义为16位,但110可以是8,16或32位立即(甚至是在64b模式下64b)。因此,在这种情况下(内存引用vs立即)的正确/好的样式是显式指定参数大小,如:

mov [ebx], word 110   ; C-like: ((short *)my_table)[some_index] = (short)110;

出于性能原因,在现代x86上最好避免使用16位寄存器,因此当处理短路或字节数组时,最好通过将它们扩展为完整的32位值来加载它们:

movzx eax,word [ebx] ; to extend word value [ebx] with zero bits
movsx ecx,byte [esi] ; to sign-extend value [ebx]
    ; the top most (sign) bit of original value is copied up to fill upper ecx

然后,您可以使用32b变体的寄存器(上例中的eaxecx)进行所有计算,并仅使用部分axcl计算结束以存储正确的结果(当然,由于32位寄存器/值的使用,确保计算本身不会产生错误的结果)。