将 C 代码转换为 x86-64 汇编

Converting C code to x86-64 assembly

我正在尝试将我的 C 代码转换为 x86-64。我的目标是反转链表。传入的两个参数是 head ptr 和 offset to 得到指针字段的地址(即指向列表中下一个节点的指针)。

据我了解,head ptr是通过rdi寄存器传入的,offset是通过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

我不愿意 post 我在编写此答案时重新创建的代码。你不会那样学到任何东西。

因此,您可能需要先解决以下问题:

1) 鉴于 linux 有 ~7 个寄存器可以用于临时,似乎不需要 push/pop rbx 和 r12。使用其他不需要保存的寄存器。

2) 看起来您将注释 放在 他们描述的代码之后(#headptr 等)。这是 而不是 阅读您的代码的人所期望的。最常见的是将它放在之前的行上,或者(尤其是在汇编程序中)放在同一行上。

3) C 中的常见做法是在使用变量(尤其是指针)之前始终将它们置零。然而,在 asm 中就更少了。特别是当下一条语句要为同一个寄存器分配不同的值时。这在 C 中不是问题,因为编译器的优化器将简单地丢弃冗余初始化器。但是汇编程序没有优化器,所以这只是浪费space/cycles。只有零必须归零的东西。

4) 对寄存器进行清零时,使用xor eax, eax 而不是mov。它smaller/faster.

5) 如果您的代码是使用 head_ptr = reverse_asm_64(head_ptr, 16) 调用的,您需要在取消引用之前检查 rdi 以查看它是否为空。

6) 在 asm 中,您应该使用 test rdi, rdi 查看 rdi 是否为零而不是 cmp rdi, 0。这是 smaller/faster.

7) "move offset into a register" 说什么?偏移量已经在寄存器中:rsi。为什么要在 r12 中复制?

8) 第一次 "checks that next ptr isn't null" 时,您只是将偏移量添加到值中。除非您的偏移量为零,否则这不会按照您的意图进行。另见#6。

9) "add offset to rax to get the next ptr" 只执行一次(即在循环外)。列表中的每个指针不需要添加这个偏移量吗?

还有更多,但那是 9 项。似乎足够开始了。