将C代码转换为x86-64程序集

时间:2017-10-18 19:29:17

标签: c assembly x86-64 inline-assembly

我正在尝试将我的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

1 个答案:

答案 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件。似乎已经足够开始了。