问题描述
我无法在保护模式下打印。
这是我的代码:
$ gcc -E boot.S
# 1 "boot.S"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "boot.S"
# 1 "header.h" 1
read_fail:
.asciz "Disk read failed"
.altmacro
.macro PUSHA
push %ax
push %bx
push %cx
push %dx
.endm
.macro POPA
pop %ax
pop %bx
pop %cx
pop %dx
.endm
.macro PUSH_EA
push %eax
push %ebx
push %ecx
push %edx
.endm
.macro POP_EA
pop %eax
pop %ebx
pop %ecx
pop %edx
.endm
.macro CLEAR
PUSH_EA
mov $0x0600,%ax
mov $0x07,%bh
mov $0x00,%cx
mov $0x184f,%dx
int $0x10
CURSOR_POS
POP_EA
.endm
.macro CURSOR_POS x=2,y=2
PUSH_EA
mov $0x02,%ah
mov $0x00,%bh
mov \x,%dh
mov \y,%dl
int $0x10
POP_EA
.endm
.macro BEGIN
.code16
_start:
xor %ax,%ax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
mov %ax,%ss
mov %ax,%bp
mov %bp,%sp
.endm
.macro PRINT_STRING str
LOCAL loop,end
mov \str,%si
mov $0x0E,%ah
cld
loop:
lodsb
cmp $0x00,%al
je end
int $0x10
jmp loop
end:
.endm
.macro HEX_NIBBLE reg
LOCAL end,letter
cmp $10,\reg
jae letter
add $'0',\reg
jmp end
letter:
add $0x37,\reg
.endm
.macro HEX c
mov \c,%al
mov \c,%ah
shr $4,%al
HEX_NIBBLE <%al>
and $0x0F,%al
HEX_NIBBLE <%ah>
.endm
.macro PRINT_CHAR c=$0x20
push %ax
mov \c,%al
mov $0x0E,%ah
int $0x10
pop %ax
.endm
.macro PRINT_HEX reg=<%al>
push %ax
HEX <\reg>
PRINT_CHAR <%al>
PRINT_CHAR <%ah>
pop %ax
.endm
.macro RESET_DISK
LOCAL error,end
mov $0x00,%ah
mov $0x80,%dl
int $0x13
jmp end
end:
.endm
.macro STAGE2
LOCAL read_error,end
RESET_DISK
mov $__stage2_nsectors,%al
mov $0x9000,%ebp
mov %ebp,%esp
mov $0x02,%ah
mov $0x0002,%cx
mov $0x80,%dl
mov $0x00,%dh
mov $0x1000,%bx
int $0x13
jc read_error
jmp 1f
read_error:
PRINT_STRING $read_fail
.section .stage2
1:
jmp *(0x1000)
.endm
.macro PROTECTED_MODE
.equ CODE_SEG,8
.equ DATA_SEG,gdt_data - gdt_start
cli
lgdt gdt_descriptor
mov %cr0,%eax
orl $0x01,%eax
mov %eax,%cr0
ljmp $CODE_SEG,$protected_mode
gdt_start:
gdt_null:
.long 0x00
.long 0x00
gdt_code:
.word 0xFFFF
.word 0x0000
.byte 0x00
.byte 0b10011010
# 220 "header.h"
.byte 0b11001111
# 230 "header.h"
.byte 0x00
gdt_data:
.word 0xffff
.word 0x00
.byte 0x00
.byte 0b10010010
.byte 0b11001111
.byte 0x00
gdt_end:
gdt_descriptor:
.word gdt_end - gdt_start
.long gdt_start
.code32
protected_mode:
mov $DATA_SEG,%ss
mov $0x9000,%esp
.endm
vga_current_line:
.long 0
.macro VGA_PRINT_STR str
LOCAL loop,end
PUSH_EA
mov \str,%ecx
mov vga_current_line,%eax
mov $0,%edx
mov $25,%ebx
div %ebx
mov %edx,%eax
mov $160,%edx
mul %edx
lea 0xb8000(%eax),%edx
mov $0x0f,%ah
loop:
mov (%ecx),%al
cmp $0,%al
je end
mov %ax,(%edx)
inc %ecx
addl $2,%edx
jmp loop
end:
POP_EA
incl vga_current_line
.endm
# 2 "boot.S" 2
.section .text
BEGIN
CLEAR
STAGE2
PROTECTED_MODE
VGA_PRINT_STR $str
jmp .
str:
.asciz "Hello"
Makefile
.POSIX:
IMAGE ?= $(FILENAME)
LD ?= ld
LD_SCRIPT ?= linker.ld
HEADER ?=header.h
GAS ?= gcc
CFLAGS ?= -c
QEMU ?= qemu-system-i386
OUT_EXT ?= .bin
all: $(IMAGE)$(OUT_EXT)
$(IMAGE).bin: $(IMAGE).o
$(LD) -T'$(LD_SCRIPT)' --oformat=binary '$<' -o '$@'
$(IMAGE).o : $(IMAGE).S $(HEADER)
$(GAS) -c '$<' -o '$@'
run: $(IMAGE)$(OUT_EXT)
$(QEMU) '$<'
clean:
rm *.o *bin
linker.ld
OUTPUT_FORMAT("elf32_i386");
SECTIONS
{
. = 0x7c00;
.text : {
__start = .;
*(.text)
. = 0x1FE;
SHORT(0xaa55);
*(.stage2 )
__stage2_nsectors = ABSOLUTE((. - __start)/512);
. = ALIGN(512);
__end = . ;
__end_align_4k = ALIGN(4K);
}
}
我正在将qemu用作仿真器。在Qemu中,应该已经显示“ Hello”,但这是输出。
我无法解决此问题。感谢您提供有关此问题的任何提示。
- 注意:当在.macro STAGE2中将bx寄存器设置为$ 1f时,代码可以工作,但是我找不到其原因
解决方法
可能不是您唯一的问题,但是您的POP_EA
将以相反的顺序从PUSH_EA
宏中弹出内容(堆栈是后进先出的),因此不会匹配:
.macro PUSH_EA
push %eax
push %ebx
push %ecx
push %edx
.endm
.macro POP_EA
pop %eax
pop %ebx
pop %ecx
pop %edx
.endm
由于最后推送的内容是%edx,而第一个弹出的内容是%eax,因此最终交换了它们。弹出的顺序必须相反:
.macro POP_EA
pop %edx
pop %ecx
pop %ebx
pop %eax
.endm