我正在尝试制作一个简单的程序。我使用 windows10x64、qemu(x86_64)、C 和 assembly-nasm。我没有使用 asm 的经验。我试图理解它。我使用了一个简单的 boot.asm、kernel_entry.asm 和 loader.c 文件。我基于一个totorial。
引导程序
;; memory offset where our kernel is located
KERNEL_OFFSET equ 0x1000
;; save the boot drive number
mov [BOOT_DRIVE], dl
;; update base and stack pointers
mov bp, 0x9000
mov sp, bp
init:
mov si, msg ; loads the address of "msg" into SI register
mov ah, 0x0e ; sets AH to 0xe (function teletype)
print_char:
lodsb ; loads the current byte from SI into AL and increments the address in SI
cmp al, 0 ; compares AL to zero
je done ; if AL == 0, jump to "done"
int 0x10 ; print to screen using function 0xe of interrupt 0x10
jmp print_char ; repeat with next byte
;; call routine that loads kernel into memory
call load_kernel_into_memory
;; switch to Protected Mode
call switch_to_pm
jmp $
;; routine reads kernel from disk into memory
load_kernel_into_memory:
;; store all register values
pusha
;; set up parameters for disk_read routine
mov bx, KERNEL_OFFSET
mov dh, 15
mov dl, [BOOT_DRIVE]
call disk_read
;; restore register values and ret
popa
ret
;
[bits 32]
begin_pm:
;; Check if we can move from Protected Mode to Long Mode
;; If something went wrong (detect_lm shouldnt return at all)
;; we call execute_kernel in x32 Protected Mode
call detect_lm
call execute_kernel
jmp $
[bits 64]
begin_lm:
;; In case, if detect_lm and switch_to_lm works fine, call kernel in x64 mode
call execute_kernel
jmp $
;
execute_kernel:
call KERNEL_OFFSET
jmp $
;
%include "disk/disk_read.asm";
%include "lm/detect_lm.asm";
%include "lm/switch_to_lm.asm";
%include "pm/gdt.asm"
%include "pm/switch_to_pm.asm"
%include "print/print_string.asm";
%include "print/print_nl.asm";
BOOT_DRIVE: db 0
done:
hlt ; stop execution
msg: db "PROGRAM STARTED", 0x0a; we need to explicitely put the zero byte here
;
times 510-($-$$) db 0 ; fill the output file with zeroes until 510 bytes are full
dw 0xaa55 ; magic number that tells the BIOS this is bootable
kernel_entry.asm
global _start
global kernel_main
[bits 32]
[extern _kernel_main] ; I use "_" otherwise it will not compile. _kernel_main comes from "c" file.
;In there that is kernel_main
_start:
call _kernel_main
jmp $
加载器.c
#include <stdio.h>
extern void kernel_main() {
//printf("test");
for (int i = 0; i < 26; i++) {
char c = 0x41 + i;
asm(
"mov %0, %%al;"
"mov $0x0E, %%ah;"
"int $0x10;"
:
: "r" (c)
);
}
}
我使用 nasm-WINx64version 和 GCC-TDM 在 WINx64 上编译。
我的步骤是:
nasm kernel_entry.asm -f elf32 -o loader_entry.o
gcc -O0 -g -ffreestanding -m32 -c C:/Users/_USR_/Desktop/nasm-2.15.05/loader.c -o C:/Users/_USR_/Desktop/nasm-2.15.05/loader.o
ld -o "C:/Users/_USR_/Desktop/nasm-2.15.05/loader.tmp" -m i386pe -Ttext 0x1000 -T NUL C:/Users/_USR_/Desktop/nasm-2.15.05/loader_entry.o C:/Users/_USR_/Desktop/nasm-2.15.05/loader.o
objcopy -O binary loader.tmp loader.bin
type boot.bin loader.bin > myboot.bin
最后,我在 QEMU 中运行它并获得“程序启动”输出,但没有“C”语言消息。此外,当我使用printf("...");时出现未声明的错误。. 还有一件事,如果我在LD命令中添加-lc参数,我会收到“找不到”消息。看起来它不识别“C”。否则我运行程序 aster 与“C”和 asm 链接。我没有得到任何错误,但我也没有得到“C”函数。
我在这里做错了什么?

