如何拆卸16位x86引导扇区code在与GDB英寸×/ I $电脑和QUOT ;?它被视为32位 [英] How to disassemble 16-bit x86 boot sector code in GDB with "x/i $pc"? It gets treated as 32-bit

查看:361
本文介绍了如何拆卸16位x86引导扇区code在与GDB英寸×/ I $电脑和QUOT ;?它被视为32位的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,具有引导扇区BIOS版画 A 屏幕 main.asm中

For example, with a boot sector that BIOS prints a to the screen main.asm:

org 0x7c00
bits 16
cli
mov ax, 0x0E61
int 0x10
hlt
times 510 - ($-$$) db 0
dw 0xaa55

然后:

nasm -o main.img main.asm
qemu-system-i386 -hda main.img -S -s &
gdb -ex 'target remote localhost:1234' \
    -ex 'break *0x7c00' \
    -ex 'continue' \
    -ex 'x/3i $pc'

我得到:

0x7c00:      cli    
0x7c01:      mov    $0x10cd0e61,%eax
0x7c06:      hlt 

所以它看起来像 MOV AX,0x0E61 是PTED为32位 MOV%EAX 吃掉了下一条指令 INT为0x10 数据。

So it looks like the mov ax, 0x0E61 was interpreted as a 32-bit mov %eax and ate up the next instruction int 0x10 as data.

我怎么能告诉GDB,这是16位code?

How can I tell GDB that this is 16-bit code?

另请参阅:

  • in 2007 a GDB dev replied "use objdump" https://www.sourceware.org/ml/gdb/2007-03/msg00308.html as explained at How do I disassemble raw x86 code? Maybe it was implemented meantime?
  • superset: Using GDB in 16-bit mode
  • similar, but the OP got an error there, so maybe it is something else? How can I disassembly win16 with GDB

推荐答案

随着小丑正确的评论所指出的,你只需要使用集架构i8086 使用时 GDB ,以便它知道要承担16位的8086指令格式。您可以了解gdb的目标这里

As Jester correctly pointed out in a comment, you just need to use set architecture i8086 when using gdb so that it knows to assume 16-bit 8086 instruction format. You can learn about the gdb targets here.

我加入这个作为一个答案,因为它太硬的评论,说明。如果汇编和链接的东西分开,你可以生成然后通过 GDB 可用于提供即使在对16位code远程进行源代码级调试的调试信息。要做到这一点,我们稍微修改你的汇编文件:

I'm adding this as an answer because it was too hard to explain in a comment. If you assemble and link things separately you can generate debug information that can then be used by gdb to provide source level debugging even when done remotely against 16-bit code. To do this we modify your assembly file slightly:

;org 0x7c00    - remove as it may be rejected when assembling
;                with elf format. We can specify it on command
;                line or via a linker script.
bits 16

; Use a label for our main entry point so we can break on it
; by name in the debugger
main:
    cli
    mov ax, 0x0E61
    int 0x10
    hlt
    times 510 - ($-$$) db 0
    dw 0xaa55

我添加了一些意见,以确定所做的一些简单的改变。现在,我们可以像使用这些命令来组装我们的文件,以便它包含dwarf格式的调试输出。我们将其链接到最终的ELF映像。这个小精灵的图像可以通过 GDB 用于符号调试。然后,我们可以ELF格式转换为平板二进制 objcopy把

I've added some comments to identify the trivial changes made. Now we can use commands like these to assemble our file so that it contains debug output in the dwarf format. We link it to a final elf image. This elf image can be used for symbolic debugging by gdb. We can then convert the elf format to a flat binary with objcopy

nasm -f elf32 -g3 -F dwarf main.asm -o main.o
ld -Ttext=0x7c00 -melf_i386 main.o -o main.elf
objcopy -O binary main.elf main.img

qemu-system-i386 -hda main.img -S -s &
gdb main.elf \
        -ex 'target remote localhost:1234' \
        -ex 'set architecture i8086' \
        -ex 'layout src' \
        -ex 'layout regs' \
        -ex 'break main' \
        -ex 'continue'

我做了一些细微的变化。我用的是 main.elf 文件(symblic信息)启动时 GDB

I've made some minor changes. I use the main.elf file (with symblic information) when starting up gdb.

我还添加了一些有用的布局的组装code和,可能使在命令行上更容易调试寄存器。我也打破(不是地址)。从我们的汇编文件的源$ C ​​$ C也应该出现,因为调试信息。您可以使用布局ASM 而不是布局SRC 如果您preFER看到原始的组装。

I also add some more useful layouts for assembly code and the registers that may make debugging on the command line easier. I also break on main (not the address). The source code from our assembly file should also appear because of the debugging information. You can use layout asm instead of layout src if you prefer to see the raw assembly.

此的一般的概念可以通过的 NASM 的支持其他格式和工作的 LD 的其他平台。 ELF32 elf_i386 以及调试类型将不得不进行修改的具体环境。我的目标样本能够理解的Linux二进制ELF32系统。

This general concept can work on other formats supported by NASM and LD on other platforms. elf32 and elf_i386 as well as the debugging type will have to be modified for the specific environment. My sample targets systems that understand Linux Elf32 binaries.

不幸的是默认 GDB 没有做段:偏移计算,并会使用的 EIP 的值的断点。你必须指定断点为32位地址( EIP 的)。

Unfortunately by default gdb doesn't do segment:offset calculations and will use the value in EIP for breakpoints. You have to specify breakpoints as 32-bit addresses (EIP).

当涉及到通过实模式$ C $步进c那么它可能会很麻烦,因为 GDB 不处理实模式分割。如果你进入一个中断处理程序,你会发现 GDB 将显示组装$相对的 EIP 的的C $ C。有效地 GDB 将展示错误的内存位置拆卸,因为它没有考虑到的 CS 的。值得庆幸的是有人创造了一个 GDB 脚本以帮帮我。下载脚本开发目录,然后运行的 QEMU 的的东西,如:

When it comes to stepping through real mode code it can be cumbersome because gdb doesn't handle real mode segmentation. If you step into an interrupt handler you'll discover gdb will display the assembly code relative to EIP. Effectively gdb will be showing you disassembly of the wrong memory location since it didn't account for CS. Thankfully someone has created a gdb script to help. Download the script to your development directory and then run QEMU with something like:

qemu-system-i386 -hda main.img -S -s &
gdb -ix gdbinit_real_mode.txt main.elf \
        -ex 'target remote localhost:1234' \
        -ex 'break main' \
        -ex 'continue'

该脚本负责设置架构,i8086,然后钩身变为 GDB 。它提供了一些新的宏这都可以通过16位code更容易使步进。

The script takes care of setting the architecture to i8086 and then hooks itself into gdb. It provides a number of new macros that can make stepping through 16 bit code easier.

break_int:增加了对软件中断向量断点(路
  好老MS-DOS和BIOS揭露他们的API)

break_int : adds a breakpoint on a software interrupt vector (the way the good old MS DOS and BIOS expose their APIs)

break_int_if_ah:增加了对软件中断一个条件断点。 AH必须等于给定的参数。这是用来过滤中断服务调用。例如,你有时只是想休息的时候中断10h的功能啊= 0H被称为(切换画面模式)。

break_int_if_ah : adds a conditional breakpoint on a software interrupt. AH has to be equals to the given parameter. This is used to filter service calls of interrupts. For instance, you sometimes only wants to break when the function AH=0h of the interruption 10h is called (change screen mode).

stepo:这是用来步骤区切换功能的卡巴拉宏和中断呼叫。它是如何工作的 ?电流指令的操作code为萃取,如果它是一个函数或中断呼叫,下一个指令的地址是计算机,一个临时断点被添加在该地址与继续函数被调用。

stepo : this is a kabalistic macro used to 'step-over' function and interrupt calls. How does it work ? The opcode of the current instruction is extracted and if it is a function or interrupt call, the "next" instruction address is computed, a temporary breakpoint is added on that address and the 'continue' function is called.

step_until_ret:这是用来单步,直到我们遇到了RET指令。

step_until_ret : this is used to singlestep until we encounter a 'RET' instruction.

step_until_iret:这是用来单步,直到我们遇到一个IRET指令。

step_until_iret : this is used to singlestep until we encounter an 'IRET' instruction.

step_until_int:直到我们遇到一个INT指令这是用来单步

step_until_int : this is used to singlestep until we encounter an 'INT' instruction.

该脚本还会打印出与输出计算分割地址和寄存器每条指令的执行看起来像后:

This script also prints out addresses and registers with segmentation calculated in. Output after each instruction execution looks like:

---------------------------[ STACK ]---
D2EA F000 0000 0000 6F62 0000 0000 0000
7784 0000 7C00 0000 0080 0000 0000 0000
---------------------------[ DS:SI ]---
00000000: 53 FF 00 F0 53 FF 00 F0 C3 E2 00 F0 53 FF 00 F0  S...S.......S...
00000010: 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0  S...S...S...S...
00000020: A5 FE 00 F0 87 E9 00 F0 76 D6 00 F0 76 D6 00 F0  ........v...v...
00000030: 76 D6 00 F0 76 D6 00 F0 57 EF 00 F0 76 D6 00 F0  v...v...W...v...
---------------------------[ ES:DI ]---
00000000: 53 FF 00 F0 53 FF 00 F0 C3 E2 00 F0 53 FF 00 F0  S...S.......S...
00000010: 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0  S...S...S...S...
00000020: A5 FE 00 F0 87 E9 00 F0 76 D6 00 F0 76 D6 00 F0  ........v...v...
00000030: 76 D6 00 F0 76 D6 00 F0 57 EF 00 F0 76 D6 00 F0  v...v...W...v...
----------------------------[ CPU ]----
AX: AA55 BX: 0000 CX: 0000 DX: 0080
SI: 0000 DI: 0000 SP: 6F2C BP: 0000
CS: 0000 DS: 0000 ES: 0000 SS: 0000

IP: 7C00 EIP:00007C00
CS:IP: 0000:7C00 (0x07C00)
SS:SP: 0000:6F2C (0x06F2C)
SS:BP: 0000:0000 (0x00000)
OF <0>  DF <0>  IF <1>  TF <0>  SF <0>  ZF <0>  AF <0>  PF <0>  CF <0>
ID <0>  VIP <0> VIF <0> AC <0>  VM <0>  RF <0>  NT <0>  IOPL <0>
---------------------------[ CODE ]----
=> 0x7c00 <main>:       cli
   0x7c01:      mov    ax,0xe61
   0x7c04:      int    0x10
   0x7c06:      hlt
   0x7c07:      add    BYTE PTR [bx+si],al
   0x7c09:      add    BYTE PTR [bx+si],al
   0x7c0b:      add    BYTE PTR [bx+si],al
   0x7c0d:      add    BYTE PTR [bx+si],al
   0x7c0f:      add    BYTE PTR [bx+si],al
   0x7c11:      add    BYTE PTR [bx+si],al

这篇关于如何拆卸16位x86引导扇区code在与GDB英寸×/ I $电脑和QUOT ;?它被视为32位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆