如何在 16 位模式下使用 GDB?
How to use GDB in 16-bit mode?
我有以下代码,我试图在其中实现一个使用 BIOS 函数打印字符串的函数:
int printString(char* string)
{
int i = 0;
while (*(string + i) != '[=10=]')
{
char al = *(string + i);
char ah = 0xe;
int ax = ah * 256 + al;
interrupt(0x10,ax,0,0,0);
i++;
}
return i;
}
函数中断在汇编中实现。它调用第一个参数给出的适当的 BIOS 中断,其余参数分别包含 ax、bx、cx 和 dx 寄存器的内容:
.global _interrupt
_interrupt:
push bp
mov bp, sp
push si
push ds
mov ax, #0x100
mov ds, ax
mov ax, [bp + 0x4]
mov si, #intr
mov [si + 1], al
pop ds
mov ax, [bp + 0x6]
mov bx, [bp + 0x8]
mov cx, [bp + 0xa]
mov dx, [bp + 0xc]
intr: int #0x0
pop si
pop bp
ret
因为我使用 BIOS 中断,所以我使用 16 位模式编译这段代码。我使用了以下命令:
bcc -ansi -c -o printString.o printString.c
我想在 GDB 中测试此代码,但是当我尝试使用以下命令将此 printString.o 文件加载到 gdb 中时:
gdb printString.o
我收到以下错误:
"/home/kern/printString.o":不是可执行格式:无法识别文件格式
我还尝试使用以下方法将 GDB 更改为 16 位格式:
set architecture i8086
但是这个错误还是来了。如何将 16 位代码加载到 GDB 中?
正如 Jester 在评论中所说,您不能 运行 带有 gdb
的目标文件。
并且您不能 运行 16 位可执行文件或带有 gdb
的 16 位汇编代码。您必须使用 qemu
to run your code on an emulated CPU and connect to it using gdb
, or you can use dosbox
之类的东西才能 运行 您的代码,并在 DOS 上使用调试程序。请记住,使用 BIOS 中断在现代 OS 上是错误的,例如 Linux,因为在启动时这些操作系统会禁用 BIOS 中断。
最小 QEMU 示例
qemu-system-i386 -hda main.img -S -s &
gdb -ex 'target remote localhost:1234' \
-ex 'set architecture i8086' \
-ex 'break *0x7c00' \
-ex 'continue'
其中 main.img
是 boot sector.
break *0x7c00
:第一条指令不会是您的引导扇区,而是 0x0000fff0
执行 BIOS 设置,see also。所以我们使用它从引导扇区加载到的位置开始。
set architecture i8086
:对于常规的 ELF 可执行文件,GDB 可以根据 headers 决定体系结构。但是对于原始引导扇区,没有这样的元数据,所以我们必须告诉它。
另请参阅:
- 如何获取源代码级调试信息:How to do source level debugging of x86 code with GDB inside QEMU?
- 类似问题:Low level qemu based debugging || Debug qemu with gdb || Debugging bootloader with gdb in qemu
- 一些更好的想法:https://whosebug.com/a/32960272/895245
- 如何跨过
int
:How to step over interrupt calls when debugging a bootloader/bios with gdb and QEMU?
我有以下代码,我试图在其中实现一个使用 BIOS 函数打印字符串的函数:
int printString(char* string)
{
int i = 0;
while (*(string + i) != '[=10=]')
{
char al = *(string + i);
char ah = 0xe;
int ax = ah * 256 + al;
interrupt(0x10,ax,0,0,0);
i++;
}
return i;
}
函数中断在汇编中实现。它调用第一个参数给出的适当的 BIOS 中断,其余参数分别包含 ax、bx、cx 和 dx 寄存器的内容:
.global _interrupt
_interrupt:
push bp
mov bp, sp
push si
push ds
mov ax, #0x100
mov ds, ax
mov ax, [bp + 0x4]
mov si, #intr
mov [si + 1], al
pop ds
mov ax, [bp + 0x6]
mov bx, [bp + 0x8]
mov cx, [bp + 0xa]
mov dx, [bp + 0xc]
intr: int #0x0
pop si
pop bp
ret
因为我使用 BIOS 中断,所以我使用 16 位模式编译这段代码。我使用了以下命令:
bcc -ansi -c -o printString.o printString.c
我想在 GDB 中测试此代码,但是当我尝试使用以下命令将此 printString.o 文件加载到 gdb 中时:
gdb printString.o
我收到以下错误:
"/home/kern/printString.o":不是可执行格式:无法识别文件格式
我还尝试使用以下方法将 GDB 更改为 16 位格式:
set architecture i8086
但是这个错误还是来了。如何将 16 位代码加载到 GDB 中?
正如 Jester 在评论中所说,您不能 运行 带有 gdb
的目标文件。
并且您不能 运行 16 位可执行文件或带有 gdb
的 16 位汇编代码。您必须使用 qemu
to run your code on an emulated CPU and connect to it using gdb
, or you can use dosbox
之类的东西才能 运行 您的代码,并在 DOS 上使用调试程序。请记住,使用 BIOS 中断在现代 OS 上是错误的,例如 Linux,因为在启动时这些操作系统会禁用 BIOS 中断。
最小 QEMU 示例
qemu-system-i386 -hda main.img -S -s &
gdb -ex 'target remote localhost:1234' \
-ex 'set architecture i8086' \
-ex 'break *0x7c00' \
-ex 'continue'
其中 main.img
是 boot sector.
break *0x7c00
:第一条指令不会是您的引导扇区,而是0x0000fff0
执行 BIOS 设置,see also。所以我们使用它从引导扇区加载到的位置开始。set architecture i8086
:对于常规的 ELF 可执行文件,GDB 可以根据 headers 决定体系结构。但是对于原始引导扇区,没有这样的元数据,所以我们必须告诉它。
另请参阅:
- 如何获取源代码级调试信息:How to do source level debugging of x86 code with GDB inside QEMU?
- 类似问题:Low level qemu based debugging || Debug qemu with gdb || Debugging bootloader with gdb in qemu
- 一些更好的想法:https://whosebug.com/a/32960272/895245
- 如何跨过
int
:How to step over interrupt calls when debugging a bootloader/bios with gdb and QEMU?