在引导加载程序中使用的正确调用约定是什么?

Aru*_*pur 5 assembly operating-system calling-convention bootloader x86-16

我正在尝试编写一个引导加载程序和一个非常原始和基本的内核,以了解裸机编码实践和技术。无论如何,我正在使用 NASM 编写我的引导程序。我的代码正在运行,但我对要使用的调用约定有疑问。

我只是通过运行 NASM 来编译我的引导加载程序: nasm bootloader.asm -o bootloader

在我的汇编代码,我写的功能,如BlDisplayString通过BIOS中断显示字符串int 0x10AH = 0x13。我试图__fastcall通过在CX, DX, STACK. 这是在 16 位代码中使用的正确调用约定标准吗?当我调用这些函数时,CPU 未处于保护模式并且仍处于实模式。

Pet*_*des 5

CPU 不在乎,做任何方便和可维护的事情。 “正确性”的唯一判断者是您,如果您不尝试链接到由 C 编译器生成的任何代码。

但是,是的,注册 args 通常是一个好主意,带有呼叫破坏的 AX、CX、DX。如果您愿意在每个rep-string 函数之前设置它,让 ES 被调用破坏可能会方便避免让函数保存/恢复它。

在与 BIOS 所在位置对齐的寄存器中传递参数 int调用希望它们可以在包装器代码中保存一些指令。

您甚至可以在每个函数的基础上使用自定义调用约定,但这更难记住/记录。对于仅从一个函数(但在该函数中的多个位置)或从一个文件中的几个类似函数调用的本地辅助函数很有用。在注释中,注册输入、输出和破坏的文档(用作没有保存/恢复的暂存空间)。

对不同类型的函数有几个不同的调用约定是 1 个固定约定与每个函数不同的约定之间的中间地带。

在 FLAGS 中返回布尔条件对于 asm 很方便,尤其是当您希望调用者在其上进行分支时。或者对于像memcmp, 结尾cmp al, dl或任何让您的调用者分支相等或更大/更少的函数,无论它想读取哪个 FLAGS。所有这些都没有像 C 函数那样实际生成 + / 0 / - 返回值的成本。

CodeGolf.SE在 x86/x64 机器代码中打高尔夫球的技巧的答案详细介绍了如果您全力以赴编写小代码而不关心函数之间的可维护性或一致性,您可能会做什么。

如果您想将更多代码放入 512 字节的第一阶段引导加载程序,或放入更少的额外扇区,您通常可以在不影响可读性的情况下节省一些字节。更少的指令通常更容易阅读。(不过,这并不总是与较小的机器代码大小相同。)