push
/ pop
操作以及用于遍历每个元素的first / next。我正在寻找常规反馈。
这是堆栈子例程:
; Stack Structure
; Pointer Head
; Pointer Current
; Stack Node
; Pointer Next
; Pointer Value
; input
; void
; output
; stack or 0 on error
StackCreate:
mov rdi, 24
call malloc
test rax,rax
jz StackCreate_end
xor rdi, rdi
mov [rax], rdi
mov [rax+8], rdi
ret
StackCreate_end:
add rsp, 8
ret
; input
; stack
; output
; void
StackDestroy:
call free
ret
; input
; stack
; value
; output
; 0 on error
StackPush:
push rdi
push rsi
mov rdi, 16
call malloc
test rax,rax
jz StackPush_end
pop rsi
pop rdi
mov rdx, [rdi]
mov [rax], rdx
mov [rax+8], rsi
mov [rdi], rax
ret
StackPush_end:
add rsp, 16
ret
; input
; stack
; output
; value or 0 if empty
StackPop:
mov rsi, rdi
mov rdi, [rdi]
test rdi, rdi
jz StackPop_end
mov rax, [rdi]
mov [rsi], rax
mov rax, [rdi+8]
push rax
call free
pop rax
ret
StackPop_end:
xor rax, rax
ret
nop;e
; input
; stack
; output
; value or 0 if empty
StackFirst:
mov rax, [rdi]
test rax, rax
jz StackFirst_end
mov rsi, [rax]
mov [rdi+8], rsi
mov rax, [rax+8]
StackFirst_end:
ret
; input
; stack
; output
; value or 0 if end
StackNext:
mov rsi, [rdi+8]
test rsi, rsi
jz StackNext_end
mov rax, [rsi]
mov [rdi+8], rax
mov rax, [rsi+8]
ret
StackNext_end:
xor rax, rax
ret
这里是驱动程序:
[extern puts]
[extern malloc]
[extern free]
[SECTION .data]
arguments:
db "Incorrect arguments.",10,"Expected: stackme <string1> <string2> ...",0
[SECTION .text]
BITS 64
global main
wrong_arguments:
mov rdi, arguments
call puts
jmp main_end
main:
cmp rdi, 1
jle wrong_arguments
lea r12, [rsi+8]
lea r13, [rdi-1]
call StackCreate
test rax, rax
jz main_end
mov r14, rax
pushing_loop:
test r13, r13
jz pushing_done
mov rdi, r14
mov rsi, [r12]
call StackPush
add r12, 8
dec r13
jmp pushing_loop
pushing_done:
mov rdi, r14
call StackFirst
print_loop:
test rax, rax
jz print_done
mov rdi, rax
call puts
mov rdi, r14
call StackNext
jmp print_loop
print_done:
stack_delete:
mov rdi, r14
call StackPop
test rax, rax
jnz stack_delete
stack_delete_done:
mov rdi, r14
call StackDestroy
main_end:
xor eax, eax
ret
组装/链接
>
nasm -f elf64 -l stackme.lst stackme.asm
gcc -o stackme stackme.o
#1 楼
该代码通常写得很好并且易于理解,但是我对它有一些意见可以帮助改进它。消除
StackCreate
例程中的“幻数” ,第一个指令是
mov rdi,24
,但在这种情况下尚不清楚24表示什么。注释或命名常量或两者都将对此有所帮助。添加更多有意义的注释
注释中的堆栈结构不是很清楚。我们可以推断出堆栈是由节点组成的,但是从代码或注释中很难分辨出来。
还要考虑堆栈代码的用户。当前代码中没有足够的信息来理解调用顺序,注册用法或返回值。所有这些内容在评论中都会很有用。如果您打算使用标准的ABI,则最好说出哪一个。
适当地使用
rep ret
当
rep ret
可能是gcc编译器时,gcc编译器会发出ret
。跳跃的目标。这似乎很奇怪(而且确实如此!),但是原因是当ret
不是分支目标时,AMD和Intel处理器上的分支预测逻辑都能更好地工作。因此,这意味着代码中的StackFirst_end
标签实际上应该在rep
之前有一个ret
前缀。适当地使用
struc
因为您的堆栈使用两种结构,这会有所帮助使用NASM的
struc/endstruc
宏。这样既可以使代码在处理数据结构时更清楚,又可以消除我前面提到的许多“魔术数字”。考虑重构
StackFirst
和StackNext
StackFirst
和StackNext
例程除了特定寄存器选择上的细微差别外,非常相似。可以将它们合并以消除一些代码。减少使用
malloc
和free
malloc
和free
调用在计算上往往相对昂贵,尤其是相对于您已获得的汇编代码而言。因此,分配和管理一个块而不是为每次堆栈推调用malloc
或用用户可以为速度而替换的某些其他内存分配方案替换对malloc
和free
的调用,可能更有意义。 br /> 重新排列循环以避免无条件跳转
当前的
pushing_loop
如下所示: pushing_loop:
test r13, r13
jz pushing_done
mov rdi, r14
mov rsi, [r12]
call StackPush
add r12, 8
dec r13
jmp pushing_loop
pushing_done:
但是,可以稍微重新排列以消除其中一种跳转:
inc r13
jmp push_test
pushing_loop:
mov rdi, r14
mov rsi, [r12]
call StackPush
add r12, 8
push_test:
dec r13
jnz pushing_loop
无条件跳转仅在循环的顶部进行一次,所有其他迭代仅在以下位置使用条件测试循环的底部。代码中还有其他一些地方可以应用。