我在汇编程序中编写了一个小内核。我在QEMU运行它并且遇到一些bug问题。现在我想用dbg调试内核。所以我这样组装起来了:
$ nasm -g -f elf -o myos.elf myos.asm
$ objcopy --only-keep-debug myos.elf myos.sym
$ objcopy -O binary myos.elf myos.bin
然后我在QEMU中运行:
$ qemu-system-i386 -s -S myos.bin
然后我用gdb连接:
$ gdb
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
symbol-file myos.sym
Reading symbols from /home/sven/Projekte/myos/myos.sym...done.
我的内核中有一个名为welcome
的标签,指向一个字符串。测试时,我试着查看该字符串,结果如下:
(gdb) x/32b welcome
0x1e <welcome>: 0x00 0xf0 0xa5 0xfe 0x00 0xf0 0x87 0xe9
0x26: 0x00 0xf0 0x6e 0xc9 0x00 0xf0 0x6e 0xc9
0x2e: 0x00 0xf0 0x6e 0xc9 0x00 0xf0 0x6e 0xc9
0x36: 0x00 0xf0 0x57 0xef 0x00 0xf0 0x6e
标签的定义如下:
welcome: db "System started. Happy hacking!", 10, 0
所以你可以看到,gdb假装以null字节开始欢迎启动,但根据定义它不是。但是内核正确地使用了标签,因此它看起来不像是我的代码的问题。检查内存的其他部分与加载的内核完全不匹配。
有没有人知道为什么虚拟机的内存与加载的内核不匹配,而机器仍然具有核心行为?
答案 0 :(得分:3)
qemu-system-i386
在运行时在地址0x7c00
处加载x86引导扇区图像文件的第一个字节。myos.elf
,myos.sym
)错误地通知GDB代码将在地址0加载。因此,GDB认为welcome
处于0x1e
,而实际上是0x7c1e
在0x7c00
。x/32xb (welcome + 0x7c00)
添加到GDB中的所有地址会起作用但是很笨拙:welcome
<强> boot.asm 强>
; 'boot.asm' ; loaded by BIOS [bits 16] global main main: mov di, welcome print_welcome: mov ah, 0x0e mov al, [di] int 0x10 inc di cmp byte [di], 0 jne print_welcome hlt db "XXXXXXXXXXXXXX" ; some padding to make welcome appear at 0x1e welcome: db "System started. Happy hacking!", 10, 0 ; x86 boot sector padding and signature ; NOTE: intentionally commented out. Will be added by linker script ;times 510 - ($ - $$) db 0x00 ;db 0x55, 0xAA
<强> x86的boot.ld 强>
ENTRY(main); SECTIONS { . = 0x7C00; .text : AT(0x7C00) { _text = .; *(.text); _text_end = .; } .data : { _data = .; *(.bss); *(.bss*); *(.data); *(.rodata*); *(COMMON) _data_end = .; } .sig : AT(0x7DFE) { SHORT(0xaa55); } /DISCARD/ : { *(.note*); *(.iplt*); *(.igot*); *(.rel*); *(.comment); /* add any unwanted sections spewed out by your version of gcc and flags here */ } }
使用以下代码构建代码:
nasm -g -f elf -F dwarf boot.asm -o boot.o cc -nostdlib -m32 -T x86-boot.ld -Wl,--build-id=none boot.o -o boot objcopy -O binary boot boot.good.bin
<强>转储welcome.gdb 强>
target remote localhost:1234 symbol-file boot monitor system_reset # run until hlt instruction, address obtained through disassembly until *0x7c0f x/32xb welcome monitor quit disconnect quit
示例会话:
$ qemu-system-x86_64 -s -S boot.good.bin & $ gdb -q -x dump-welcome.gdb 0x0000fff0 in ?? () main () at boot.asm:16 16 hlt 0x7c1e : 0x53 0x79 0x73 0x74 0x65 0x6d 0x20 0x73 0x7c26: 0x74 0x61 0x72 0x74 0x65 0x64 0x2e 0x20 0x7c2e: 0x48 0x61 0x70 0x70 0x79 0x20 0x68 0x61 0x7c36: 0x63 0x6b 0x69 0x6e 0x67 0x21 0x0a 0x00
您转储的32个字节中的大多数都具有≥0.080的值,即它们不是可打印的ASCII字符。这提出了一个问题:我真的倾销了正确的地址吗?
welcome
消息的十六进制转储应为:
$ python -c 's = "System started. Happy hacking!"; print [hex(ord(x)) for x in s ]' ['0x53', '0x79', '0x73', '0x74', '0x65', '0x6d', '0x20', '0x73', '0x74', '0x61', '0x72', '0x74', '0x65', '0x64', '0x2e', '0x20', '0x48', '0x61', '0x70', '0x70', '0x79', '0x20', '0x68', '0x61', '0x63', '0x6b', '0x69', '0x6e', '0x67', '0x21']
使用GDB在内存中搜索{{1}}消息也会显示正确的地址:
(gdb) find 0, 0xffff, 'S', 'y', 's', 't' 0x7c1e