【问题标题】:Inline assembly multiplication "undefined reference" on inputs输入上的内联汇编乘法“未定义引用”
【发布时间】:2020-02-16 18:55:26
【问题描述】:

尝试使用内联汇编将 400 乘以 2,使用事实 imul 隐式乘以 eax。但是,我收到 $1$2 的“未定义引用”编译错误

 int c;
 int a = 400;
 int b = 2;

 __asm__(
  ".intel_syntax;"
  "mov eax, $1;"
  "mov ebx, $2;"
  "imul %0, ebx;"
  ".att_syntax;"
  : "=r"(c)
  : "r" (a), "r" (b)
  : "eax");

std::cout << c << std::endl;

【问题讨论】:

  • 那不是masm 所以不要用masm 标记它。不要使用eaxebx,除非您已正确编写约束。不要在内联 asm 中切换语法,如果要编写 intel 语法,请使用 -masm=intel。 (实际的错误当然是你需要.intel_syntax noprefix,但不要修复它。而是修复其他所有问题。)
  • 在 Intel 语法中,$1 是符号名称。英特尔语法不对立即数使用修饰符,mov $1, %eax 仅适用于 AT&T。一旦你解决了这个问题,你会发现其他所有东西都坏了。见小丑的评论。此外,您不需要mov 指令,只需告诉编译器将您的输入放在哪里,或者在任何地方使用%0 / %1 或命名操作数让它选择。见segmentation fault(core dumped) error while using inline assembly。如果您在 asm 模板中的第一条或最后一条指令是 mov,那么您通常做错了。
  • 哦,是的,应该是%1 用于操作数替换。
  • @Jester 我猜你是说clobber 列表不正确?
  • @Jester 我用 MASM 标记了它,因为 MASM 标记的 Stackoverflow 描述提到了 Intel 语法。

标签: gcc assembly x86 inline-assembly


【解决方案1】:

不要在内联 asm 中使用固定寄存器,特别是如果您没有将它们列为 clobber 并且没有确保输入或输出不会与它们重叠。 (这部分基本上是segmentation fault(core dumped) error while using inline assembly的翻版)

不要在内联汇编中切换语法,因为编译器会替换错误的语法。如果您需要 intel 语法,请使用 -masm=intel

要在 asm 模板字符串中引用参数,请使用 % 而不是 $ 前缀。 $1 没有什么特别之处;它被视为符号名称,就像您使用 my_extern_int_var 一样。链接时,链接器找不到$1 符号的定义。

不要mov 不必要的东西。还要记住,仅仅因为某些东西似乎在特定环境中工作,这并不能保证它是正确的,并且每次都可以在任何地方工作。内联汇编更是如此。你必须要小心。无论如何,固定版本可能如下所示:

__asm__(
  "imul %0, %1"
  : "=r"(c)
  : "r" (a), "0" (b)
  : );

必须使用-masm=intel 编译。注意b 已被放入与c 相同的寄存器中。


使用事实 imul 隐式乘以 eax

the normal 2-operand form of imul 不是这样。它与其他指令的工作方式相同,执行dst *= src,因此您可以使用任何寄存器,如果您甚至不想要它,也不会浪费 uops 在任何地方写入高半部分。

【讨论】:

  • 是否需要在内联汇编中使用固定寄存器?是否需要做出权衡/决定,或者只是始终使用占位符?
  • 一些指令需要特定的寄存器。否则,只需将寄存器分配留给编译器即可。即使这样。你会使用适当的约束,而不是 mov 周围的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
相关资源
最近更新 更多