我正在尝试使用 GCC 编写一个简单的操作系统,这将允许我在我键入的显示器上显示文本。我在 C 中有一个中断表,我需要加载并希望能够使用内联汇编而不是外部汇编语言模块来实现。
我正在寻找的是一种将 C 指针传递给内联汇编的方法。
我试图内联需要内存操作数的指令是LIDT:
将源操作数中的值加载到全局描述符表寄存器(GDTR)或中断描述符表寄存器(IDTR)中。源操作数指定一个6字节的存储器位置,其中包含全局描述符表(GDT)或中断描述符表(IDT)的基址(线性地址)和限制(以字节为单位的表的大小)。如果操作数大小属性为32位,则16位限制(6字节数据操作数的低2字节)和32位基址(数据操作数的高4字节)将加载到寄存器中。如果操作数大小属性是16位,则加载16位限制(低2字节)和24位基址(第三,第四和第五字节)。这里,不使用操作数的高位字节,GDTR或IDTR中基址的高位字节用零填充。
答案 0 :(得分:2)
您没有提供任何代码,也没有说哪个 C 编译器,但我会假设 GCC 和一个32位内核。这是你可以做的一个例子:
#include <stdint.h>
struct idt_record
{
uint16_t limit; /* Size of IDT array - 1 */
uintptr_t base; /* Pointer to IDT array */
} __attribute__((packed));
void load_idt (struct idt_record *idt_r)
{
__asm__ ("lidt %0" :: "m"(*idt_r));
}
此代码使用内联汇编并将 IDT 记录的地址传递到扩展内联模板,LIDT指令使用该模板。我们使用m
constraint。如果约束的参数为(idt_r)
,它会将内存引用传递给指针。我们需要对实际数据的内存引用,因此我们使用*
取消引用它,这就是我使用"m"(*idt_r)
的原因。
您必须将base
设置为指向您的实际 IDT 数组,limit
将是 IDT 数组减去1的大小。如果您向我们展示了您的数据结构,我就不必提供这样的通用响应。我不知道您是如何定义 IDT 记录结构的,所以我使用了一个简单快捷的例子。
我可能会在包含文件中提供load_idt
函数,并将该函数标记为static inline
。
注意:如果您使用 IDT 记录的结构,请确保打包结构类似于我对{ {1}}。如果您不打包,则会在__attribute__((packed))
和limit
之间添加额外的2个字节,这将生成损坏的 IDT 记录。