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

标签 c assembly x86-64 inline-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

最佳答案

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

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

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) 第一次“检查下一个指针不为空”时,您只是将偏移量添加到该值。除非您的偏移量为零,否则这不会按照您的意图进行。另见#6。

9) “将偏移量添加到 rax 以获得下一个 ptr”仅执行一次(即在循环之外)。列表中的每个指针不需要添加这个偏移量吗?

还有更多,但那是 9 项。似乎足以作为一个开始。

关于将 C 代码转换为 x86-64 汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46817800/

相关文章:

c - 使用变量将不同的字符串分配给 char 数组

c - 可能是内存问题还是其他什么问题?

c - strcasecmp 实现不打印

编译器使用局部变量而不调整 RSP

c - 如何在 C 中读取 .txt

android - 如何重新启动 Activity 来重新加载静态库?

assembly - 有什么可以防止汇编中的堆栈溢出吗?

linux - syscall getpid,打印返回值?

assembly - 字和字操作数的大小是多少?

linux - 该程序(提供源)在Ivy Bridge Xeon上运行的时间是旧版移动Sandy Bridge的两倍