2017-10-18 190 views
0

我試圖將我的C代碼轉換爲x86-64。我的目標是扭轉鏈接列表。傳入的兩個參數是頭部ptr和偏移量以獲取指針字段的地址(即指向列表中下一個節點的指針)。將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

我不願意發佈我作爲編寫此答案的一部分而創建的重新工作的代碼。你不會學到任何東西。

因此,這裏有您可能要修復啓動一些事情:

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,以便在對其進行解引用之前檢查rdi是否爲空。

6)在asm中,您應該使用test rdi, rdi來查看rdi是否爲零而不是cmp rdi, 0。它更小/更快。

7)「將偏移移入寄存器」說什麼?偏移量已經在寄存器中:rsi。爲什麼要在r12中製作副本?

8)第一次你「檢查下一個ptr不爲空」,你剛剛添加了偏移量的值。除非你的抵消是零,這不會做你想要的。另見#6。

9)「添加抵消rax來獲得下一個ptr」只做一次(即在循環外)。列表中的每個指針都不需要添加這個偏移量嗎?

還有更多,但這是9項。似乎足夠一開始。