【发布时间】:2012-04-29 07:35:13
【问题描述】:
我正在尝试在 NASM 中实现一个在 64 位 Linux 上运行的数组的选择排序。
数组声明为:
section .bss
strbuf resb 10
small resb 1 ; current minimum value
排序算法本身很简单,但我觉得受到两件事的限制:可用寄存器的数量,以及无法交换立即数(即括号)
我需要跟踪未排序的数组边界、它的索引、当前最小值的位置以及它的索引。那已经是四个寄存器了。我还需要跟踪两个循环计数器,一个用于表示未排序数组边界的外部循环,另一个用于每次遍历的迭代(即内部循环)。那是另外两个,总共六个寄存器。
由于立即数不能相互移动,例如mov [var1], [var2],所以每当我需要交换两个元素时,我都需要使用寄存器作为临时占位符。在跟踪哪些寄存器保存哪些信息方面,这很快变得笨拙!
以下是我目前的尝试。请注意,这是触发分段错误的无效代码。但也许你能看出我在做什么,并指出我的方法哪里出了问题。
我不希望使用简化结构的宏,例如提供 .IF 和 .ELSE 的宏。
; ====== Sorting begins here ======
sorting:
mov edi, strbuf ; outer loop pointer
mov esi, strbuf ; inner loop pointer
mov eax, 0 ; inner loop counter
mov ebx, 0 ; outer loop counter
innerloop:
; store the value of first element in [small]
mov edx, [esi]
mov [small], edx
; compare the current small value with the value pointed by esi
mov edx, [esi]
cmp [small], edx
jg new_small
inc esi
inc eax
cmp eax, 9
jle innerloop
cmp eax, 9
jg innerloop_done
new_small:
mov [small], edx ; save the new small value
mov ecx, esi ; save its index in ecx
inc esi
inc eax
cmp eax, 9
jle innerloop
innerloop_done:
; When the inner loop is completed...
; First, do the swap
push rax
mov eax, [edi]
mov edx, [small]
mov [ecx], edx
pop rax
inc edi ; move the outer loop pointer forward
inc esi ; move the inner loop pointer forward
inc ebx ; increment the outer loop counter (the unsorted array becomes smaller)
inc eax ; increment the inner loop counter (same reason as above)
cmp ebx, 9
jle innerloop
; ====== Sorting ends here ======
【问题讨论】:
-
关于如何正确构建汇编代码的指南似乎并不多。每当您阅读有关 C++、C 或 Java 等流行语言的编程书籍时,您总是会获得扎实的、扎实的编程原则,以防止您自欺欺人。在汇编中,唯一的原则似乎是“只要你需要让你的程序正常工作,就在脚上开枪。”
-
:)) ASM 非常需要注意力,需要大量细致而乏味的工作。但!它在某一方面优于 C 和 C++。它是固定的。当您使用不同的汇编程序时,x86 字节、字和双字的大小不会改变。并且 x86 ASM 不能直接适用于 ARM 或 MIPS 等其他平台或可重新编译。没有来自 C/C++ 程序员很少阅读和理解的语言标准的未定义行为。 CPU 手册准确地说明了该 CPU 的有效内容和无效内容。所见即所得! :)
-
您也可以在 ASM 中使用许多高级编程技术。您可以定义子例程,可以定义宏,所有这些都不要重复自己并避免一些错误。您可以评论代码。您可以在多个模块中构建它。您可以拥有回调和其他可间接调用的子例程。虚拟方法,如果你愿意的话。在 ASM 中,您可以做任何事情,只是需要更多的代码和工作。
-
谢谢。我还发现很少有高级编程概念有助于汇编。我的思维习惯于将数据视为值、指针或地址。但在 ASM 中,这些概念似乎都不适用,因为寄存器不知道它包含什么类型的数据。
-
ASM 本质上是极其明确和低级的。没有隐藏的函数调用、跳转、堆栈展开、类型转换、临时对象。我发现了解 ASM 对学习 C 和 C++ 有很大帮助。反过来说,没那么多。这是有原因的。 C 和 C++ 是从 ASM 发展而来的。
标签: assembly x86 x86-64 nasm yasm