我想在Objective-C程序中对变量执行ROR和ROL操作。然而,我不能管理它-我不是一个组装专家。
到目前为止我所做的是:
uint8_t v1 = ....;
uint8_t v2 = ....; // v2 is either 1, 2, 3, 4 or 5
asm("ROR v1, v2");
我得到的错误是:
使用长度未知后缀的指令助记符
我该如何解决这个问题?
编辑:代码不需要使用内联汇编。但是,我还没有找到使用Objective-C/c++/C指令来做到这一点的方法。
在标准C中,您可以这样做:
var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift))
大多数编译器都会识别这种模式,并将其优化为单个指令(如果目标支持的话)。
您可以在这里阅读更多内容:http://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts
var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift))
不要使用这个代码。当shift
= 0时,它的行为没有定义。英特尔的ICC删除了带有未定义行为的语句。我知道第一手资料。
另外,代码不会通过Clang或GCC的未定义行为杀毒器。有关阅读,请参阅Clang的控制代码生成或GCC的未定义行为杀毒器- ubsan。
我得到的错误是:
的指令助记符
使用长度未知后缀
您正在使用两个工具之一- GCC或Clang。我认为苹果在Xcode 4默认切换到Clang,所以你可能正在使用Clang。
GCC将委托给GNU AS (GAS),而Clang将使用其集成汇编器。在这两种情况下,都应该使用AT&T内联汇编,因为Clang对Intel汇编的支持参差不齐。例如,Clang目前无法生成否定指令(又名LLVM Bug 24232)。
使用Clang时,需要指定操作数的大小。所以你将使用rolb
, rolw
, roll
, rolq
和朋友。这在Clang的语言兼容性|内联汇编页面中有文档。
8位旋转是这样的:
// Immediate
inline word8 rotlImmediate8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolb %1, %0" : "+mq" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word8 rotl8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolb %1, %0" : "+mq" (x) : "cI" ((unsigned char)y));
return x;
}
// Immediate
inline word8 rotrImmediate8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorb %1, %0" : "+mq" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word8 rotr8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorb %1, %0" : "+mq" (x) : "cI" ((unsigned char)y));
return x;
}
8位字需要对约束进行特殊处理。你不能使用+g
;相反,你需要+mq
。
这是16位的word版本:
// Immediate
inline word16 rotlImmediate16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolw %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word16 rotl16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolw %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
// Immediate
inline word16 rotrImmediate16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorw %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word16 rotr16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorw %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
32位版本:
// Immediate
inline word32 rotlImmediate32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("roll %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word32 rotl32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("roll %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
// Immediate
inline word32 rotrImmediate32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorl %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word32 rotr32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorl %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
最后,这是64位版本。你应该用__amd64
或__x86_64__
之类的东西来保护它。因为旋转量可以是[0,63]
,所以使用J
约束。
// Immediate
inline word64 rotlImmediate64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolq %1, %0" : "+g" (x) : "J" ((unsigned char)y));
return x;
}
// Immediate or register
inline word64 rotl64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolq %1, %0" : "+g" (x) : "cJ" ((unsigned char)y));
return x;
}
// Immediate
inline word64 rotrImmediate64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorq %1, %0" : "+g" (x) : "J" ((unsigned char)y));
return x;
}
// Immediate or register
inline word64 rotr64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorq %1, %0" : "+g" (x) : "cJ" ((unsigned char)y));
return x;
}
Clang不像GCC那样传播常量,所以使用Immediate-8版本的旋转时可能会遇到麻烦。参见强制Clang对Stack Overflow和LLVM的常量值"提前执行数学"漏洞24226。
你应该花点时间去看看John Regehr的《C/c++中的安全、高效和可移植旋转》。这有点反高潮。它说,一旦你在C/c++中正确地编写了旋转(即没有未定义的行为),它将不再被识别为旋转,并且旋转指令将不会生成。
最后,请参见不违反堆栈溢出标准的近常数时间旋转