Assembly BIOS int 0x13修改CS:IP?
我正在编写一个x86引导加载程序,它占用磁盘上的两个部分(1024字节),我希望它做的第一件事是在继续执行之前将这两个部分加载到段Assembly BIOS int 0x13修改CS:IP?,assembly,gdb,x86-16,bootloader,real-mode,Assembly,Gdb,X86 16,Bootloader,Real Mode,我正在编写一个x86引导加载程序,它占用磁盘上的两个部分(1024字节),我希望它做的第一件事是在继续执行之前将这两个部分加载到段0x60 以下是我的代码的重新定位部分: _start: // relocate and load remaining bootloader code mov $0x60, %ax mov %ax, %es mov $0x02, %ah mov $2, %al xor %bx, %bx mov $0, %ch mov $2,
0x60
以下是我的代码的重新定位部分:
_start:
// relocate and load remaining bootloader code
mov $0x60, %ax
mov %ax, %es
mov $0x02, %ah
mov $2, %al
xor %bx, %bx
mov $0, %ch
mov $2, %cl
xor %dh, %dh
int $0x13
jmp $0x60, $reloc_done
reloc_done:
// set up segment registers
mov $0x60, %ax
mov %ax, %ds
mov %ax, %es
// set up stack
mov $0x8000, %bx
mov %bx, %ss
xor %ax, %ax
mov %ax, %sp
这似乎不起作用,但是,我试图用gdb调试代码,除了一个普通二进制文件之外,我还创建了一个ELF文件boot.ELF
,并在将gdb附加到运行我的二进制文件的qemu进程之后执行addsymbol file boot.ELF 0x60
,然后执行break reloc_done
。我本来希望继续
然后实际命中0x60:reloc_done
处的断点,但这没有发生。这里怎么了
当我单步执行这个程序时,它看起来像是int$0x13
实际上将CS:IP修改为F000:E3FE
,我完全不理解这一点
编辑:尝试整合MichaelPetch的一些建议的一个最小示例:
boot.S:
// real mode code
.code16
.global _start
jmp $0x0, $_start
_start:
mov $0x8000, %ax
mov %ax, %sp
// relocate and load remaining bootloader code
mov $0x60, %ax
mov %ax, %es
xor %bx, %bx
mov $0x02, %ah
mov $2, %al
mov $0, %ch
mov $1, %cl
xor %dh, %dh
int $0x13
jmp $0x60, $reloc_done
reloc_done:
nop
// set up segment registers
mov $0x60, %ax
mov %ax, %ds
mov %ax, %es
// set up stack
mov $0x8000, %bx
mov %bx, %ss
xor %ax, %ax
mov %ax, %sp
boot.ld:
OUTPUT_FORMAT("elf32-i386");
ENTRY(_start);
SECTIONS
{
. = 0x0;
.text : {
*(.text);
. = 510;
SHORT(0xAA55);
}
.data : SUBALIGN(2) {
*(.data);
*(.rodata*);
}
/DISCARD/ : {
*(.eh_frame);
*(.comment);
}
}
编译如下:
gcc -m32 -fno-PIC -g -gdwarf -Wall -Werroro -c asm/boot.S -o out/boot_S.o
ld -melf_i386 -Tout/boot.ld out/boot_S.o -o ../elf/boot.elf
objcopy -O binary ../elf/boot.elf ../img/boot.img
boot.img
然后被复制到磁盘映像的第一个扇区。现在执行的初始指令不是mov$0x60,%ax,而是完全不同的东西
另一个编辑:我想我现在明白了,我必须按照MichaelPetch的建议更改链接器脚本中的链接地址,但也要从代码中删除初始的
jmp$0x0,
,这已经没有意义了。每种函数调用、分支或中断都会修改CS:IP。看起来你的调试器进入了BIOS代码。@interjay:你说得对,CS:IP在中断后确实指向BIOS ROM,我没有意识到,我以为gdb的“下一步”会跨过中断。@MichaelPetch:我使用的是处理段:偏移寻址的gdb脚本。我现在要做的是首先中断jmp 0x60:reloc_done
指令,然后在地址0x600
处重新加载boot.elf
(在我的问题中,我使用了0x60
,这显然是错误的)。当我继续单步执行时,它一开始似乎起作用,但随后指令/装配线似乎被随机跳过,因此仍然存在一些问题。我认为问题是,在jmp之后,CS是0x60
,这很好,但是对于CS:IP,IP应该减少0x7C00
,以指向我希望它指向的地方。但我不知道如何做到这一点,GAS拒绝jmp$0x60,$reloc_done-$0x7C00@MichaelPetch:我不确定我是否理解,我的链接器脚本以开头0x7C00。文本:{…
,即加载地址0x7C00
和链接地址(默认情况下,我假设,因为在(0)处添加不会改变任何内容)零。每种函数调用、分支或中断都会修改CS:IP。看起来你的调试器进入了BIOS代码。@interjay:你说得对,在中断后CS:IP确实指向BIOS ROM,我没有意识到,我以为gdb的“下一步”将跳过中断。@MichaelPetch:我正在使用一个处理段:偏移寻址的gdb脚本。我现在要做的是首先中断jmp 0x60:reloc_done
指令,然后在地址0x600
处重新加载boot.elf
(在我的问题中,我使用了0x60
,这显然是错误的)。当我继续单步执行时,它一开始似乎起作用,但随后指令/装配线似乎被随机跳过,因此仍然存在一些问题。我认为问题是,在jmp之后,CS是0x60
,这很好,但对于CS:IP,IP应该减少0x7C00
,以指向我希望它指向的位置。但是我我不知道如何做到这一点,GAS拒绝了jmp$0x60,$reloc_done-$0x7C00
@MichaelPetch:我不知道我是否理解,我的链接器脚本以=0x7C00;开始。文本:{…
,即加载地址0x7C00
和链接地址(默认情况下我假设,因为在(0)
处添加不会改变任何东西)零。