2015-12-06 62 views
1

我真的試圖使while循環,通過0-10打印,但有一些錯誤...需要與NASM環

編譯這些一些建議:

nasm -f elf myprog.asm 
gcc -m32 -o myprog myprog.o 

錯誤:

在輸出可以看到134513690 ..很多.... ,並在最後一行segmentation fault

這是代碼:

SECTION .text 

global main 

extern printf 

main: 
    xor eax,eax  ; eax = 0 

myloop: 
    cmp eax,10   ; eax = 10? 
    je finish   ; If true finish 

    push eax   ; Save eax value 
    push number  ; push number value on stack 
    call printf 

    pop eax 
    inc eax   ; eax + 1 
    add esp,80   ; Im not sure what is this 
    jmp myloop   ; jump to myloop 

number db "%d",10,0 ; This is how i print the numbers 

finish: 
    mov eax,1 
    mov ebx,0 
    int 0x80 
+0

您應該在main的開始/結束處保存/恢復ebx,並將其用於循環計數器。在正常的ABI中,EBX被保留在函數調用中:http://stackoverflow.com/a/34100481/224132 –

+0

謝謝,我會試試:) – Bit87

回答

1

有一個在此代碼的一個真正的錯誤;函數調用清理並不完全正確。我想改變myloop部分是這樣的:

myloop: 
    cmp eax,10   ; eax = 10? 
    je finish   ; If true finish 

    push eax   ; Save eax value 
    push number  ; push number value on stack 
    call printf 

    add esp, 4   ; move past the `push number` line 
    pop eax 
    inc eax   ; eax + 1 
    jmp myloop   ; jump to myloop 

最大的區別在於,不是增加80 esp(我不知道你爲什麼這樣做,是),你只需要添加尺寸的推論。此外,之前錯誤的值被彈出爲eax,但切換addpop的順序解決了此問題。

+0

謝謝,這個工作完美,我是彙編語言的新手,這對我很有幫助,它花了我一週時間,但是非常感謝: D – Bit87

+0

很高興幫助。我自己並沒有進行過多的彙編編程,但是當調試C代碼時,這些知識當然有幫助:) –

0

有一些問題,您需要將「數字」不是地址,而是數字。

push dword number 

在您調用printf之後,您需要恢復堆棧ESP。 基本上,當你「推」一個寄存器時,它會被存儲在堆棧中。由於你推兩次(兩個參數),你需要恢復8個字節。

當您「pop eax」時,您將檢索堆棧的頂部,即「數字」,而不是計數器。因此,你只需要做

pop eax 
pop eax 

然後沒有必要通過添加來恢復ESP,因爲它是通過彈出來完成的。 基本上,在第一次迭代後,在地址EAX分,所以它永遠不會等於10

進一步閱讀有關堆棧指針和基址指針: Ebp, esp and stack frame in assembly with nasm

+0

'add esp,4'是首選的(如果你沒有因爲它不需要訪問像「pop」這樣的內存, –

+0

@MichaelPetch:實際上,根據上下文的不同,'add esp,4'可能會變慢。堆棧引擎將不得不插入一個額外的uop,以將esp的OOO核的值與堆棧引擎的偏移量同步。 'pop'是單用戶指令,而加載端口資源通常不是瓶頸。但是,這個答案應該建議使用[call-preserved register](http://stackoverflow.com/a/34100481/224132)像ebx這樣的循環變量,而不是eax。 –

+1

至於關於使用不同註冊表的評論,這部分是非常真實的,爲什麼我沒有真正upvote這個答案。與額外寄存器的混亂只發生,因爲我們碰巧使用將被破壞的寄存器。最好的解決方法是使用不同的解決方案。 –