关于ret的汇编代码

时间:2012-06-17 04:47:39

标签: assembly

我正在使用gdb调试我的代码,并遇到了这个问题。 gdb显示如下:

(gdb) ni
0x08048ca5 in getbufn ()
(gdb) disas 0x08048c98
Dump of assembler code for function getbufn:
0x08048c89 <+0>:     push   %ebp
0x08048c8a <+1>:     mov    %esp,%ebp
0x08048c8c <+3>:     sub    $0x208,%esp
0x08048c92 <+9>:     lea    -0x200(%ebp),%eax
0x08048c98 <+15>:    mov    %eax,(%esp)
0x08048c9b <+18>:    call   0x8048bf4 <Gets>
0x08048ca0 <+23>:    mov    $0x1,%eax
=> 0x08048ca5 <+28>:    leave  
0x08048ca6 <+29>:    ret    
End of assembler dump.
(gdb) p /x $ebp
$1 = 0x55683950
(gdb) p /x $esp
$2 = 0x55683748
(gdb) ni
0x08048ca6 in getbufn ()
(gdb) p /x $ebp
$3 = 0x4030201
(gdb) p /x $esp
$4 = 0x55683954
(gdb) x /1xw $esp
0x55683954:     0x55683750
(gdb) si
Cannot access memory at address 0x4030205
(gdb) 

0x08048ca6中的代码是“ret”,表示jmp(%esp),addl 0x4,%esp 所以我想知道为什么gdb的最后一句是“无法访问地址0x4030205的内存” 它应该在地址0x55683750中执行指令代码吗?

THX!

2 个答案:

答案 0 :(得分:1)

嗨 -

                     ; Enter subroutine: build stack frame
0x08048c89 <+0>:     push   %ebp            ; Save the old buffer pointer
0x08048c8a <+1>:     mov    %esp,%ebp       ; Save the current stack pointer
0x08048c8c <+3>:     sub    $0x208,%esp     ; Allocate space for local variables

0x08048c92 <+9>:     lea    -0x200(%ebp),%eax ; call "gets()" subroutine
0x08048c98 <+15>:    mov    %eax,(%esp)
0x08048c9b <+18>:    call   0x8048bf4 <Gets>

0x08048ca0 <+23>:    mov    $0x1,%eax       ; eax <= 1

=> 0x08048ca5 <+28>:    leave  ; we *think* we're leaving the subroutine...but
0x08048ca6 <+29>:    ret       ; in fact we crash at this point

结论:

“gets()”中的某些内容会破坏您的堆栈,因此无法从子例程返回。

建议:

不要使用“gets()”。这不安全。大多数编译器实际上 WARN 你不安全。使用“fgets()”(或输入字符串的任意数量的其他选择)代替:

http://cboard.cprogramming.com/c-programming/137352-gets-unsafe-method-alternatives.html

... IMHO

答案 1 :(得分:0)

“=&gt;”指向 about 执行的指令,在这种情况下是“离开”。并且“离开”定义为首先将esp设置为ebp,然后弹出ebp。将esp设置为ebp0x4030201后,一个错误的地址和一些看起来很可疑的地址就是从字节1,2,3,4中生成的,流行音乐失败。

您可能希望在调用ebp之前和之后查看Gets()的值。我的猜测是对Gets()的调用导致该寄存器被修改,这不应该发生,因为ebp通常是被调用者保存。

请注意,虽然使用512字节的堆栈缓冲区调用Gets()可能不可取,但在这种情况下,缓冲区溢出不会导致崩溃。缓冲区溢出可能会使ret在其他位置跳转,但不会导致ebp被修改。