2012-10-14 76 views
2

我試圖學習程序集並發現當試圖從堆棧推送/彈出數據時,我總是收到段錯誤。我已經閱讀了一些指南,並知道堆棧如何工作以及如何使用堆棧;但不知道爲什麼我不斷收到錯誤。當使用堆棧時,程序集不斷收到seg錯誤

有人可以幫忙嗎?

segment .data 
     myvar: db "hello world", 0xA0, 0 
     myvarL: equ $-myvar 

segment .text 
     global _start 

_start: 
     push ebp 
     mov ebp, esp 
     push myvarL 
     push myvar 
     call _hworld 

     mov eax, 1 
     mov ebx, 0 
     int 0x80 

_hworld: 
     mov eax, 4 
     mov ebx, 1 
     mov ecx, [ebp+4] 
     mov edx, [ebp+8] 
     pop ebp 
     int 0x80 
     ret 

我假設+4是32位,那麼+8是64位。我不清楚爲什麼在我讀過的一些指南中這樣做。我會假設myvar是13個字節?

這是錯誤:

$ ./pushpop 
Segmentation fault 
+2

你真的確認你第一次調用_hworld,然後再次運行呢?即程序的exit()在哪裏? –

+0

4/8的事情可能是由於棧對齊。我認爲我說的一般而言,堆棧指針保持與機器字長對齊。所以只能移動32或64位塊。 – lynks

回答

0

我的代碼被拒絕的原因是因爲我沒有在輸入_hworld段時保存esp,並且在離開時沒有恢復它。

這是新的工作代碼:

segment .data 
    myvar: db "hello world", 0x0A, 0 
    myvarL: equ $-myvar 
    myvar2: db "super bad test", 0x0A, 0 
    myvar2L: equ $-myvar2 

segment .text 
    global _start 

_start: 
    push myvarL ; store myvarL on the stack 
    push myvar ; store myvar on the stack 
    call _hworld 

    push myvar2L ; store myvar2L on the stack 
    push myvar2 ; store myvar2 on the stack 
    call _hworld2 

    mov eax, 1 
    mov ebx, 0 
    int 0x80 

_hworld: 
    push ebp ; store the current value of ebp on the stack (hence +8) 
    mov ebp, esp ; store current esp in ebp 

    mov eax, 4 
    mov ebx, 1 
    mov ecx, [ebp+8] ; +4 is old ebp 
    mov edx, [ebp+12] 
    int 0x80 

    mov esp, ebp ; restore ebp to esp 
    pop ebp  ; restore ebp 
    ret 

_hworld2: 
    push ebp ; store old ebp on the stack 
    mov ebp, esp ; store esp in ebp 

    mov eax, 4 
    mov ebx, 1 
    mov ecx, [ebp +8] ; +4 is old ebp 
    mov edx, [ebp +12] 
    int 0x80 

    mov esp, ebp ; restore ebp to esp 
    pop ebp  ; restore ebp 
    ret 
+0

您似乎將變量myvarXX保留在堆棧中。 –

0

只是一個想法

segment .data 
    myvar: db "hello world", 0xA0, 0 
    myvarL: equ $-myvar 
segment .text 
    global _start 
_start: 
    push ebp 
    mov ebp, esp 
    push myvarL 
    push myvar 
    call _hworld 
    pop ebp   // 
// 
    mov eax,1 
    mov ebx,0 
    int 80h ; // exit 

_hworld: 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, [ebp+4] 
    mov edx, [ebp+8] 
// pop ebp    <-- this will pop the return address 
    int 0x80 
    ret 
+0

不是這樣。或者這只是其中的一部分。 'ebp + 4/8'將堆棧指向'_start'的返回地址和參數。 'ebp-4/8'字體向下推送到'myvarL'和'myvar'。 –

0
_start: 
     push ebp 
     mov ebp, esp ; ebp points to its old value on the stack 
        ; ebp + 4 points to the return address from _start 
        ; ebp + 8 points to 1st on-stack parameter to _start 

     push myvarL ; ebp - 4 points to myvarL on stack 
     push myvar ; ebp - 8 points to myvar on stack 
     call _hworld 

;  are we going to now execute _hworld without a call??? 
;  vvvv 

_hworld: 
     mov eax, 4 
     mov ebx, 1 
     mov ecx, [ebp+4] ; ebp + 4 points to return address from _start 
     mov edx, [ebp+8] ; ebp + 8 points to 1st on-stack parameter to _start 
;     ^^^^ why??? 

順便說一句,我不知道冒號就在這裏:myvarL: equ $-myvar,除非,當然,push myvarL原來是push 13

哦,這條線:

 pop ebp 

打算從_hworld偷返回地址,所以下面ret將從堆棧返回地址獲取myvar並嘗試執行myvar的代碼。

+0

是的,彈出ebp會彈出返回地址 –

+0

是的,失去'pop ebp',它應該工作。你仍然會在堆棧上有一些陷阱,但是sys_exit不應該在意。使用'[esp + 4]'等來查找您的參數。 –