我正在尝试将我的C代码转换为x86-64。我的目标是扭转链表。传入的两个参数是head ptr和偏移量,以获得指针字段的地址(即指向列表中下一个节点的指针)。
根据我的理解,head ptr通过rdi寄存器传入,偏移量通过rsi寄存器传入。当它到达“mov rcx,[rbx]”这一行时,我一直遇到分段错误。当它只是“mov rcx,rbx”并且后面的行从“mov [rbx],rdx”变为“mov rbx,rdx”时,分段故障消失了。但是,我最终陷入了无限循环,因为它只是一遍又一遍地分配相同的值。
当我跟随我的C代码时,x86-64中的所有逻辑都对我有意义,所以我真的处于停滞状态。有任何想法吗?这是我第一次使用x86-64。
.intel_syntax noprefix
.text
.global reverse_asm_64
reverse_asm_64:
push rbx
push r12
mov rax, 0x0
#headptr
mov rbx, rax
#nextptr
mov rcx, rax
#new_headptr
mov rdx, rax
#head
mov rax, [rdi]
#checks if head is null
cmp rax, 0
je null_ret
#move offset into a register
mov r12, rsi
add rax, r12
#add offset to rax to get the next ptr
mov rbx, rax
while_start:
#checks that next ptr isn't null
cmp rbx, 0x0
je while_done
#setting the next ptr
mov rcx, [rbx]
# *headptr = new_headptr
mov [rbx], rdx
#new_headptr = headptr
mov rdx, rbx
#sets headptr to nextptr
mov rbx, rcx
jmp while_start
while_done:
mov rax, rdx
sub rax, rsi
null_ret:
pop r12
pop rbx
ret
答案 0 :(得分:3)
我不愿意发布我在编写此答案时创建的重新编写的代码。你不会那样学习任何东西。
所以,这里有一些你可能想要开始修复的事情:
1)鉴于linux有~7个寄存器你可以用于刮擦,似乎没有必要推/弹rbx和r12。使用其他不需要保存的寄存器。
2)看起来你正在将之后的评论放在所描述的代码中(#headptr
等)。这是不读取您的代码的人会期望什么。最常见的是将它放在线之前,或者(尤其是在汇编程序中)放在同一行上。
3)C中的常见做法是在使用它们之前始终将所有变量(尤其是指针)清零。然而,在asm中则不那么重要。特别是当下一个语句要为同一个寄存器分配不同的值时。这不是C中的问题,因为编译器的优化器将简单地丢弃冗余初始化器。但是汇编程序没有优化器,所以这只是浪费空间/周期。只有零事物必须归零。
4)归零寄存器时,请使用xor eax, eax
代替mov
。它更小/更快。
5)如果您的代码是使用head_ptr = reverse_asm_64(head_ptr, 16)
调用的,那么在解除引用之前,您需要检查rdi是否为null。
6)在asm中,您应该使用test rdi, rdi
来查看rdi是否为零而不是cmp rdi, 0
。它更小/更快。
7)“将偏移移入寄存器”说什么?偏移量已经在寄存器中:rsi。为什么要在r12中复制?
8)第一次“检查下一个ptr不为空”时,您刚刚将偏移量添加到该值。除非您的偏移量为零,否则这不符合您的意图。另见#6。
9)“向rax添加偏移以获得下一个ptr”仅执行一次(即在循环外部)。列表中的每个指针都不需要添加此偏移量吗?
还有更多,但那是9件。似乎已经足够开始了。