2016-04-08 221 views
0

這是我的x86彙編代碼:打印時爲什麼會出現分段錯誤?

section .data 
    output db '%d',10,0 
section .text 
    global main 
    extern printf 
main : 
    xor ecx,ecx 
    xor eax,eax 
    mov eax,1 
    mov ecx,5 
lable1: 
    push ecx 
    push eax 
    cmp eax,0 
    jg print 
    pop eax 
    pop ecx 
    inc eax 
loop lable1 
    ret 
print: 
    push eax 
    push output 
    call printf 
    add esp,8 
    ret 

這個程序應在1間打印所有號碼5 爲什麼我打印「1」後得到一個分段錯誤?

+0

查看[x86標記wiki](http://stackoverflow.com/tags/x86/info)中的調用約定/ ABI鏈接。您可以將您的計數器保存在通話保存的寄存器中,而不是試圖在printf中推送/彈出它們。 –

回答

4

printret指令結尾,這意味着它應該是call。所以jg print應該是jng skip/call print/skip:(或只是call print,因爲> 0檢查似乎沒有必要)。
call將返回地址放在堆棧上,jg沒有。

+0

我知道檢查是不必要的。我只想知道爲什麼不打印後打印1並繼續主打印和打印1到5. @Michael – jasonjpq

+0

就像我說的,如果你期望'ret'工作,你需要使用'call'。 – Michael

+0

如果我想使用jg指令並將其重新恢復爲主,我該怎麼辦?如果它大於0,我想打印數字。(這是我爲jg錯誤編寫的示例代碼。)@Michael – jasonjpq

1

你不斷收到錯誤的原因是:你忽略了堆棧!

您的lable1子程序已正確設置,但您的jg從其中彈出,忽略堆棧 - 使堆棧損壞。

lable1: 
    push ecx 
    push eax 
    cmp eax,0 
    jg print 
    pop eax 
    pop ecx 
    inc eax 

你卻因爲

xor eax,eax  ; EAX = 0 - breaking pipeline 
mov eax,1  ; EAX = 1 - which is redundant 

cmp eax,0 
jg print 

lable1子程序,你跳到print:例行如果EAX大於0(它是第一以EAX = 1進行迭代),其中-8的堆棧偏移量由

push ecx 
push eax 

lable1:開頭。從print:開始的ret,最後清理棧正確add esp,8將導致程序返回到您已經分配給[ESP] =(前EAX = 1)的堆棧的第一個入口的地址。主要:mov eax,1

因此,您會得到一個SegFault,因爲您嘗試跳轉/返回到地址[00000001](= EAX = 1,32bit)。