2

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 の最後の文が "Cannot access memory at address 0x4030205" なのか不思議です。アドレス 0x55683750 の命令コードを実行することになっていますか?

どうも!

4

2 に答える 2

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()」を使用しないでください。安全ではありません。ほとんどのコンパイラは、実際には安全ではないことを警告します代わりに "fgets()" (または文字列を入力するためのその他の任意の数の代替手段) を使用します。

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

私見では...

于 2012-06-17T05:03:17.653 に答える
0

「=>」は、実行しようとしている命令(この場合は「leave」)を指します。そして、「leave」は、最初にに設定され、次にpopに設定されるように定義されてespebpますebp。(つまり、不正なアドレスであり、バイト1、2、3、4から生成されたように見えるもの)にesp設定されると、ポップは失敗します。ebp0x4030201

ebpの呼び出しの前後の値を確認することをお勧めしますGets()。私の推測では、を呼び出すGets()とそのレジスタが変更されますが、これebpは通常のcallee-saveのようには発生しないはずです。

512バイトのスタックバッファを使用して呼び出すGets()ことはお勧めできませんが、この場合、バッファオーバーランがクラッシュの原因であるとは思われないことに注意してください。retバッファオーバーランは、どこか別の場所にジャンプする可能性がありebpますが、変更されることはありません。

于 2013-02-13T23:20:46.670 に答える