如何拆卸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
问题描述
例如,具有引导扇区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 $ C $间$ P $ C>吃掉了下一条指令
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?
另请参阅:
- 在2007年GDB dev的回答说:用
objdump的
的 https://www.sourceware.org/ml/gdb/2007-03/msg00308.html 作为的如何拆卸生的x86 code?的也许是同时实现的? - 超:使用GDB在16位模式
- 相似,但OP了那里一个错误,也许是别的东西? 我怎么能拆卸的Win16用GDB
- 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屋!