2017-10-22 4 views
2

ブレークポイントを追加するときにgdbが行番号を間違ったメモリアドレスにマッピングしているという問題が発生しています。x86アセンブリ関数のGDBブレークポイントが間違ったアドレスに設定されているのはなぜですか?

次のx86 Linuxアセンブリプログラムは "hello"を出力します。

/* hello.s */ 

    .section .data 
str: 
    .ascii "hello\n" 
    strlen = . - str 

    .section .text 

print: 
    pushl %ebp 
    movl %esp, %ebp 
    pushl %ebx 
    movl $4, %eax 
    movl $1, %ebx 
    movl $str, %ecx 
    movl $strlen, %edx 
    int $0x80 
    popl %ebx 
    movl %ebp, %esp 
    popl %ebp 
    ret 

    .globl _start 
_start: 
    call print 
    movl $1, %eax 
    movl $0, %ebx 
    int $0x80 

デバッグ情報でコンパイルしてリンクします。

$ as -g --32 -o hello.o hello.s 
$ ld -m elf_i386 -o hello hello.o 

次に、GDBで、Iは、ライン11上の印刷機能(pushl %ebp)の最初の行にブレークポイントを設定しようとします。

0x8048078で
$ gdb ./hello 
(gdb) break hello.s:11 

ブレークポイント3に:ファイルhello.s、ライン11

出力に示されるように、ブレークポイントは、アドレス0x8048078に設定されています。しかし、それは間違ったアドレスです。プログラムをgdbで実行すると、14行目でブレークします。11行目のアドレスは0x8048074で、gdbのinfoコマンドで確認できます。

(gdb) info line hello.s:11 

"hello.s" の11行目は、アドレス0x8048074から始まり、0x8048075で終了。

印刷命令にブレークポイントを設定すると、ブレークポイントが直接動作します(ブレークポイントは11行目のアドレス0x8048074に設定されます)。

11行目にブレークポイントを追加すると、gdbは上記のinfoコマンドを使用して出力と同じアドレスを使用しません。これは、私が打破しようとしているメモリアドレスです。

gdb 7.11.1と8.0.1の両方で同じ動作が発生しています。私は.type print,@function注釈を追加しようとしましたが、それは私の問題を解決しませんでした。

+0

アセンブラで作成されたDWARF情報はそれほど信頼できません。これは一般にコンパイラによって生成されます –

+1

GDBはデフォルトでスタックフレームのプロローグコードを検出しています。そのようなプロローグコードを見つけると、その後ろにブレークポイントが置かれます。この場合、ブレークポイントは11行目から自動的に14行目に移動します。ブレークしたい命令の正確なアドレスがわかっている場合は、 'b * 0x8048074'(または実際に停止したいアドレス)を実行できます。フロントアスタリスクは、デバッガがプロローグコードを自動的にスキップするのを防ぎます。 –

+1

関連する(正確には重複しない)質問はこちら:https://stackoverflow.com/questions/25545994/how-does-gdb-determine-the-address-to-break-at-when-you-do-break関数名 –

答えて

4

どのようにデフォルトで

を来る、GDBは、過去の関数は、関数にブレークポイントを設定プロローグ、または機能が起動している行をスキップしようとします。

これは、通常はパラメータ設定に関心がないので、Cの開発者が欲しいものです。

他にも必要な場合は、b *addressまたはb &printを使用して、GDBの通常の処理を防止します。

関連する問題