我正在调试一些程序集,但当我跳过(si
)一个除法(div
)时,当前指令不会改变。
具体来说,我正在编写一个引导加载程序(对于笑话和咯咯笑声),并且在尝试将LBA地址转换为CHS地址时,我遇到了div
指令。
这是我的调试会话的注释版本:
# Attach to QEmu instance:
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
# Tell gdb we're debugging 16-bit x86.
(gdb) set architecture i8086
warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB. Attempting to continue with the default i8086 settings.
The target architecture is assumed to be i8086
# Break at the start of the booloader.
(gdb) b *0x7c00
Breakpoint 1 at 0x7c00
# (and go there now)
(gdb) c
Continuing.
# Start of bootloader.
Breakpoint 1, 0x00007c00 in ?? ()
(gdb) disassemble 0x7c00,+50
Dump of assembler code from 0x7c00 to 0x7c32:
=> 0x00007c00: ljmp $0x0,$0x7c05
0x00007c05: xor %ax,%ax
0x00007c07: mov %ax,%ds
0x00007c09: mov %ax,%es
0x00007c0b: mov %ax,%ss
0x00007c0d: mov $0x800,%sp
0x00007c10: sti
0x00007c11: mov $0x7ce0,%bx
0x00007c14: call 0x7c28
0x00007c17: call 0x7c3a
0x00007c1a: call 0x7c1f # <= stop here, at the call to read_stage_2
0x00007c1d: cli
0x00007c1e: hlt
0x00007c1f: xor %ax,%ax
0x00007c21: mov $0x1,%ax
0x00007c24: call 0x7c56
0x00007c27: ret
0x00007c28: mov (%bx),%al
0x00007c2a: cmp $0x0,%al
0x00007c2c: je 0x7c39
0x00007c2e: push %bx
0x00007c2f: xor %bx,%bx
0x00007c31: mov $0xe,%ah
End of assembler dump.
# Stop at `call read_stage_2`; go there
(gdb) b *0x7c1a
Breakpoint 2 at 0x7c1a
(gdb) c
Continuing.
Breakpoint 2, 0x00007c1a in ?? ()
# Step into the call.
(gdb) si
0x00007c1f in ?? ()
# Show the disassembly of read_stage_2:
(gdb) disassemble 0x7c1f,+10
Dump of assembler code from 0x7c1f to 0x7c29:
=> 0x00007c1f: xor %ax,%ax
0x00007c21: mov $0x1,%ax
0x00007c24: call 0x7c56
0x00007c27: ret
0x00007c28: mov (%bx),%al
End of assembler dump.
(gdb) si # si over xor.
0x00007c21 in ?? ()
(gdb) si # si over mov.
0x00007c24 in ?? ()
# Double-check that I'm at the call.
(gdb) disassemble 0x7c1f,+10
Dump of assembler code from 0x7c1f to 0x7c29:
0x00007c1f: xor %ax,%ax
0x00007c21: mov $0x1,%ax
=> 0x00007c24: call 0x7c56
0x00007c27: ret
0x00007c28: mov (%bx),%al
End of assembler dump.
# Yup; step into lba_to_chs
(gdb) si
0x00007c56 in ?? ()
# Show me the source of lba_to_chs
(gdb) disassemble 0x7c56,+30
Dump of assembler code from 0x7c56 to 0x7c74:
=> 0x00007c56: xor %bx,%bx
0x00007c58: mov 0x803,%bl
0x00007c5c: div %bx
0x00007c5e: inc %ax
0x00007c5f: push %ax
0x00007c60: xor %bx,%bx
0x00007c62: mov 0x802,%bl
0x00007c66: div %bx
0x00007c68: mov %dx,%bx
0x00007c6a: mov %al,%dh
0x00007c6c: pop %ax
0x00007c6d: ret
0x00007c6e: mov %bl,%ch
0x00007c70: shr $0x2,%bx
0x00007c73: mov %bl,%cl
End of assembler dump.
(gdb) si # si over xor
0x00007c58 in ?? ()
(gdb) si # si over mov
0x00007c5c in ?? ()
# We should be at the div, indeed, we are.
(gdb) disassemble 0x7c56,+30
Dump of assembler code from 0x7c56 to 0x7c74:
0x00007c56: xor %bx,%bx
0x00007c58: mov 0x803,%bl
=> 0x00007c5c: div %bx
0x00007c5e: inc %ax
0x00007c5f: push %ax
0x00007c60: xor %bx,%bx
0x00007c62: mov 0x802,%bl
0x00007c66: div %bx
0x00007c68: mov %dx,%bx
0x00007c6a: mov %al,%dh
0x00007c6c: pop %ax
0x00007c6d: ret
0x00007c6e: mov %bl,%ch
0x00007c70: shr $0x2,%bx
0x00007c73: mov %bl,%cl
End of assembler dump.
# Show me the registers. We should be dividing LBA 1 by the total number of
# sectors. (%ax / %bx). Here %ax is 1 (correct), and %bx is 63 (likely
# correct).
(gdb) info registers
eax 0x1 1
ecx 0x3f 63
edx 0x3f01 16129
ebx 0x3f 63
esp 0x7fc 0x7fc
ebp 0x0 0x0
esi 0x0 0
edi 0x0 0
eip 0x7c5c 0x7c5c
eflags 0x242 [ ZF IF ]
cs 0x0 0
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
# Step over the div.
(gdb) si
0x00007c5c in ?? ()
# Why are we still at the div instruction?
(gdb) disassemble 0x7c56,+30
Dump of assembler code from 0x7c56 to 0x7c74:
0x00007c56: xor %bx,%bx
0x00007c58: mov 0x803,%bl
=> 0x00007c5c: div %bx
0x00007c5e: inc %ax
0x00007c5f: push %ax
0x00007c60: xor %bx,%bx
0x00007c62: mov 0x802,%bl
0x00007c66: div %bx
0x00007c68: mov %dx,%bx
0x00007c6a: mov %al,%dh
0x00007c6c: pop %ax
0x00007c6d: ret
0x00007c6e: mov %bl,%ch
0x00007c70: shr $0x2,%bx
0x00007c73: mov %bl,%cl
End of assembler dump.
# IP refuses to advance?
(gdb) si
0x00007c5c in ?? ()
(gdb) si
0x00007c5c in ?? ()
# Frustration ensues…
(gdb) si
0x00007c5c in ?? ()
(gdb) si
0x00007c5c in ?? ()
(gdb) si
0x00007c5c in ?? ()
…
这是代码:
.code16
.global entry
# Memory:
# 0x500 - 0x800 stack
# 0x800: drive geometry
# 2 bytes: cylinders in drive
# 1 byte: max head number
# 1 byte: max sector number
.section .bss
drive_cylinders:
.space 2
drive_heads:
.space 1
drive_sectors:
.space 1
.section .text
entry:
# Jump incase we're not a 0000:7c00
ljmp $0x0,$start
start:
# Set es, ss to 0x0000
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
# Put the stack at 0x500 - 0x800 (256 * 3 bytes)
mov $0x800, %sp
sti
mov $msg_greeting, %bx
call print
call get_disk_geometry
call read_stage_2 # <-- The third call in the above disassembly.
cli
hlt
read_stage_2:
xor %ax, %ax
mov $0x01, %ax
call lba_to_chs
ret
print:
« omitted »
ret
get_disk_geometry:
xor %ax, %ax
mov %ax, %es
mov %ax, %di
mov $0x08, %ah
int $0x13
jc _io_error
inc %dh
mov %dh, (drive_heads)
mov %cl, %dh
and $0x3f, %dh
mov %dh, (drive_sectors)
ret
lba_to_chs:
# Stores CHS in:
# bx = cylinder
# dh = head
# ax = sector
# LBA in ax.
xor %bx, %bx
mov (drive_sectors), %bl
div %bx # <--- The problematic div.
inc %ax
push %ax
xor %bx, %bx
mov (drive_heads), %bl
div %bx
mov %dx, %bx
mov %al, %dh
pop %ax
ret
我也在使用以下链接器脚本:
ENTRY(entry);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
_text = .;
*(.text);
_text_end = .;
}
.data :
{
_data = .;
*(.data);
*(.rodata*);
*(COMMON)
_data_end = .;
}
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
. = 0x800;
.bss : AT(0x800)
{
*(.bss);
*(.bss*);
}
/DISCARD/ :
{
*(.note*);
*(.iplt*);
*(.igot*);
*(.rel*);
*(.comment);
}
}
这要建立:
#!/bin/bash
set -e
as bootsector.S -o bootsector.o
ld -static -Tbootsector.ld -nostdlib --nmagic -o bootsector.elf bootsector.o
objcopy -O binary -R .bss bootsector.elf bootsector.bin
这里发生了什么?
答案 0 :(得分:1)
指令div %bx
将32位值DX:AX除以16位值BX,因此必须在划分前将DX设置为零。