【问题标题】:Reverse contents of array in assembly在汇编中反转数组的内容
【发布时间】:2011-03-09 20:43:06
【问题描述】:

我正在做一些组装作业,但对我的最后一个程序感到困惑。如果有 x86 汇编知识的人潜伏,请随时评论我如何开始使用它。谢谢!

问题

使用间接或索引寻址的循环来反转整数数组的元素。不要将元素复制到任何其他数组。还可以使用 SIZEOF、TYPE 和 LENGTHOF 运算符使程序灵活适应不同的数组。

到目前为止的代码:

.data
array BYTE 10h,20h, 30h, 40h

.code
main PROC
    call Clrscr

        ;no clue... 

    exit
main ENDP

END main

【问题讨论】:

  • 也许首先要考虑如何用您更熟悉的语言来做这件事。
  • 用 C 语言写出答案,然后编译到汇编器中,让它看起来像你自己输入的一样。 :D
  • 您可以使用堆栈将元素压入其中并弹出它们。例如:arr db 3, 2, 1push 3push 2push 1 在堆栈上,然后将它们弹出并从头开始将它们放置在适当的索引处。
  • 您可以使用堆栈将元素压入其中并弹出它们。例如:arr db 3, 2, 1push 3push 2push 1 在堆栈上,然后将它们弹出并放置在适当的索引处。

标签: assembly x86


【解决方案1】:

好吧,用 esi 指向数组的开头,用 edi 指向数组的结尾,加载这两个.. 元素(?),交换它们然后相应地更改 esi 和 edi 并重复直到......提示:你不必须交换任何东西,因为你在组装 =P

【讨论】:

  • 不知道谁投了你的票。向我投赞成票以抵消它。感谢您的回答!
【解决方案2】:

我不是很擅长组装,所以可能会有更好的答案(这个有效)。

TITLE Reversing an array without using oneother array
INCLUDE Irvine32.inc

.data
    array1 DWORD 10d,20d,30d,40d,50d,60d,70d,80d,90d
.code
main PROC
        mov ESI, OFFSET array1  ;ESI now points to the first item of array1
        mov EDI, SIZEOF array1
        add EDI, OFFSET array1
        sub EDI, TYPE array1    ;EDI now points to the last item of array1

        mov ECX, LENGTHOF array1
        shr ECX, 1          ;now ecx is half the length of the array1
L1:     mov EAX, [ESI]          ;in this loop we reverse the items of the array
        mov EBX, [EDI]
        mov [EDI],EAX
        mov [ESI],EBX
        add ESI, TYPE array1
        sub EDI, TYPE array1
        LOOP L1

        mov ECX, LENGTHOF array1;here we just print the array
        mov ESI, OFFSET array1
L2:     MOV EAX, [ESI]
        call WriteInt
        call Crlf
        add ESI, TYPE array1
        LOOP L2
        exit        
main ENDP
END main

【讨论】:

  • 是的,除非您不需要the slow loop instruction。只需 cmp esi, edi / jb L1 在开始指针低于结束指针时循环。指针设置也可以更简单:要么在数组末尾放一个标签,要么mov edi, OFFSET array1 + SIZEOF array1 - TYPE array1 以汇编类型进行所有计算。
【解决方案3】:

专业人士会使用特殊的字符串指令以及源和目标寄存器;但这可能看起来像你作弊了。

以下是您可以用来实现目标的基本记忆法:

  • MOV 目标源

    MOV eax,array 将数组地址加载到eax中

    MOV edx,[eax] 将eax指向的值加载到edx中

  • INC eax 将 eax 中的值增加一

  • OR eax, eax(如果 eax 为零,则设置零标志)

  • JZ 标签(如果设置了零标志,则跳转到标签)

通过添加冒号“:”来设置标签,例如label:

【讨论】:

  • 带有 特殊的字符串指令 你指的是 movs* 吗?我听说它们已经过时了
  • 已过时可能会对现代管道造成严重破坏,但仍能提供优雅而简单的解决方案。
  • 不是在谈论 MOVS。谈论使用 R/ESX 和 R/EDX 的微代码。此外:这根本不是问题或我的答案的意义所在。
  • @eznme,不知道谁投了你的票。向我投赞成票以抵消它。感谢您的回答!
  • 专业人士会使用 4 字节加载和 bswap 来反转寄存器中的 4 字节。您可能会考虑将 lodsd 用于负载和指针增量之一,但仅限于 Haswell 和更新版本,它只有 2 微秒。 (与mov eax, [esi] / add esi,4 相同)。另外,use test eax,eax to check if EAX is zero; or same,same is worse。但这没有任何意义,因为它是您建议的代码中的指针,而不是索引。
【解决方案4】:
INCLUDE Irvine32.inc
.data
arr1 word 1,3,4,6,7,8,9
.code
main PROC
mov esi,offset arr1
mov ax,offset arr1
mov ecx,lengthof arr1-1
l1:
mov ax,type arr1
loop l1

mov ecx,lengthof arr1
l2:
mov eax,[esi]
mov ebx,[ax]
xchg eax,ebx
mov esi,eax
mov ebx,ax

add esi,type arr1
sub ax,type arr1
dec ecx
loop l2


call dumpRegs
exit 
main ENDP
END main

【讨论】:

  • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。
  • mov ebx,[ax] 不会组装; 16 位寻址模式不能使用AX 作为基址或索引。这是 32 位代码,所以如果您使用有效寄存器但仍将 32 位标签地址截断为 16 位,您几乎肯定会出错。另外,这在任何一个循环中都没有任何存储指令,只是一个无用的xchg 和 reg-reg 移动。还有一个超级奇怪的dec ecx/loop,而不是首先使用length / 2 作为计数,或者像正常人一样步行2 个指针直到它们交叉。在注意到它完全被破坏之前,我只是因为效率低下(并且缺乏解释)而对此投了反对票!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-17
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多