【问题标题】:Assembly keep getting seg fault when working with stack使用堆栈时组件不断出现段错误
【发布时间】:2012-10-14 16:23:44
【问题描述】:

我正在尝试学习汇编,并发现在尝试从堆栈中推送/弹出数据时,我不断收到段错误。我已经阅读了一些指南并且知道堆栈是如何工作的以及如何使用堆栈;但不知道为什么我总是收到错误。

有人可以帮忙吗?

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

【问题讨论】:

  • 你确定你先调用 _hworld 然后再运行它吗?即你的程序的 exit() 在哪里?
  • 4/8 的事情可能是由于堆栈对齐。我认为我说得对,一般来说,堆栈指针与机器字长保持对齐。所以只会在 32 或 64 位块中移动。

标签: assembly x86 stack


【解决方案1】:

只是一个想法

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

【讨论】:

  • 不是这样的。或者这只是其中的一部分。 ebp+4/8 向上指向堆栈,指向_start 的返回地址和参数。 ebp-4/8 向下栈,推送到 myvarLmyvar
【解决方案2】:
_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作为代码执行。

【讨论】:

  • 是的,pop ebp 会弹出返回地址
  • 是的,丢掉pop ebp,它应该可以工作。您仍然会在堆栈上有些杂物,但 sys_exit 不应该在意。使用[esp + 4] 等查找您的参数。
【解决方案3】:

我的代码出现段错误的原因是因为我在进入 _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

【讨论】:

  • 您似乎将变量 myvarXX 留在了堆栈中。
猜你喜欢
  • 2021-01-17
  • 2021-12-03
  • 2019-09-30
  • 2015-02-14
  • 1970-01-01
  • 2021-08-05
  • 2013-04-16
  • 1970-01-01
相关资源
最近更新 更多