1

我正在用汇编程序编写一个小内核。我在 QEMU 中运行它并且遇到了一些问题。现在我想用 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 假装 Welcome 以空字节开头,但根据定义它不是。但是内核正确使用了标签,因此我的代码似乎没有问题。检查内存的其他部分与加载的内核完全不匹配。

有谁知道为什么虚拟机的内存与加载的内核不匹配,而机器仍然正常运行?

4

1 回答 1

4

解释

  • qemu-system-i386 0x7c00在运行时将 x86 引导扇区映像文件的第一个字节加载到地址
  • 您的 ELF 文件 ( myos.elf, myos.sym) 错误地通知 GDB 代码将在地址 0 加载。因此 GDB 认为welcome是 at0x1e而它实际上是 at 0x7c1e
  • 添加0x7c00到 GDB 中的所有地址都可以,但很笨拙:x/32xb (welcome + 0x7c00)
  • 更好的解决方案是创建一个具有正确地址的 ELF 文件。

解决方案

引导程序

; 'boot.asm'
; 由 BIOS 加载

[位 16]

全球主要
主要的:
mov di,欢迎
打印欢迎:
mov 啊,0x0e
移动,[di]
整数 0x10
公司二
cmp 字节 [di], 0
jne print_welcome
hlt

分贝“XXXXXXXXXXXXXX”;一些填充以使欢迎出现在 0x1e
Welcome: db "系统已启动。黑客攻击愉快!", 10, 0

; x86 引导扇区填充和签名
; 注意:故意注释掉。将由链接描述文件添加
;times 510 - ($ - $$) db 0x00
;db 0x55, 0xAA

x86-boot.ld

条目(主要);
部分
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        _text = .;
        *(。文本);
        _text_end = .;
    }
    。数据 :
    {
        _data = .;
        *(.bss);
        *(.bss*);
        *(。数据);
        *(.rodata*);
        *(常见的)
        _data_end = .;
    }
    .sig : AT(0x7DFE)
    {
        短(0xaa55);
    }
    /丢弃/ :
    {
        *(。笔记*);
        *(.iplt*);
        *(。我有*);
        *(.rel*);
        *(。评论);
/* 在此处添加由您的 gcc 版本和标志喷出的任何不需要的部分 */
    }
}

使用以下代码构建代码:

nasm -g -f elf -F 矮人 boot.asm -o boot.o
cc -nostdlib -m32 -T x86-boot.ld -Wl,--build-id=none boot.o -o boot
objcopy -O 二进制启动 boot.good.bin

转储-welcome.gdb

目标远程本地主机:1234
符号文件引导
监控 system_reset
# 运行到hlt指令,反汇编得到地址
直到 *0x7c0f
x/32xb 欢迎

监控退出
断开
退出

示例会话:

$ qemu-system-x86_64 -s -S boot.good.bin &
$ gdb -q -x 转储-welcome.gdb
0x0000fff0 在 ?? ()
主 () 在 boot.asm:16
16 小时
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 个字节中的大多数值 ≥ 0x80,即它们不是可打印的 ASCII 字符。这就提出了一个问题:真的倾销了正确的地址吗?

您的消息的十六进制转储welcome应该是:

$ python -c 's = "系统已启动。黑客攻击愉快!"; 打印 [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 在内存中搜索welcome消息也会显示正确的地址:

(gdb) 找到 0, 0xffff, 'S', 'y', 's', 't'
0x7c1e

延伸阅读

于 2014-03-12T10:35:01.683 回答