Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
GCC内联汇编英特尔语法“;错误:寄存器“的使用无效”;_C_Gcc_X86_Inline Assembly_Intel Syntax - Fatal编程技术网

GCC内联汇编英特尔语法“;错误:寄存器“的使用无效”;

GCC内联汇编英特尔语法“;错误:寄存器“的使用无效”;,c,gcc,x86,inline-assembly,intel-syntax,C,Gcc,X86,Inline Assembly,Intel Syntax,我决定尝试在我的基本操作系统中使用c语言中的内联汇编(使用intel语法,因为我已经习惯了NASM)。我遇到了一些我无法解决的问题,我试着到处寻找,但没有任何效果。尝试错误消息后显示的代码时,GCC显示以下消息: main.c: Assembler messages: main.c:8: Error: invalid use of register 守则如下: int main(){ asm("mov ah, 0x00\n\t"); asm("mo

我决定尝试在我的基本操作系统中使用c语言中的内联汇编(使用intel语法,因为我已经习惯了NASM)。我遇到了一些我无法解决的问题,我试着到处寻找,但没有任何效果。尝试错误消息后显示的代码时,GCC显示以下消息:

main.c: Assembler messages:
main.c:8: Error: invalid use of register
守则如下:

int main(){
    asm("mov ah, 0x00\n\t");
    asm("mov al, 0x13\n\t");
    asm("int 0x10\n\t");
    asm("mov bx, 0xA000\n\t");
    asm("mov es, bx\n\t");
    asm("mov di, 0\n\t");
    asm("mov byte [es:di], 0x0f\n\t"); // Problem line of error.
    while(1){
        asm("nop");
    }
    return 0;
}

有人能帮我吗?

关于这件事有很多要提的。首先,您使用的是Intel语法,这很好(至少对于GCC来说,对于clang来说更难)。您可以在编译时使用
-masm=intel
,也可以在asm模板中作为黑客开关切换到
.intel\u syntax noprefix
,然后在asm字符串末尾切换回
.att\u syntax
,这样编译器的其余代码仍然可以工作。()

接下来,您有许多
asm()
块。最好有一个,这样就可以为整个块指定输入/输出/clobbers/goto。这很容易做到,因为C连接相邻的字符串

您的代码中有NASM样式的
[es:di]
。在GAS的Intel语法方言中,段名称在括号外:
es:[di]
。我还注意到,
[di]
并不合适,除非您使用的是16位体系结构;方括号中的东西必须是平台上指针的大小

…然而,您也在使用
int0x10
,这是一种BIOS中断,因此我猜16位实际上是您在这里想要的

尽管如此,您确实需要养成指定重击者的习惯。也就是说,指定代码修改的寄存器,以及它是否修改条件代码寄存器和内存。编译器正在决定将哪些变量保存在寄存器等中,而不知道汇编代码的作用。您必须告诉它您正在修改,例如,
ax
,以便它知道并可以保存/恢复它

GCC并不真正了解分段(它是一个采用平面内存模型的便携式编译器,不专门用于x86-16),因此将
es
ds
保留不同的基并不安全。e、 g.GCC可以选择使用
rep stosd
初始化结构或数组。这里很安全,因为asm之后的代码非常少

这是我对你的代码的重写

int main()
{
    asm volatile(
        ".intel_syntax noprefix\n\t"
        "mov ah, 0x00\n\t"
        "mov al, 0x13\n\t"
        "int 0x10\n\t"
        "mov bx, 0xA000\n\t"
        "mov es, bx\n\t"
        "mov di, 0x00\n\t"
        "mov byte ptr es:[di], 0x0f\n\t"
        ".att_syntax"                      // undo .intel_syntax
        : /* output operands */
        : /* input operands */
        : "ax","bx","di","cc", "memory" /* clobbers */
    );
    while(1){
        // asm("nop");  // unneeded: empty infinite loops are already legal in C.
    }
    return 0;
}
如果您的代码修改或甚至读取您也通过C指针访问的内存,那么您还应该在clobbers行中包含
“memory”
。看到了吗

volatile
在这里不是绝对必要的,因为没有输出操作数,asm语句是隐式的
volatile
。但最好包含
volatile
,以明确(对人类读者)存在明显的副作用(BIOS调用和存储到视频内存)。因此,如果您确实包含一个输出操作数,它将不会得到优化

附录:
通常,使用
-masm=intel
进行编译,而不是使用清单中的
.intel\u语法
。这使得编译器在替换操作数时可以使用正确的语法。

。首先,您使用的是Intel语法,这很好(至少对于GCC来说,对于clang来说更难)。您可以在编译时使用
-masm=intel
,也可以在asm模板中作为黑客开关切换到
.intel\u syntax noprefix
,然后在asm字符串末尾切换回
.att\u syntax
,这样编译器的其余代码仍然可以工作。()

接下来,您有许多
asm()
块。最好有一个,这样就可以为整个块指定输入/输出/clobbers/goto。这很容易做到,因为C连接相邻的字符串

您的代码中有NASM样式的
[es:di]
。在GAS的Intel语法方言中,段名称在括号外:
es:[di]
。我还注意到,
[di]
并不合适,除非您使用的是16位体系结构;方括号中的东西必须是平台上指针的大小

…然而,您也在使用
int0x10
,这是一种BIOS中断,因此我猜16位实际上是您在这里想要的

尽管如此,您确实需要养成指定重击者的习惯。也就是说,指定代码修改的寄存器,以及它是否修改条件代码寄存器和内存。编译器正在决定将哪些变量保存在寄存器等中,而不知道汇编代码的作用。您必须告诉它您正在修改,例如,
ax
,以便它知道并可以保存/恢复它

GCC并不真正了解分段(它是一个采用平面内存模型的便携式编译器,不专门用于x86-16),因此将
es
ds
保留不同的基并不安全。e、 g.GCC可以选择使用
rep stosd
初始化结构或数组。这里很安全,因为asm之后的代码非常少

这是我对你的代码的重写

int main()
{
    asm volatile(
        ".intel_syntax noprefix\n\t"
        "mov ah, 0x00\n\t"
        "mov al, 0x13\n\t"
        "int 0x10\n\t"
        "mov bx, 0xA000\n\t"
        "mov es, bx\n\t"
        "mov di, 0x00\n\t"
        "mov byte ptr es:[di], 0x0f\n\t"
        ".att_syntax"                      // undo .intel_syntax
        : /* output operands */
        : /* input operands */
        : "ax","bx","di","cc", "memory" /* clobbers */
    );
    while(1){
        // asm("nop");  // unneeded: empty infinite loops are already legal in C.
    }
    return 0;
}
如果您的代码修改或甚至读取您也通过C指针访问的内存,那么您还应该在clobbers行中包含
“memory”
。看到了吗

volatile
在这里不是绝对必要的,因为没有输出操作数,asm语句是隐式的
volatile
。但最好包含
volatile
,以明确(对人类读者)存在明显的副作用(BIOS调用和存储到视频内存)。因此,如果您确实包含一个输出操作数,它将不会得到优化

附录: 通常,使用
-masm=intel
进行编译,而不是使用清单中的
.intel\u语法
。这使得编译器在替换操作数时可以使用正确的语法。

GCC是否使用操作数