在Objective-C中使用内联汇编对变量进行ROL / ROR



我想在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++中正确地编写了旋转(即没有未定义的行为),它将不再被识别为旋转,并且旋转指令将不会生成

最后,请参见不违反堆栈溢出标准的近常数时间旋转

最新更新