ブレークポイントを追加するときに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
)の最初の行にブレークポイントを設定しようとします。
$ 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
注釈を追加しようとしましたが、それは私の問題を解決しませんでした。
アセンブラで作成されたDWARF情報はそれほど信頼できません。これは一般にコンパイラによって生成されます –
GDBはデフォルトでスタックフレームのプロローグコードを検出しています。そのようなプロローグコードを見つけると、その後ろにブレークポイントが置かれます。この場合、ブレークポイントは11行目から自動的に14行目に移動します。ブレークしたい命令の正確なアドレスがわかっている場合は、 'b * 0x8048074'(または実際に停止したいアドレス)を実行できます。フロントアスタリスクは、デバッガがプロローグコードを自動的にスキップするのを防ぎます。 –
関連する(正確には重複しない)質問はこちら:https://stackoverflow.com/questions/25545994/how-does-gdb-determine-the-address-to-break-at-when-you-do-break関数名 –