【发布时间】:2021-01-10 18:09:43
【问题描述】:
我想在 C 程序中使用内联汇编,而不使用约束,因为我不想在我足够复杂的学校论文中解释这一点。我试图用一个键异或一些字符。代码如下:
#include <stdio.h>
char text[11] = {'H','e','l','l','o'};
int key = 42;
int e;
char z;
int main()
{
for (e=0; e<12; e++){
z = text[e];
asm volatile(
"movl $z, %ax;" \
"movl $key, %bx;" \
"xor $ax, %bx;" \
"movl $ax, %[z];");
printf("%c\n", z);
}
return 0;
}
但我不断得到:
main.c:11:13: error: undefined named operand ‘z’ "movl $key, %ax;" \
我尝试在变量前面添加static,因为它可能是编译器/链接器优化的东西。我也尝试添加__attribute__((used)),但没有任何帮助。我正在使用 GNU GCC v7.1.1
任何帮助表示赞赏,谢谢。
【问题讨论】:
-
要解决您遇到的直接问题,请使用
z和key而不是%[z]、$z和$key来访问变量。请注意,代码仍然不正确,因为您在未通知编译器的情况下破坏了寄存器。 -
重要的是所需的寻址模式不同(对于 64 位模式,您需要
z(%rip)而不是z)。编译器假定在asm语句之后,所有寄存器都保留其先前的值。您通过覆盖ax和bx违反了此假设,导致行为未定义。它现在可能看起来有效,但以后可能会以神秘的方式失败。如果您愿意,我可以写一个概述如何正确执行此操作的答案。 -
如果您修改任何寄存器或其余代码读取或写入的任何内存变量,就不可能在函数内安全地使用 GNU C Basic asm(无约束)。对于 x86-64,您也不能使用堆栈来推送/弹出,因为这会破坏红色区域。您可能会想出可能会正常工作的代码(在调试版本中),但要使其真正安全是不可能的。编写大量错误的代码而不解释它似乎是一个非常糟糕的主意。
-
(虽然在某些时候 GCC 决定让非空的基本 asm 语句具有隐含的
"memory"clobber,但这没有记录,基本上只是为了使旧代码和/或错误代码发生 -更频繁地工作。不要在新代码中依赖它。gcc.gnu.org/wiki/ConvertBasicAsmToExtended) -
这是我学校论文的例子 - 请不要写一个任何人都不应该做的事情的例子。 GNU C 内联 asm 已经够难了,人们不会被不安全的例子误导。 永远不要鼓励在任何地方使用 GNU C Basic asm,除非是在全局范围内,或者作为
__attribute__((naked))函数的整个主体。两者都与在单独的 .S 文件(您可以从普通 C 中调用)中用 asm 编写整个函数没有根本不同,如果您想避免处理约束,您实际上应该这样做。
标签: c assembly gcc compiler-errors inline-assembly