我是大会的新手,之前做了一些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
将MY_TABLE的有效地址分配给EBX,有点像指针到表格的第一个值? (我知道它不能与 C 相提并论......但我必须以某种方式理解它:))
它说ADD EBX,2(这意味着 inc EBX寄存器为2,但是当下一行被提到它时,不应该向[2]提供再次......把它想象成 C 的阵列。
希望这个问题在现场。 我想提前感谢大家。
答案 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],ax
,ax
的大小将此类操作的数据宽度定义为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变体的寄存器(上例中的eax
和ecx
)进行所有计算,并仅使用部分ax
和cl
计算结束以存储正确的结果(当然,由于32位寄存器/值的使用,确保计算本身不会产生错误的结果)。