我正在尝试在64位Linux上运行的NASM中实现一个选择类型的数组。
数组声明为:
section .bss
strbuf resb 10
small resb 1 ; current minimum value
排序算法本身很简单,但我觉得受到两件事的限制:可用的寄存器数量,以及无法交换立即数(即括号)
我需要跟踪未排序的数组边界,索引,当前最小值的位置及其索引。那已经是四个寄存器了。我还需要跟踪两个循环计数器,一个用于表示未排序数组边界的外循环,另一个用于每次传递(即内循环)的迭代。那是另外两个,总共六个寄存器。
由于immediates不能相互移动,例如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 ======
答案 0 :(得分:2)
如果这应该在64位模式下执行,你必须使用64位地址,这意味着当你取这些地址并将它们放入寄存器时,那些接收寄存器也必须是64位,否则你将截断地址并访问内存并不是你想要的地方。
另外,您是否有调试器来逐步执行代码?
答案 1 :(得分:1)
对于64位代码,有16个通用寄存器:RAX,RBX,RCX,RDX,RSI,RDI,RSP,RBP,R8,R9,R10,R11,R12,R13,R14,R15。
其中,RSP有特殊用途,只能用于此目的(当前堆栈地址)。 RBP寄存器通常由编译器用于跟踪堆栈帧(不包括“-fomit-frame-pointer”可能性),但您不是编译器,可以将它用于您喜欢的任何内容。
这意味着您可以使用的15个寄存器中只有6个。
如果你确实用完了寄存器,那么你可以把一些东西转移到堆栈空间。例如:
foo:
sub rsp,8*5 ;Create space for 5 values
%define .first rsp
%define .second rsp+8
%define .third rsp+8*2
%define .fourth rsp+8*3
%define .fifth rsp+8*4
%define .first rsp+8*5
mov [.first],rax
mov [.second],rax
mov rax,[.first]
add rax,[.second]
mov [.third],rax
...
add rsp,8*5 ;Clean up stack
ret
希望您可以看到堆栈上可能有数百个值,并且如果需要,可以使用一些寄存器(临时)保存这些值。通常,您可以计算出最常使用的值(例如,在内部循环中)并尝试使用寄存器,并将堆栈用于最不常用的变量。但是,对于64位代码(你可以使用8个以上的寄存器),很少用完寄存器,如果你这样做,可能表明你需要将例程拆分成多个例程。