bootloader代码应该如何选择反汇编模式?

How should the disassembly mode be chosen for bootloader code?

假设我有一个要调试的引导加载程序汇编代码,它使用 .code16.code32 来为 CPU 的不同模式定义代码,它在 运行 中。此引导加载程序适用的架构是 64 位 (x86) CPU.

现在在反汇编过程中应该使用什么模式(使用objdump、gdb等工具)? i8086i386x86-64?

根据我的理解和观察,我们应该根据我们正在分析的代码部分(.code16.code32)使用它们的组合,因为这给出了预期的结果(对我来说) .

例如:

.code16
mov %ax, %bx
mov %ecx, %edx

.code32
mov %eax, %ebx
mov %cx, %dx

这样编译:

$ as -o test.o test.S. #16-bit and 32-bit code packed in 64-bit elf, default 64 since host is 64-bit

16 位模式反汇编CPU。 16位代码段显示正常,32位代码段乱码

$ objdump -m i8086 -d test.o

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   89 c3                   mov    %ax,%bx
   2:   66 89 ca                mov    %ecx,%edx
   5:   89 c3                   mov    %ax,%bx
   7:   66 89 ca                mov    %ecx,%edx

正在以 32 位模式分析。现在32位的coe段被完美反汇编了,虽然16位的代码段乱七八糟

$ objdump -m i386 -d test.o

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   89 c3                   mov    %eax,%ebx
   2:   66 89 ca                mov    %cx,%dx
   5:   89 c3                   mov    %eax,%ebx
   7:   66 89 ca                mov    %cx,%dx

请确认策略是否完美,否则,请指正混合汇编代码(16、32、64位)反汇编时最好的方法是什么。

您设计的示例不包括可以更改模式的远跳转,因此反汇编是否有效取决于您希望 CPU 对其进行解码的模式。执行将继续通过两个块合并为一个模式。

例如,在Determine your language's version I show all 3 ways to disassemble that block of machine code; all 3 are equally valid and produce different results intentionally. (It's polyglot machine code like )


如果您在实际用例中确实有不同的代码块,大概您想要查看 16 位部分的 16 位反汇编,以及 32 位部分的 32 位反汇编.或者只是阅读源代码。 或者让你的 assembler 生成一个列表,比如 nasm -l /dev/stdout -fbin foo.asm. 然后你会根据什么模式为每个源代码行得到 "the machine code"你告诉 assembler 到 assemble for.

GAS 也可以使用 as -agcc -c -Wa,-a(-Wa 将额外的选项直接传递给 assembler)。

该清单仅包括十六进制机器代码和源代码行(包括注释),不包括 disassembly。因此,如果您使用 .byte 之类的技巧手动编码一条指令,您将看不到 CPU 将如何解释它。为此,请参阅 Ross 的回答或使用调试器。

$ as -a foo.s -o foo.o   # still creates an output file as normal
GAS LISTING foo.s                       page 1


   1                    .code16
   2 0000 89C3              mov %ax, %bx
   3 0002 6689CA           mov %ecx,   %edx  # comment
   4              
   5                    .code32
   6 0005 89C3            mov %eax, %ebx     # comment 1
   7 0007 6689CA          mov %cx, %dx       # comment 2

GAS LISTING foo.s                       page 2


NO DEFINED SYMBOLS

NO UNDEFINED SYMBOLS

左栏是地址。

(我修改了您的源代码以改变间距并添加注释,以仔细检查它只是转储源代码行,而不是反汇编。)

GAS 列表默认为标准输出,-ahls 列表选项 gas man page。没有 -h "high level source" 用于手写 asm 文件,该选项用于从编译器输出中生成列表,但这很好。列/分页有选项选项,例如 --listing-lhs-width=number


您还可以使用带有内置调试器的仿真器(如 BOCHS)在 CPU 当前处于 的模式下显示反汇编。 BOCHS 了解模式、实模式分段等。 这可能是确保真正执行正确指令的最佳选择。(如果 BOCHS 可以读取调试信息/源代码,您可能需要另一个 window 中的源代码。 )

反汇编程序无法知道什么是 16 位代码或 32 位代码,因此您需要明确地告诉它。例如 objdump:

> objdump -m i8086 --stop-address 0x5 -D test.o

test.o:     file format pe-i386


Disassembly of section .text:

00000000 <.text>:
   0:   89 c3                   mov    %ax,%bx
   2:   66 89 ca                mov    %ecx,%edx

> objdump -m i386 --start-address 0x5 -D test.o

test.o:     file format pe-i386


Disassembly of section .text:

00000005 <.text+0x5>:
   5:   89 c3                   mov    %eax,%ebx
   7:   66 89 ca                mov    %cx,%dx
   a:   90                      nop
   b:   90                      nop

由于您将其与引导加载程序一起使用,因此您可能还想使用 --adjust-vma 选项:

> objdump -m i8086 --adjust-vma 0x7c00 --stop-address 0x7c05 -D t457.o

t457.o:     file format pe-i386


Disassembly of section .text:

00007c00 <.text>:
    7c00:       89 c3                   mov    %ax,%bx
    7c02:       66 89 ca                mov    %ecx,%edx

如果您不构建二进制引导加载程序,那么您可能需要考虑将不同的代码类型放入不同的部分,以便于 select 反汇编哪一部分(-j 选项objdump).

其他命令行反汇编程序有类似这些的选项,例如 ndisasm 的 -k 选项。