2014-01-19 24 views
2

我正在調試一些程序集,但是當我跨越(si)一個分區(div)時,當前指令不會改變。爲什麼我不能跨越這個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 

這是怎麼回事?

回答

1

指令div %bx將32位值DX:AX除以16位的值BX,因此您必須在分割前將DX設置爲零。

+0

我也跳過了手冊中異常表中的行,因爲行以「除以零,#DE」開頭,而且我知道我的除數不是0.(行分成兩部分,下半部分,「特殊登記冊中的商數太大」,在「例外原因」下)。 – Thanatos

相關問題