将 C 代码转换为 x86-64 程序集
Posted
技术标签:
【中文标题】将 C 代码转换为 x86-64 程序集【英文标题】:Converting C code to x86-64 assembly 【发布时间】:2018-03-30 18:39:48 【问题描述】:我正在尝试将我的 C 代码转换为 x86-64。我的目标是反转一个链表。传入的两个参数是头 ptr 和偏移量,以获取指针字段的地址(即指向列表中下一个节点的指针)。
据我了解,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
【问题讨论】:
这种看似无用的练习有充分的理由吗? 有一些工具对此非常有用:C 编译器。他们中的许多人可以选择发出汇编代码,而那些没有的可以与反汇编程序配对。 很高兴有人同意这是一个无用的练习。我需要完成课堂作业,但过去几天我一直卡住了。 您没有发布您的 C 代码,但第一个整数/指针参数在rdi
中传递,第二个在 rsi
中传递。什么是“抵消”?进入链表的位置?你的汇编很难阅读;缩进你的说明而不是标签。此外,与指令在同一行的 cmets 使事情更加紧凑。
另外,您不需要保存/恢复 rbx 和 r12。您可以使用 r8、r9、r10 和 r11 作为临时注册,以及 rax/rcx/rdx/rsi/rdi。
【参考方案1】:
我不愿意只发布我在编写此答案时创建的重新编写的代码。那样你不会学到任何东西。
因此,您可能需要先解决以下问题:
1) 鉴于 linux 有大约 7 个寄存器可以用于临时,似乎不需要推送/弹出 rbx 和 r12。使用其他不需要保存的寄存器。
2) 看起来您将 cmets 置于 他们描述的代码之后(#headptr
等)。这不是阅读您的代码的人所期望的。最常见的是将它放在之前的行上,或者(尤其是在汇编程序中)放在同一行上。
3) C 中的常见做法是在使用之前始终将所有变量(尤其是指针)清零。但是,在 asm 中则更少。尤其是当下一条语句要为同一个寄存器分配不同的值时。这在 C 中不是问题,因为编译器的优化器将简单地丢弃冗余的初始化程序。但是汇编器没有优化器,所以这只是浪费空间/周期。只有零的东西必须归零。
4) 清零寄存器时,使用xor eax, eax
而不是mov
。它更小/更快。
5) 如果您的代码是用head_ptr = reverse_asm_64(head_ptr, 16)
调用的,您将需要在取消引用之前检查 rdi 是否为空。
6) 在 asm 中,您应该使用 test rdi, rdi
来查看 rdi 是否为零,而不是使用 cmp rdi, 0
。它更小/更快。
7)“将偏移量移入寄存器”说什么?偏移量已经在寄存器中:rsi。为什么要在 r12 中制作副本?
8) 第一次“检查下一个 ptr 是否为空”时,您刚刚将偏移量添加到值中。除非您的偏移量为零,否则这不会达到您的预期。另见 #6。
9) “将偏移量添加到 rax 以获取下一个 ptr”仅执行一次(即在循环之外)。列表中的每个指针不是都需要添加这个偏移量吗?
还有更多,但那是 9 项。开始似乎已经足够了。
【讨论】:
以上是关于将 C 代码转换为 x86-64 程序集的主要内容,如果未能解决你的问题,请参考以下文章