当前位置:  开发笔记 > 编程语言 > 正文

在QEMU中诊断引导加载程序代码?

如何解决《在QEMU中诊断引导加载程序代码?》经验,为你挑选了1个好方法。

在QEMU中诊断引导加载程序代码?

我试图创建一个最小的“引导程序代码”,该代码打印字符“ A”,然后停止。

我为此编写了以下C ++程序

#include 
#include 
#include 

int main(int argc, char** argv)
{
  /*
   * If I run these code directly in Windows, it crashes, for I believe Windows 
   * do not allow accessing the BIOS directly, that make sense
   * 
   * But I can compile a binary, then I can use the debugger to view what machine code
   * does these correspond to, and build to boot program!
   */
  /*
  __asm
  {
    mov ah, 0x0e
    mov al, 0x41
    mov bx, 15
    int 0x10
    hlt
lp: jmp lp   
  }
   */
  int disk_length = 80 * 18 * 512 * 2;
  char* disk = (char*)calloc(disk_length, sizeof(char));

  const char program[] =
  {
    0xb4, 0x0e,             //     mov ah, 0EH
    0xb0, 0x41,             //     mov al, 41H
    0x66, 0xbb, 0x0f, 0x00, //     mov bx, 0FH
    0xcd, 0x10,             //     int 10H
    0xf4,                   //     hlt
    0xeb, 0xfe              // lp: jmp lp
  };
  const char boot_signature[] = {0x55, 0xAA};

  const int program_length = _countof(program);
  const int boot_signature_length = _countof(boot_signature);

  // Be careful with file mode
  FILE* imgFile = fopen("disk.img", "wb");

  memcpy(disk, program, program_length);
  memcpy(disk + 510, boot_signature, boot_signature_length);

  int written = 0;
  while (written < disk_length)
  {
    written += fwrite(disk + written, sizeof(char), disk_length - written, imgFile);
  }
  fclose(imgFile);

  return 0;
}

首先,我在未注释内联程序集的情况下运行了代码。在调试器中,我派生了操作码,并确定操作码与源代码中的操作码匹配。接下来,我运行带有注释的内联程序集的代码,然后生成了一个img文件。我使用二进制编辑器查看内容,并确保其外观符合我的期望。最后,我运行了qemu-system-i386.exe -fda disk.img,我期望引导加载程序显示大写的“ A”,但是什么也没显示。

现在我有两个问题:

1.)我的代码有什么问题?2.)我如何诊断?



1> Michael Petc..:

问题似乎是以下指令序列:

0x66, 0xbb, 0x0f, 0x00, //     mov bx, 0FH
0xcd, 0x10,             //     int 10H

实模式下的操作数前缀0x66将指令解码为32位寄存器(在这种情况下),然后将使用4个字节对立即数进行编码。当然,这会将int 10h用作数据的一部分mov。因此,您的指令真正要做的是:

0x66, 0xbb, 0x0f, 0x00, 0xcd, 0x10,  // mov ebx,0x10cd000f

然后是通常显示的hltjmp指令。在以16位实模式为目标(预期在8086/8088上运行)的代码中,您根本不需要使用此类前缀。您的代码应该简单地排除前缀,如下所示:

0xbb, 0x0f, 0x00,       //     mov bx, 0FH
0xcd, 0x10,             //     int 10H

您可以使用了解16位指令的反汇编disk.img程序来反汇编文件。NDISASM是可以处理16位代码的很好的反汇编程序,它是NASM程序(Netwide汇编程序)的一部分。NASM可用于Windows。NDISASM将被安装并可以通过以下方式运行:

ndisasm -b16 disk.img

这将尝试解码disk.img为16位(-b16)二进制。您可能会发现字节翻译的指令是什么,什么地方出错了。

您也可以尝试使用QEMU中的远程调试功能,并使用GDB调试器逐步执行代码。我不在Windows上运行QEMU,所以不知道它是否具有远程调试支持。


您可以考虑使用可用于生成适合在引导加载程序中使用的16位8086/8088代码的汇编程序(例如NASM),而不是像现在那样编写引导加载程序。关于Stackoverflow的许多问题和答案表明如何使用NASM创建引导加载程序。


嗯,是的。同时,我[在GNU binutils的版本上进行了扩展](http://stackoverflow.com/a/34424194/2171120)在其他地方,它也包含一些指向`ndisasm`的指针;当然,“随操作系统附带”这一论点毫无意义,因为其中一个都需要下载。(在DOS上,我本人出于这种目的使用`debug.com`或Borland的Turbo Debugger,前者随MS-DOS 3.30A一起提供。)
推荐阅读
个性2402852463
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有