MASM Assembly 中的数组(非常困惑的初学者)

Posted

技术标签:

【中文标题】MASM Assembly 中的数组(非常困惑的初学者)【英文标题】:Arrays in MASM Assembly (very confused beginner) 【发布时间】:2022-01-21 01:19:15 【问题描述】:

我有一个非常基本的问题: 你如何在汇编中填充数组?在高级编程语言中,您可以使用 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?任何帮助将不胜感激...我很困惑。

【问题讨论】:

【参考方案1】:

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

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 只存在于注册目的地。【参考方案2】:

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

看看这里的微软页面: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 相同),但其他更差

以上是关于MASM Assembly 中的数组(非常困惑的初学者)的主要内容,如果未能解决你的问题,请参考以下文章

在 Assembly x86 MASM 中连接字符串和数组的大小

如何将Assembly(irvine masm)中的字符串初始化回null?

使用 MASM32 随机化装配中的数字

在 MASM 8086 程序集中读取多个文件

为 C++ 程序编写 MASM 函数

MASM:8086 中的 3X3 矩阵乘法有问题吗?