4

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

4

2 回答 2

2

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

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

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

你可以在这里阅读更多:http ://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts

于 2013-05-05T21:15:19.440 回答
1
var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift))

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

另外,代码不会通过 Clang 或 GCC 的未定义行为清理程序。如需阅读,请参阅 Clang 的Controlling Code Generation或 GCC 的Undefined Behavior Sanitizer – ubsan


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

您正在使用两种工具之一 - GCC 或 Clang。我认为 Apple 在 Xcode 4 前后默认切换到 Clang,因此您可能正在使用 Clang。

GCC 将委托给 GNU AS (GAS),而 Clang 将使用它的 Integrated Assembler。在这两种情况下,您都应该使用 AT&T 内联汇编,因为 Clang 对 Intel 汇编的支持参差不齐。例如,Clang 目前无法生成否定指令(又名LLVM 错误 24232)。

使用 Clang 时,需要指定操作数大小。因此,您将使用rolb, rolw, roll, and rolqand 朋友。这记录在 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 位字版本:

// 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 位版本。你应该用类似的东西来保护它__amd64or __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 版本的旋转时遇到问题。另请参阅Force Clang 以对 Stack Overflow上的常量值“提前执行数学运算”和LLVM 错误 24226


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

最后,另请参阅不违反Stack Overflow 标准的近乎恒定时间旋转。

于 2015-08-09T18:21:36.257 回答