【问题标题】:ROL / ROR on variable using inline assembly in Objective-C在 Objective-C 中使用内联汇编对变量进行 ROL / ROR
【发布时间】:2013-04-29 13:25:07
【问题描述】:

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

【问题讨论】:

  • 您确定需要组装吗?只有当这是一个性能瓶颈时才需要这样做。对于正常使用,使用var = (var << shift) | (var >> (sizeof(var)*8-shift)) 就可以了。
  • 更多详情,en.wikipedia.org/wiki/…
  • 不错。感谢你的回复。既然这回答了这个问题,如果你把它作为一个答案,我会接受它。

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


【解决方案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 将使用其集成汇编器。在这两种情况下,您都应该使用 AT&T 内联汇编,因为 Clang 对 Intel 汇编的支持参差不齐。例如,目前是Clang can't generate a negate instructions(又名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++ 中正确编写了旋转(即没有未定义的行为),它将不再被识别为旋转,并且不会生成旋转指令

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

【讨论】:

    【解决方案2】:

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

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

    无论如何,大多数编译器都会识别该模式并将其优化为一条指令(如果目标支持它)。

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

    【讨论】:

    • ++posting++;特别注意维基百科文章中的references,其中引用了gcc / clang 在将此类代码转换为可用的硬件旋转方面应用的优化。由于 Objective C/C++ 总是意味着 gcc / clang,因此可以安全地假设应用了优化。此外,对于 ARM, 将旋转编码为 单独指令 更好,因为桶形移位器可以将旋转“集成”到任何算术中; var = rotate(var, xxx) + 1 是 ARM 中的 单指令,但只有在 not 拆分为函数调用/内联 asm 时才能检测到。
    • 感谢您的回复。这是最有帮助的。你碰巧知道如何使用内联汇编来做到这一点吗?我之所以问,是因为我很好奇代码是什么样的,以及如何在该汇编代码中引用局部变量。
    • 如何在汇编中编写代码取决于您的目标架构。我自己不能编写汇编(意思是学习),但从错误消息的外观来看,我猜你需要告诉它你想要一个 32 位还是 64 位操作,或者类似的东西。也许这个页面会有所帮助:sourceware.org/binutils/docs/as/i386_002dMnemonics.html
    猜你喜欢
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    • 2012-11-17
    相关资源
    最近更新 更多