2013-03-22 85 views
0

我在linux上使用NASM編寫基本彙編程序,該程序從C庫(printf)調用函數。不幸的是,我在這樣做時發生了分段錯誤。註釋掉對printf的調用可以使程序無誤地運行。從組件調用C函數時發生Seg故障

; Build using these commands: 
; nasm -f elf64 -g -F stabs <filename>.asm 
; gcc <filename>.o -o <filename> 
; 

SECTION .bss ; Section containing uninitialized data 

SECTION .data ; Section containing initialized data 

    text db "hello world",10 ; 

SECTION .text ; Section containing code 


global main 

extern printf 

;------------- 
;MAIN PROGRAM BEGINS HERE 
;------------- 

main: 



     push rbp 

     mov rbp,rsp 

     push rbx 

     push rsi 

     push rdi ;preserve registers 

     **************** 


     ;code i wish to execute 

     push text ;pushing address of text on to the stack 
     ;x86-64 uses registers for first 6 args, thus should have been: 
     ;mov rdi,text (place address of text in rdi) 
     ;mov rax,0 (place a terminating byte at end of rdi) 

     call printf ;calling printf from c-libraries 

     add rsp,8 ;reseting the stack to pre "push text" 

     ************** 

     pop rdi ;preserve registers 

     pop rsi 

     pop rbx 

     mov rsp,rbp 

     pop rbp 

     ret 
+0

庫函數的調用約定又是什麼?我的猜測是你使用了錯誤的。 – 2013-03-22 16:46:31

+0

在我正在閱讀的書中(涵蓋32位程序集,而不是64位),它只是說推動字符串地址,調用函數,清理堆棧指針。我認爲文本將是唯一需要的參數,因爲printf搜索空字節終止。 – user2177208 2013-03-22 16:56:10

+1

文本字符串必須以0字節結尾!如果沒有,'printf()'知道它會在哪裏結束? – 2013-03-22 17:00:30

回答

3

x86_64不使用堆棧的前6個參數。您需要將它們加載到正確的寄存器中。這些都是:

rdi, rsi, rdx, rcx, r8, r9 

我使用記得前兩個訣竅是想象中的功能memcpy實現爲rep movsb

+0

謝謝。我的書是在32位組件上,它將參數放在堆棧上。 – user2177208 2013-03-22 17:15:59

+2

另外,由於'printf'是一個可變參數函數,所以你需要在這裏設置'%al'爲用於參數的XMM寄存器的數量。 – 2013-03-22 17:57:56

0

你需要熟悉與使用中的調用約定。 AMD64上的Linux使用System V AMD64 ABI。從這個文件中,我們得知:

  • 整型參數RDI,RSI,RDX,通過RCX,R8和R9
  • 花車傳入XMM0到XMM7
  • 的可變參數的函數的SSE寄存器的數目使用放在RAX

所以呼叫

printf ("Hello World\n"); 

你有

.section .data 
format db "Hello World", 10, 0 

.section .text 
mov rdi, format 
mov rax, 0 
call printf