x86 - 在实模式下通过 gdb 访问 $api 失败

标签 x86 gdb nasm ld real-mode

我正在尝试调试我使用 gdb 编写的 x86 引导加载程序。由于 gdb 似乎不能很好地处理 16 位实模式,所以我使用 gdb script其他人为此目的而写的。

我尝试调试的代码的最小示例如下所示(文件 asm/boot.asm):

bits 16

global _start

_start:
  ; zero DS
  xor ax, ax
  mov ds, ax

  ; TODO

sleep:
  jmp sleep

  times 510-($-$$) db 0 ; zero out rest of section
  dw 0xAA55             ; add boot signature (needed by qemu)

我执行以下命令来创建一个可调试的 elf 文件以及一个复制到虚拟软盘镜像开头的平面二进制文件:

nasm -i asm -f elf64 -g -F dwarf asm/boot.asm -o out/boot.o
ld -Ttext=0x7c00 -melf_x86_64 out/boot.o -o out/boot.elf
objcopy -O binary out/boot.elf out/boot.img
dd if=/dev/zero of=imgs/os.flp bs=512 count=1000
dd if=out/boot.img of=imgs/os.flp bs=512 count=1 conv=notrunc

我在 qemu 下运行此图像:

qemu-system-x86_64 -nographic -drive format=raw,file=imgs/os.flp,index=0,if=floppy -S -s &

并附加 gdb:

gdb out/boot.elf \
    -ex "target remote localhost:1234" \
    -x gdbinit_real_mode.txt \
    -ex "break _start" \
    -ex "continue"

其中 gdbinit_real_mode.txt 是链接脚本。

这实际上不起作用,因为脚本包含一个函数 compute_regs ,该函数将(除其他外)$rip 设置为 $cs * 16 + $eip 。我知道这样做是因为在实模式下内存是使用段+偏移寄存器来寻址的,但 gdb 本身并不知道这一点。但是,compute_regs 中的以下 gdb 命令因“无效转换”而失败(并且似乎实际上对 $eip 的任何访问都以这种方式失败):

set $rip = ((((unsigned long)$cs & 0xFFFF) << 4) + ((unsigned long)$eip & 0xFFFF)) & $ADDRESS_MASK

这是为什么?我该如何解决?我在 64 位 Linux 主机上使用 nasm 2.15.05qemu 5.1.0gdb 9.2

最佳答案

该脚本设计为在 GDB 以 32 位模式运行时使用。 GDB 假设 64 位代码,因为您使用 64 位 ELF 文件进行调试。由于这不是 64 位代码,您可以更改 NASM 的命令行以使用 -f elf32 而不是 -f elf64,然后使用 LD 选项 -melf_i386 而不是 -melf_x86_64。这样做应该会生成 32 位 ELF 可执行文件,并且脚本应该可以工作。

或者,如果您想在 64 位 ELF 中使用该脚本,您可能需要将 $eip 更改为 $rip

我还建议在通过 GDB 调试 32 位代码时使用 qemu-system-i386。如果您在尝试调试在 16 位模式下运行的 32 位 ELF 可执行文件时使用 qemu-system-x86_64,您可能会遇到更多问题。

关于x86 - 在实模式下通过 gdb 访问 $api 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64821954/

相关文章:

c++ - 导致除法溢出错误 (x86)

gdb - 在 MinGW 上的 GDB 中,如何让 Ctrl-C 停止程序?

c - 我们如何在Linux 2.6 中从保护模式切换到实模式?

assembly - 通过堆栈进行 32 位扩展乘法

c++ - 代码对齐会显着影响性能

assembly - 如何检测卷引导记录(分区引导扇区)中的保护模式?

c++ - 使用 gdb 将数组内容打印到文件

linux - 在宏 + linux 系统调用 (nasm) 中定义标签

c - 带有内联汇编段错误的程序,除非以函数调用为前缀

string - 为什么 GDB 认为我的 Fortran 字符串是 ~4GiB