内联汇编寻址方式

Inline assembly addressing mode

我正在尝试使用 -masm=intel 和 32 位 (-m32) 在 gcc 的内联汇编中编写 lidt 指令。所以我定义了以下结构:

typedef struct {
    uint16_t length;
    uint32_t base;
} idt_desc;

static idt_desc desc = {
    sizeof(idt)-1,
    (uint32_t)(uintptr_t)idt,
};

如果我使用 nasm,我将不再使用 lidt [desc]。但是我正在使用内联汇编并将其放在一个函数中:

asm volatile("lidt %0"::"m"(desc):);

这给了我 "Error: unsupported instruction `lidt'"。生成的程序集如下所示:

    lidt QWORD PTR desc

据我所知,大括号在 gas intel 语法中是可选的。所以这里的问题是 qword ptrlidt 指令中是不可接受的,因为它需要一个 m16&32 操作数。我怎样才能告诉 gcc 使用它?即,删除 qword ptr 并只使用 desc

您需要打包 idt_desc 结构,因为编译器将在 16 位 length 和 32 位 base 结构成员之间添加填充。即使编译器设法为此生成代码,该结构也会无效,并且 LIDT 几乎肯定会加载错误的 IDT 记录,导致最终在运行时出现 crash/triple 错误。应该是:

typedef struct {
    uint16_t length;
    uint32_t base;
} __attribute__((packed)) idt_desc;

-masm=intel 选项似乎导致编译器将结构的解压缩版本视为填充的 8 字节结构,然后将其视为 64 位 QWORD。在 32 位代码中,LIDT 不接受指向 QWORD 的指针,它接受指向 48 位值(在某些 Intel 方言中又名 FWORD)的指针,这是源代码的错误。通过打包结构,编译器不再生成 QWORD,因为打包版本的大​​小为 6 个字节。