Assembly 汇编程序-间接存储器寻址

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]

我是个汇编新手,以前做过一些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_表的有效地址分配给EBX,有点像指向表的第一个值的指针?(我知道这和C不可比……但我总得明白:))

  • 它说ADD EBX,2(这意味着将EBX寄存器加上2,但是当引用到下一行时,它不应该引用到[2]位置吗?再次..像C的数组一样思考这个问题

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

    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
    的下一个字节。第一个字节