【发布时间】:2018-11-04 01:57:24
【问题描述】:
环境:Debian 9.5 - gcc 6.3.0
当我尝试使用多个 InputOperands 时,无法让嵌入式汇编函数工作。
我有以下代码工作(基本rol 函数,1 InputOperand,预定义rol 操作数):
#include <stdio.h>
#include <stdlib.h>
void asm_rol(int32_t* p_rolled)
{
__asm__ volatile
(
".intel_syntax noprefix;"
"rol %0, 1;"
:"=a"(*p_rolled)
:"a"(*p_rolled)
:"cc"
);
}
int main(int argc, char** argv)
{
int32_t test = 0x1;
asm_rol(&test);
printf("0x%08x\n", test);
return 0;
}
这打印出0x00000002,是rol 0x1, 1 的正确结果。
现在我不明白为什么下面的代码无法编译。我认为我对InputOperands 的使用不好:
#include <stdio.h>
#include <stdlib.h>
void asm_rol(int32_t* p_rolled, int16_t i)
{
__asm__ volatile
(
".intel_syntax noprefix;"
"rol %0, %1;"
:"=a"(*p_rolled)
:"a"(*p_rolled), "b"(i)
:"cc"
);
}
int main(int argc, char** argv)
{
int32_t test = 0x1;
asm_rol(&test, 1);
printf("0x%08x\n", test);
return 0;
}
gcc 返回错误:
resolve.c: Assembler messages:
resolve.c:6: Error: operand type mismatch for `rol'
我用int8_t 和int32_t 尝试了i,它没有任何改变。
我必须说我是在这种环境下在 C 中嵌入 asm 的新手,我只在 Windows 上使用 Visual Studio 完成了一些基本的内联汇编。
【问题讨论】:
-
因为唯一允许用于控制移位位数的移位指令的寄存器是 CL。
-
void asm_rol(int32_t* p_rolled, int8_t i) { __asm__ volatile ( ".intel_syntax noprefix;" "rol %0, %1;" :"+a"(*p_rolled) :"cI"(i) :"cc" ); }可能工作 -
因为
%1可能意味着%2。 %2 表示它映射到第三个约束。约束编号基于 0 (0=1, 1=2, 2=3) -
@NdFeB:因为该 asm 语句中的班次计数为
%2。使用命名约束,如asm("rol %0, %[count]", blah blah, [count] "cI" (i) );并使用"+r"作为读写输入/输出操作数;没有理由强制编译器使用 EAX/RAX。无论如何,所有这些仍然比纯 C 更糟糕,因为它破坏了持续传播和其他可能的优化。 -
在调试内联 asm 时,您应该查看编译器生成的 asm 以查看它替换到模板中的内容。例如godbolt.org 很方便:How to remove "noise" from GCC/clang assembly output?。您甚至可以执行
nop # %0 %1 %2之类的操作,以查看编译器为所有操作数选择的内容,无论您是否在模板中引用它们。有关更多指南和示例,另请参阅 stackoverflow.com/tags/inline-assembly/info。