【问题标题】:Arrays in MASM Assembly (very confused beginner)MASM Assembly 中的数组(非常困惑的初学者)
【发布时间】:2014-11-25 19:04:29
【问题描述】:

我有一个非常基本的问题: 你如何在汇编中填充数组?在高级编程语言中,您可以使用 for 循环为每个索引设置一个值,但我不确定如何完成相同的组装。我知道这是错误的,但这就是我所拥有的:

ExitProcess PROTO
.data
warray WORD 1,2,3,4
darray DWORD ?

.code
main PROC
mov edi, OFFSET warray
mov esi, OFFSET darray
mov ecx, LENGTHOF warray


L1:
mov ax, [edi]          ;i want to move a number from warray to ax
movzx esi,ax           ;i want to move that number into darray...
add edi, TYPE warray   ;this points to the next number?

    loop L1 

    call ExitProcess
main ENDP
END

每次循环运行时,ax 都会被数组索引的值覆盖,对吧?相反,我如何使用 warray 中的数组元素填充 darray?任何帮助将不胜感激...我很困惑。

【问题讨论】:

    标签: arrays visual-studio loops assembly


    【解决方案1】:

    您可能不“应该知道”这一点,但无论如何,有一条指令和一条指令前缀(早在何时)就是为了做到这一点。

    看看这里的微软页面:HERE (click on it)

    在该页面上向下滚动,直到找到该短语...

    "...这些指令是 x86 的 CISC 遗产的残余,在最近的处理器中实际上比写出的等效指令慢。..."

    你所做的是……

    • 将数组的大小放入Ecx
    • 指向Edi 的起点
    • 使用适当的字符串指令来填充它

    语法(Masm/Tasm/etc.)可能看起来像这样......

     Mov       Ecx, The_Length_Of_The_Array            ;Figure this out somehow
     Lea       Edi, The_Target_You_Want_To_Fill        ;Define this somewhere
    

    现在,如果您想从一个地方复制到另一个地方,请执行此操作...

     Lea       Esi, The_Source_You_Want_To_Copy         ;Whatever, define it
     Cld                                                ;This is the direction flag, make it inc
     Rep       Movsb                                    ;Movsb means move byte for byte
    

    现在,如果您想在数组中的每个字节中填充相同的值,请执行此操作...

     Mov       AL, The_Value_You_Want_To_Stuff          ;Define this to your liking
     Cld                                                ;This is the direction flag, make it inc
     Rep       Stosb                                    ;Stosb means store AL into each byte
    

    同样,由于其他人会解释的原因,这些说明不再酷了,如果你使用它们,你会得到一些东西。

    还有用于比较的字符串指令,“扫描”、“加载”等。它们曾经非常有用(现在仍然有用,但今天的“现代”帮派不会承认)特别是添加了Rep 前缀。

    如果这有帮助,但您需要更多详细信息,请随时询问。

    【讨论】:

    • 它们并没有你想象的那么糟糕。它们过去实施得非常糟糕,但在较新的架构 (SNB+) 上,它们实际上非常快。它们还不能完全替代宏指令,但在某些情况下它们的性能优于手写汇编。
    • @drivingon9 完全同意你的看法。以正确的方式编写它们(我想这是一种荒谬的文字游戏),它们将完成其他指令很少能做到的事情。现在看来,字符串指令通常被标记为不酷。愚蠢的 ?确实 !但是,这就是今天的生活。
    • 丢失了编辑窗口时间。 @drivingon9 加上您的评论,我编辑了我的答案。
    • repne scasb (memchr) 和 repe cmpsb (memcmp) 仅对代码大小有用,而不是性能。快速字符串和 ERMSB 微码仅加速 rep stosrep movs,而不是条件代表搜索指令。它们非常慢,例如在现代 x86(例如 Skylake)上 repe cmpsb 每次比较 2 个周期,因此对于大型阵列(甚至 AVX2)来说,比良好的 SSE2 pcmpeqb 慢大约 32 倍。对于短数组也不是很好;他们有一些启动开销。 lodsdlodsq 没有 rep 偶尔值得在 Haswell 及更高版本上使用(只有 2 微指令,与 mov-load + add 相同),但其他更差
    【解决方案2】:

    填充数组的方法不止一种,而且您的代码几乎可以正常工作。一种方法是在间接地址中使用计数器,这样您就不必在每个循环中修改目标和源数组指针:

    ExitProcess PROTO
    .data
        warray WORD 1,2,3,4
        darray DWORD 4 dup (?) ; 4 elements
    
    .code
    main PROC
        mov edi, OFFSET warray
        mov esi, OFFSET darray
        xor ecx, ecx                ; clear counter
    L1:
        mov ax, [edi + ecx * 2]     ; get number from warray
        movzx [esi + ecx * 4], ax   ; move number to darray
        inc ecx                     ; increment counter
        cmp ecx, LENGTHOF warray
        jne L1 
    
        call ExitProcess
    main ENDP
    END
    

    当然,可以修改此代码以向后填充数组,以节省几个字节,就像您在原始代码中可能打算做的那样。这是另一种具有更紧凑循环的方式:

    ExitProcess PROTO
    .data
        warray WORD 1,2,3,4
        darray DWORD 4 dup (?) ; 4 elements
    
    .code
    main PROC
        mov edi, OFFSET warray
        mov esi, OFFSET darray
        mov ecx, LENGTHOF warray - 1    ; start from end of array
    L1:
        mov ax, [edi + ecx * 2]     ; get number from warray
        movzx [esi + ecx * 4], ax   ; move number to darray
        loop L1 
    
        ; get and set element zero separately because loop terminates on ecx = 0:
        mov ax, [edi]
        movzx [esi], ax
    
        call ExitProcess
    main ENDP
    END
    

    您还应该注意,在使用相同类型的数组时,您可以使用重复前缀和 MOVSD 等指令非常有效地进行简单复制:

    ExitProcess PROTO
    .data
        array1 DWORD 1,2,3,4
        array2 DWORD 4 dup (?)
    
    .code
    main PROC
        mov esi, OFFSET array1      ; source pointer in esi
        mov edi, OFFSET array2      ; destination in edi
        mov ecx, LENGTHOF array1    ; number of dwords to copy
        cld                         ; clear direction flag so that pointers are increasing
        rep movsd                   ; copy ecx dwords
        call ExitProcess
    main ENDP
    END
    

    【讨论】:

    • 您需要movzx 加载和mov 存储,而不是相反。 movzx 只存在于注册目的地。
    猜你喜欢
    • 2013-12-31
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 2016-11-08
    相关资源
    最近更新 更多