我在阅读gcc's guide on extended ASM的时候遇到了一个问题,编译器没有按照我想象的方式解释汇编。我想我应该用一个位旋转指令来尝试,因为这些在C中并不容易获得。
下面是我的C函数:
int rotate_right(int num,int count) {
asm (
"rcr %[value],%[count]"
: [value] "=r" (num)
: [count] "r" (count)
);
return num;
}
字符串
使用x86-64 gcc(trunk)-O 0编译输出:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov eax, DWORD PTR [rbp-8]
rcr eax,eax
mov DWORD PTR [rbp-4], eax
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
型
我遇到的问题是,GCC将我的内联程序集理解为“将EAX
旋转EAX
,而不是旋转我想要的count
参数。这是我 * 期望得到的:*
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov eax, DWORD PTR [rbp-8]
mov ecx, DWORD PTR [rbp-4]
rcr eax,ecx
pop rbp
ret
型
3条答案
按热度按时间xkftehaa1#
对
num
使用+r
约束,表明num
将被读取而不仅仅是写入。否则gcc将假定num
的先前值无关紧要,并仅选择一个未使用的寄存器将输出转储到其中。您还必须对
count
使用c
约束,因为ror
指令的移位量必须在cl
中。有关更详细的解释,请参阅other answer。在进行任何内联汇编编程之前,请仔细阅读the manual!要正确理解它有些棘手,并且有许多微妙的细节需要注意。
还要注意的是,即使内联汇编看起来工作正常,也可能是不正确的,例如,由于丢失了clobbers,而这些clobbers恰好不会影响与该特定编译器版本相关的任何内容,在该特定优化级别上,对于该特定版本的代码。所以要格外小心,尽可能避免使用它。
例如,在你的例子中,你可以只使用标准的C旋转习惯用法。只要启用了优化,编译器就会选择它:
字符串
wlsrxk512#
首先,让我来解决标题中提到的问题。
字符串
下面我将解释一些细节,但基本上,你必须仔细阅读GCC文档。
引用OP,
我真的发现gcc的内联asm语法比Visual Studio的差得多。这几乎就像GCC试图阻止用户使用汇编语言。
从某种意义上说,它需要更多的时间来学习,但在你了解细节之后,它是各种低级编程和优化的强大工具。
我在实际程序中使用内联汇编的一个例子是使用
rcpss
指令。有一个Intel内部的指令,但是当前版本的GCC(12.1)在你使用它处理一个float
时会产生相当可怕的代码。型
这是实际的代码。当
x
的值在编译时已知时,__builtin_constant_p
使常量替换成为可能。我故意将两个操作数相同以避免假依赖问题。查看程序集在某处被调用时是如何生成的。
型
您可以看到
float_recip(2)
被替换为0.5f
常量,所有不必要的副本都消失了。你不能用MSVC内联汇编来做这件事,除此之外,它甚至不支持64位。
ifsvaxew3#
与GCC没有区别,用C编写它。
字符串
测试结果:
型
你可以在这里玩:https://godbolt.org/z/3xfs5EhWv