【问题标题】:How to use the immediate constraint with Intel syntax in gcc?如何在 gcc 中使用 Intel 语法的直接约束?
【发布时间】:2016-03-26 10:07:00
【问题描述】:

使用 GCC 中的内联汇编,您可以使用 "i" 约束指定直接 asm 操作数,如下所示:

void set_to_five(int* p)
{
    asm
    (
        "movl %1, (%0);"
        :: "r" (p)
        ,  "i" (5)
    );
}

int main()
{
    int i;
    set_to_five(&i);
    assert(i == 5);
}

到目前为止,这并没有什么问题,只是它的 AT&T 语法很糟糕。所以让我们再试一次.intel_syntax noprefix

void set_to_five(int* p)
{
    asm
    (
        ".intel_syntax noprefix;"
        "mov [%0], %1;"
        ".att_syntax prefix;"
        :: "r" (p)
        ,  "i" (5)
    );
}

但这不起作用,因为编译器在立即数之前插入了一个 $ 前缀,汇编器不再理解。

如何在 Intel 语法中使用 "i" 约束?

【问题讨论】:

  • 尝试使用%c1(参见gcc.gnu.org/onlinedocs/gcc/…)。此外,请考虑使用 -masm=intel 而不是伪操作。
  • 我一定已经阅读了该页面 10 次,但不知何故我错过了那一点。谢谢!您应该将此作为答案发布。
  • 尽管我很想使用-masm=intel,但在包含带有 AT&T 语法 asm 的标头时会引起麻烦。
  • 您正在使用哪些包含内联 asm 的标头?正是出于这个原因,公共标头应该使用方言(请参阅gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#AssemblerTemplate 下的“asm 模板中的多个汇编程序方言”)。但当然不是每个人都这样做。
  • djgpp 标准库有其中一些......但我现在想我可以用英特尔语法重新实现它们。或者使用像INTEL_ASM_BEGIN/INTEL_ASM_END 这样的宏,并根据使用的-masm 设置将它们定义为相应的伪操作或不定义任何内容。我不喜欢多方言功能,代码重复是一件坏事:)

标签: gcc inline-assembly


【解决方案1】:

您应该可以使用 %c1(请参阅modifiers)。

请注意,如果您使用符号名称(我发现它更易于阅读/维护),您可以使用 %c[five]。

最后,我意识到这只是一个“for-instance”的代码,但您正在修改内存而不告诉编译器。这是一件“坏事”。考虑对内存使用输出约束 ("=m") 或添加“内存”clobber。

【讨论】:

  • 这引出了第二个问题;我是否也应该使用"memory" clobber 来处理非内存副作用(如 I/O 端口访问)?
  • 内存破坏器的重点是让编译器知道您的 asm 是否要读取“除了输入和输出操作数中列出的内存”之外的内存。这让编译器知道,如果它有缓存在寄存器中的任何值,它们应该在之后/重新加载之后刷新到内存。如果 I/O 操作确实是“非内存”(即没有将内存块写入磁盘、从磁盘读取块等),那么编译器(可能)不需要做任何事情。很难说绝对没​​有细节。
  • 我在考虑硬件 I/O 端口(@98​​7654324@/out 指令)。这些东西没有保存在 C/C++ 变量中,所以我认为这里不需要“内存”,只需 asm volatile 以确保它们以正确的顺序执行。
  • 如果顺序是一个问题,请考虑添加对一些周围变量的引用以“锚定”您的 asm。添加输入或输入+输出可以帮助告诉 gcc 事情的去向。请注意,没有必要实际使用所有参数。
猜你喜欢
  • 1970-01-01
  • 2016-12-21
  • 2010-09-17
  • 2022-06-30
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 2016-09-01
  • 2013-06-14
相关资源
最近更新 更多