无约束内联汇编的引用变量
reference variables without constraint inline assembly
我想在 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
,因为它可能是 compiler/linker 优化的东西。我也尝试添加 __attribute__((used))
但其中的 none 有所帮助。我正在使用 GNU GCC v7.1.1
感谢任何帮助,谢谢。
如果可能,完全避免使用内联汇编。
如果必须使用内联汇编,请尽可能使用扩展内联汇编,并声明正确的操作数和破坏列表。在您的特定情况下,这样的事情会起作用:
#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 (
"movzbl %0, %%eax;" \
"movl %1, %%ebx;" \
"xor %%ebx, %%eax;" \
"movb %%al, %0;"
: "+m"(z) : "m"(key) : "eax", "ebx");
printf("%c\n", z);
}
return 0;
}
这里,"+m"(z)
是一个输出操作数,而"m"(key)
是一个输入操作数。 "eax", "ebx"
是 clobber 列表 指示您的代码覆盖了哪些寄存器。由于 asm
语句的所有副作用都通过其输出操作数和 clobbers 显式显示,因此可以省略 volatile
关键字以为编译器提供更大的灵活性。
请注意,除非要求 key
、z
和 e
是全局变量,否则最好将它们设为自动变量并使用额外的 r
或 i
输入和输出操作数的约束,使编译器更灵活地选择保留变量的位置。
还要注意更正后的操作数大小。 key
是一个 32 位变量,z
是一个 8 位变量。最后,我修复了 xor
指令。您不小心切换了操作数。
注意汇编代码可以做得更好。一种稍微更有效的呈现代码的方法是这样的:
#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 (
"xorb %b1, %0"
: "+m"(z) : "r"(key));
printf("%c\n", z);
}
return 0;
}
这会将 key
从内存加载到 C 编译器,使其能够就变量的保存位置做出更明智的选择。将 key
和 z
设为自动变量也可能是个好主意,但我不确定在您可能拥有的某些未命名约束下是否允许这样做。
我想在 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
,因为它可能是 compiler/linker 优化的东西。我也尝试添加 __attribute__((used))
但其中的 none 有所帮助。我正在使用 GNU GCC v7.1.1
感谢任何帮助,谢谢。
如果可能,完全避免使用内联汇编。
如果必须使用内联汇编,请尽可能使用扩展内联汇编,并声明正确的操作数和破坏列表。在您的特定情况下,这样的事情会起作用:
#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 (
"movzbl %0, %%eax;" \
"movl %1, %%ebx;" \
"xor %%ebx, %%eax;" \
"movb %%al, %0;"
: "+m"(z) : "m"(key) : "eax", "ebx");
printf("%c\n", z);
}
return 0;
}
这里,"+m"(z)
是一个输出操作数,而"m"(key)
是一个输入操作数。 "eax", "ebx"
是 clobber 列表 指示您的代码覆盖了哪些寄存器。由于 asm
语句的所有副作用都通过其输出操作数和 clobbers 显式显示,因此可以省略 volatile
关键字以为编译器提供更大的灵活性。
请注意,除非要求 key
、z
和 e
是全局变量,否则最好将它们设为自动变量并使用额外的 r
或 i
输入和输出操作数的约束,使编译器更灵活地选择保留变量的位置。
还要注意更正后的操作数大小。 key
是一个 32 位变量,z
是一个 8 位变量。最后,我修复了 xor
指令。您不小心切换了操作数。
注意汇编代码可以做得更好。一种稍微更有效的呈现代码的方法是这样的:
#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 (
"xorb %b1, %0"
: "+m"(z) : "r"(key));
printf("%c\n", z);
}
return 0;
}
这会将 key
从内存加载到 C 编译器,使其能够就变量的保存位置做出更明智的选择。将 key
和 z
设为自动变量也可能是个好主意,但我不确定在您可能拥有的某些未命名约束下是否允许这样做。