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

时间:2013-05-05 18:33:45

标签: objective-c xcode x86-64 inline-assembly

我想在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指令的方法。

2 个答案:

答案 0 :(得分:2)

要在标准C中执行此操作,您可以执行以下操作:

var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift))

大多数编译器都会识别该模式并将其优化为单个指令(如果目标支持它)。

您可以在此处阅读更多内容:http://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts

答案 1 :(得分:0)

var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift))

不要使用此代码。当shift为0时,它具有未定义的行为。英特尔的ICC删除具有未定义行为的语句。我知道第一手资料。

另外,该代码不会通过Clang或GCC的Undefined Behavior sanitizer。如需阅读,请参阅Clang的Controlling Code Generation或GCC Undefined Behavior Sanitizer – ubsan

  

我得到的错误是:
     未知使用具有未知大小后缀的指令助记符

您正在使用两种工具之一 - GCC或Clang。我认为Apple默认在Xcode 4周围切换到Clang,所以你可能正在使用Clang。

GCC将委托GNU AS(GAS),而Clang将使用其Integrated Assembler。在这两种情况下,您都应该使用AT&amp; T内联汇编,因为Clang对Intel汇编的支持很不稳定。例如,目前Clang can't generate a negate instructions(a.k.a。LLVM Bug 24232)。

使用Clang时,需要指定操作数大小。因此,您将使用rolbrolwrollrolq以及朋友。这在Clang的Language Compatibility | Inline Assembly页面中有记录。

这里是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位字版本:

// 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版本的旋转。另请参阅Stack Overflow上的Force Clang to “perform math early” on constant valuesLLVM Bug 24226

你应该花点时间访问John Regehr的Safe, Efficient, and Portable Rotate in C/C++。它的那种反高潮。它说,一旦你在C / C ++中正确地编写旋转(即没有未定义的行为),它将不再被识别为旋转,并且生成旋转指令赢得。 / p>

最后,另请参阅Stack Overflow上的Near constant time rotate that does not violate the standards