2017-10-18 8 views
0

私のCコードをx86-64に変換しようとしています。私の目標は、リンクされたリストを逆転させることです。渡される2つのパラメータは、ポインタフィールドのアドレス(すなわち、リスト内の次のノードへのポインタ)を得るためのhead ptrおよびoffsetである。Cコードをx86-64アセンブリに変換する

私が理解するところでは、ヘッド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

このような一見無駄な運動の理由はありますか? –

+5

これには本当に良いツールがあります:Cコンパイラ。それらの多くはアセンブリコードを発行するオプションを持っていますが、そうでないものは逆アセンブラと組み合わせることができます。 –

+0

誰かがこれが役に立たない運動であることに同意してうれしいです。私はクラスの割り当てのためにそれを完了する必要がありますが、私は過去数日間立ち往生してきました。 – Ryan

答えて

2

この回答を書いているうちに作成した再加工コードを投稿するのは嫌です。あなたはそのようなことは何も学ばないでしょう。

ので、ここであなたが開始するために修正することがありますいくつかのものです:Linuxはあなたが最初に使用することができます〜7のレジスタを持っていることを考えると

1)は、/ポップをプッシュする必要があるとは思えませんrbxとr12。保存する必要のない他のレジスタを使用してください。

2)の後に、のコードの後に​​(#headptrなど)コメントを入れているようです。これはではなく、あなたのコードを読んでいる人はどんなことを期待していますか?最も一般的なのは、前に行に置くか、(特にアセンブラで)同じ行に置くかのどちらかです。

3)C言語では、使用する前にすべての変数(特にポインタ)をゼロにするのが一般的です。しかし、asmではそうではありません。特に、次のステートメントが同じレジスタに異なる値を割り当てる場合です。コンパイラのオプティマイザは冗長イニシャライザを単に破棄するため、これはCの問題ではありません。しかし、アセンブラにはオプティマイザが搭載されていないので、これは単にスペース/サイクルの無駄です。 0にする必要があるもののみゼロにします。

4)レジスタをゼロにするときは、movの代わりにxor eax, eaxを使用します。それはより小さい/より速い。

5)コードがhead_ptr = reverse_asm_64(head_ptr, 16)で呼び出されている場合は、逆参照する前にrdiがnullであるかどうかを確認する必要があります。

6)asmでは、cmp rdi, 0ではなくrdiが0であるかどうかを確認するには、test rdi, rdiを使用する必要があります。それはより小さい/より速いです。

7) "オフセットをレジスタに移動"とは何ですか?オフセットはすでにレジスタ:rsiにあります。なぜr12でコピーを作成するのですか?

8)「次のptrがnullでないことを確認する」最初に、値にオフセットを追加しました。オフセットがゼロでない限り、これはあなたが意図したことをするつもりはありません。 #6も参照してください。

9)「次のptrを取得するためのraxへのオフセットの追加」は、1回だけ(つまりループの外側で)行われます。リスト内の各ポインタにこのオフセットを追加する必要はありませんか?

さらに、それは9項目です。開始のために十分なようです。

関連する問題