Assembly 汇编程序-间接存储器寻址
我是个汇编新手,以前做过一些Java/C。。所以这就像飞行后学会爬行一样 我现在正在学习“教程的要点”,因为它看起来非常友好 我遇到了以下代码:Assembly 汇编程序-间接存储器寻址,assembly,x86,nasm,addressing-mode,Assembly,X86,Nasm,Addressing Mode,我是个汇编新手,以前做过一些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]
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
我想提前感谢大家。
MOV EBX,[MY_TABLE]
将从地址MY_TABLE
处的内存中读取4个字节(即“数组”的前两个元素)
根据评论,我猜作者打算使用leaebx[MY_TABLE]
LEA
是“加载有效地址”的缩写,它基本上是带有内存参考变量的指令MOV
的前半部分。它将计算最终地址,从那里,这样的MOV
将加载数据,但不是联系内存芯片,加载数据,而是将地址本身加载到目标寄存器。同样,在NASM中,也可以通过MO实现V ebx,MY_表
或在MASM/TASM中通过MOV ebx,偏移MY_表
是的,它就像指向表中第一个值的指针,但要充分理解程序集的原始性,您应该记住,它就像指向表中第一个字节的指针,因为程序集中的指针没有任何类型,在32b保护模式下,具有平面内存模型(Win32,linux32)地址是uint32\u t
,内存可以通过字节寻址,因此每个这样的数字都指向内存中的某个地方(物理RAM芯片/设备I/O映射的地方,或者指向空的无效区域)。这将简单的平面内存32b模式限制为4GB内存空间(x86允许在32b模式下使用更复杂的内存映射方案,这允许寻址超过4GB的内存地址空间,但当然不能使用单个32b寄存器地址)
2) 由于指针指向字节,而您的表是从字开始的,每个字的大小为2字节。表的第一个元素位于偏移量0
,但也占据偏移量1
的下一个字节。第二个值的第一个字节(C中的表[1])位于偏移量2
。因此add ebx,2
用于获取第二个值的地址。add ebx,1
将使您指向第一个my_表[0]
值的中间
尽量不要像它们的C对应物那样引用这些东西,数组本身有点低级,所以它通常是匹配的,但是任何更高级的C构造都会更加混淆它。C数组已经对您隐藏了指针算法,使用元素类型为您计算正确的地址。在汇编中,这不会发生
其他变体32b x86如何处理类C值my_表[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)。因此,在这种情况下(内存引用与立即数)的正确/nice样式是显式指定参数大小,如:
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位寄存器/值而产生错误的结果)。MOV EBX,[MY_TABLE]
将从地址MY_TABLE
处的内存中读取4个字节(即“数组”的前两个元素)
根据评论,我猜作者打算使用leaebx[MY_TABLE]
LEA
是“加载有效地址”的缩写,它基本上是带有内存参考变量的指令MOV
的前半部分。它将计算最终地址,从那里,这样的MOV
将加载数据,但不是联系内存芯片,加载数据,而是将地址本身加载到目标寄存器。同样,在NASM中,也可以通过MO实现V ebx,MY_表
或在MASM/TASM中通过MOV ebx,偏移MY_表
是的,它就像指向表中第一个值的指针,但要充分理解程序集的原始性,您应该记住,它就像指向表中第一个字节的指针,因为程序集中的指针没有任何类型,在32b保护模式下,具有平面内存模型(Win32,linux32)地址是uint32\u t
,内存可以通过字节寻址,因此每个这样的数字都指向内存中的某个地方(物理RAM芯片/设备I/O映射的地方,或者指向空的无效区域)。这将简单的平面内存32b模式限制为4GB内存空间(x86允许在32b模式下使用更复杂的内存映射方案,这允许寻址超过4GB的内存地址空间,但当然不能使用单个32b寄存器地址)
2) 由于指针指向字节,而您的表是从字开始的,每个字的大小为2字节。表的第一个元素位于偏移量0
,但也占据偏移量1
的下一个字节。第一个字节