2012-12-15 78 views
1

我是一名編寫彙編代碼的新手,我需要一些幫助。將32位斐波納契nasm代碼轉換爲64位

我的任務是在NASM(在Linux上)編寫一個程序,它計算第n個斐波那契數,其中n是從STDIN中讀取的系統調用,並且用C atoi/atol轉換爲int/long。計算出的數字將被寫入STDOUT(我可以使用C printf)。

我設法寫出工作的32位代碼,我堅持將它轉換爲64位(使用64位寄存器,64位長int)。我試圖做到天真(改變eax - > rax,esp - > rsp等),但我得到的唯一東西是segfault。

編輯:錯字是固定

EDIT2:任何想法,如何使用64位整數,以顯示出比46個Fibonacci數高?

下面的代碼:

section .data 
     format: db  '%d', 0xA 


section .bss 
     buffer resb 8 
     bufferLength equ $-buffer; 

section .text 

extern printf 
extern atoi 

global main 

main: 
     call fib 

fib: 
     mov rax, 3 
     mov rbx, 0 
     mov rcx, buffer 
     mov rdx, bufferLength 
     int 0x80 

     push 0 
     push buffer 
     call atoi 
     add rsp, 8 

     push rbx 
     mov rcx, rax 
     xor rax, rax 
     xor rbx, rbx 
     inc rbx 

     call print 

exitProg: 
     mov rbx, 0 
     mov rax, 1 
     int 0x80 

print: 
     push rax 
     push rcx 

     push rax 
     push format 
     cmp rcx, 1 
     je lastPrint 
     add rsp, 8 

     pop  rcx 
     pop  rax 

     mov  rdx, rax 
     mov  rax, rbx  
     add  rbx, rdx   
     dec  ecx   
     jnz  print  

     pop  rbx  

lastPrint: 
     call printf 
     add rsp, 8 
     call exitProg 

在此先感謝。

回答

3

你的函數不是真正的函數,因爲它們不返回。你應該考慮重寫它們。如果您使用的是C庫,最好從main返回而不是使用exit系統調用。另外,如果允許,最好使用C庫I/O函數。

在64位模式下,您通常使用syscall指令訪問系統調用,但int 0x80接口也可用於兼容性。請注意,system call numbers與32位不同。

此外,即使調用約定是不同的(用戶和系統調用),一些參數在寄存器中傳遞並且堆棧需要保持對齊。有關詳細信息,請參閱ABI文檔。

我很難理解print代碼的邏輯,尤其是瘋狂的堆棧操作。還要注意,因爲rcx之前檢查爲1,因此永遠不會到達pop rbx行,因此在遞減之後它永遠不會爲零。

您還有一個錯字bufor。最後,你的格式字符串在文本部分。雖然這是有效的,但我猜你在.data想要的,你只是錯誤的指令(這是在你的文件的第一行)。

我希望大部分上述內容也適用於原始的32位代碼。

更新這裏是一個可能的實現,現在64位的結果(對於高至N = 93),並使用XADD(感謝弗蘭克·科特勒):

section .data 
format: 
     db  "%lu", 10, 0 

section .bss 
     buffer resb 8 
     bufferLength equ $-buffer 

section .text 

default rel ; use rip relative addressing (optional) 
extern printf 
extern atoi 

global main 

main: 
     sub rsp, 8    ; stack alignment 

     ; note: this should be a call to libc read function 
     ; but apparently assignment forces us to use syscall 
     xor eax, eax   ; syscall number for "read" is 0 
     xor edi, edi   ; fd 0, stdin 
     lea rsi, [buffer]  ; buf 
     mov edx, bufferLength ; length 
     syscall 

     lea rdi, [buffer] 
     call atoi 

     mov edi, eax   ; pass returned value from atoi 
     call fib 

     lea rdi, [format] 
     mov rsi, rax   ; the returned value from fib 
     xor eax, eax   ; no xmm registers used 
     call printf 

     xor eax, eax   ; return zero 
     add rsp, 8 
     ret 

fib: 
     mov eax, edi 
     sub edi, 1 
     jle fib_done   ; f(0)=0, f(1)=1 
     xor ecx, ecx   ; f(n-1) 
     mov eax, 1    ; f(n) 
fib_loop: 
     xadd rax, rcx 
     sub edi, 1 
     jnz fib_loop 

fib_done: 
     ret 
+0

感謝您指出這個錯誤。我也將格式移至.data。 實際上,我只能從C庫中使用atoi和printf(這是我的任務的一部分)。 刪除計算並僅使用read()+ printf()(如echo)與64位編譯的elf64可執行文件中的兼容性系統調用完美地工作。 – Protazy

+2

對於一個「可愛」的方式做斐波那契,看看'xadd' ... –

+0

@FrankKotler:很好。 – Jester