【发布时间】:2020-08-24 23:12:54
【问题描述】:
这是我应该打印的新内核代码(顺便说一句,它之所以称为 printstack 是因为我试图通过堆栈传递参数,但这不起作用):
void printstack(char in){ /*print function*/
asm ("mov ah,0x0e\n"
"mov al,%0\n"
"int 0x10\n"
::"r"(in)
);
}
void main(){ /*kernel entry point*/
printstack('a');
}
但是当我在 QEMU 中测试它时,它只打印空格。
这是构建 os.flp 的完整脚本:
echo ">>> Creating floppy image..."
mkdosfs -C os.flp 1440 || exit
echo ">>> Assembling bootloader..."
nasm -O0 -w+orphan-labels -f bin -o source/bootload/bootload.bin source/bootload/bootload.asm || exit
echo "compiling kernel"
gcc -c ./source/kernel.c -masm=intel
ld --oformat binary kernel.o -o ./source/kernel.bin -e main
echo ">>> Adding bootloader to floppy image..."
dd status=noxfer conv=notrunc if=source/bootload/bootload.bin of=os.flp || exit
echo ">>> Copying kernel"
rm -rf tmp-loop
mkdir tmp-loop && mount -o loop -t vfat os.flp tmp-loop && cp source/kernel.bin tmp-loop/
sleep 0.2
echo ">>> Unmounting loopback floppy..."
umount tmp-loop || exit
rm -rf tmp-loop
t
echo '>>> Done!'
【问题讨论】:
-
请发帖Minimal, Reproducible Example。
os.flp是如何构建的?是否正确考虑了入口点? -
这应该取决于环境,但是将
main()的定义移到printstack之一之前可能会使其表现更好。 (printstack的声明应该在main()之前) -
您的约束没有描述它修改 EAX(通过覆盖 AH)的事实。作为唯一的 C 语言,这似乎不太可能成为问题,尤其是对于 64 位代码。哦,但是你没有任何 asm 来调用你的 C!您正在制作 64 位机器代码,然后通过 QEMU 在 16 位实模式下执行它。
push rbp/mov rbp,rsp上的 REX 前缀将解码为dec eax指令...在调试器中单步执行 asm 以查看发生了什么。此外,编译器在函数末尾的ret可能会造成严重破坏。编写一个无限循环并使用gcc -m16编译。 -
使用 GCC 生成代码以在 16 位实模式下运行是充满问题的(我不推荐它)。如果您不顾警告选择执行此操作,则需要使用
-m16GCC 选项;在调用main之前加载内核 SS=DS=CS=ES=0 (并设置 SP 堆栈指针)之前;使用-ffreestanding编译。有一个答案(在 Proper use of Inline Assembly to Write a String Using the BIOS 部分下)给出了构建内核和使用针对实模式的内联汇编的示例stackoverflow.com/a/57932741/3857942
标签: c kernel x86-16 inline-assembly bootloader