【问题标题】:ROL / ROR on variable using inline assembly only in Objective-C [duplicate]仅在 Objective-C 中使用内联汇编对变量进行 ROL / ROR [重复]
【发布时间】:2013-05-08 17:47:37
【问题描述】:

几天前,我问了下面的问题。因为我需要一个快速的答案,所以我补充说:

代码不需要使用内联汇编。但是,我还没有找到使用 Objective-C / C++ / C 指令的方法。

今天,我想学点东西。所以我再次问这个问题,使用内联汇编寻找答案。


我想对 Objective-C 程序中的变量执行 ROR 和 ROL 操作。但是,我无法管理它——我不是装配专家。

这是我到目前为止所做的:

uint8_t v1 = ....;
uint8_t v2 = ....; // v2 is either 1, 2, 3, 4 or 5

asm("ROR v1, v2"); 

我得到的错误是:

未知大小后缀的指令助记符的未知使用

我该如何解决这个问题?

【问题讨论】:

  • 这是 ARM 还是 x86 还是 x86-64?
  • 这是一个非常恰当的评论。谢谢你写它。代码是 x86_64。
  • 这个问题不是重复的,我相信不需要编辑问题来解释它有什么不同因为我在写问题时已经这样做了FrankH.MonoloNT3RPldav1sThor just懒得看问题。关于为什么它不是重复的解释很难错过,因为它是问题中的第一个主题。

标签: objective-c xcode inline-assembly


【解决方案1】:

旋转只是两个班次 - 一些位向左,其他位向右 - 一旦您看到这种旋转很容易,无需组装。该模式被一些编译器识别并使用旋转指令进行编译。代码见wikipedia

更新:x86-64 上的 Xcode 4.6.2(其他未测试)编译双移位 + 或对 32 位和 64 位操作数进行旋转,对于 8 位和 16 位操作数,双移位 + 或被保留。为什么?也许编译器了解这些指令的性能,也许只是没有优化 - 但一般来说,如果你可以避免汇编器这样做,编译器总是最清楚!也可以在函数上使用static inline,或者使用与标准宏MAX相同方式定义的宏(宏具有适应其操作数类型的优点),可用于内联操作。

OP 评论后的附录

这里以 i86_64 汇编器为例,详细了解如何使用 asm 构造 start here

首先是非汇编版本:

static inline uint32 rotl32_i64(uint32 value, unsigned shift)
{
   // assume shift is in range 0..31 or subtraction would be wrong
   // however we know the compiler will spot the pattern and replace
   // the expression with a single roll and there will be no subtraction
   // so if the compiler changes this may break without:
   //    shift &= 0x1f;
   return (value << shift) | (value >> (32 - shift));
}

void test_rotl32(uint32 value, unsigned shift)
{
   uint32 shifted = rotl32_i64(value, shift);

   NSLog(@"%8x <<< %u -> %8x", value & 0xFFFFFFFF, shift, shifted & 0xFFFFFFFF);
}

如果您在 Xcode(产品 > 生成输出 > 汇编文件,然后在窗口底部的弹出菜单中选择 Profiling)中查看汇编器输出以进行分析(因此优化器启动),您将看到rotl32_i64 内联到 test_rotl32 并编译为循环 (roll) 指令。

现在自己直接生成汇编程序比 FrankH 展示的 ARM 代码要复杂一些。这是因为要获取变量移位值,必须使用特定寄存器cl,因此我们需要为编译器提供足够的信息来执行此操作。如下:

static inline uint32 rotl32_i64_asm(uint32 value, unsigned shift)
{
   // i64 - shift must be in register cl so create a register local assigned to cl
   // no need to mask as i64 will do that
   register uint8 cl asm ( "cl" ) = shift;
   uint32 shifted;
   // emit the rotate left long
   // %n values are replaced by args:
   //    0: "=r" (shifted) - any register (r), result(=), store in var (shifted)
   //    1: "0" (value) - *same* register as %0 (0), load from var (value)
   //    2: "r" (cl) - any register (r), load from var (cl - which is the cl register so this one is used)
   __asm__ ("roll %2,%0" : "=r" (shifted) : "0" (value), "r" (cl));
   return shifted;
}

test_rotl32 更改为调用 rotl32_i64_asm 并再次检查程序集输出 - 它应该是相同的,即编译器和我们一样。

进一步注意,如果包含 rotl32_i64 中被注释掉的屏蔽行,它本质上会变为 rotl32 - 编译器将为任何体系结构做正确的事情,所有这些都以 i64 版本中的单个 and 指令为代价.

所以asm 是不是你需要它,使用它可能会有些麻烦,编译器总是会自己做的一样好或更好......

HTH

【讨论】:

  • ARM 桶形移位器仅在寄存器全宽上运行,因此您可以告诉它旋转 32 位数量而不是 8/16 位数量。这就是为什么你得到双班/或非 32 位的原因。您可以将 8 位立即数移动到 32 位字中的任何位置,但不能旋转 32 位字中的任意字节。
  • @FrankH。 - 糟糕,我错过了在我的答案中指定 x86-64 - 它确实有 8 位和 16 位旋转 - 已编辑,谢谢。将你的 ARM 和上面的 x86-64 结合起来,我认为强调了我们都提出的观点:使用标准 C 代码并让编译器弄清楚
  • +1。 CRD,谢谢你的回复。 ROR 和 ROL 是更多的例子。我实际上对如何在内联汇编代码中使用局部变量更感兴趣。很多时候我看到像: "=r"(out) : "r"(in), "M"(N); 这样的代码却没有理解它。而clang关于内联汇编的页面更像是几句话……
  • @Adrien - 我添加了一个附录。
  • 非常感谢您的完美回答。
【解决方案2】:

ARM 中的 32 位循环将是:

__asm__("MOV %0, %1, ROR %2\n" : "=r"(out) : "r"(in), "M"(N));

其中N 必须是编译时常量。

但是桶形移位器的输出,无论是用于寄存器还是立即操作数,始终是全寄存器宽度;您可以将恒定的 8 位数量移动到 32 位字中的任何位置,或者 - 如此处 - 以任何方式移动/旋转 32 位寄存器中的值。
但是您不能使用单个 ARM 指令在寄存器中旋转 16 位或 8 位值。没有这样的存在。

这就是为什么编译器,在 ARM 目标上,当您使用“普通”(便携式 [Objective-]C/C++)代码(in &lt;&lt; xx) | (in &gt;&gt; (w - xx)) 时将为您创建 一个 32 位旋转的汇编指令,但对于 8/16 位的,至少 两个(一个正常的移位后跟一个移位的或)。

【讨论】:

  • 一方面,您花时间回答我,我很感激。另一方面,你投票结束了这个问题,确保没有人会添加任何答案,我不欣赏它。考虑到它不是上述问题的重复,这不仅不公平,而且完全不合适。您应该花时间阅读这两个问题。第一个允许非 ASM 代码作为答案,这个选项是由接受答案的作者忠实选择的。现在,我对 ans ASM 答案感兴趣。任何问题都不能有两个被接受的答案。
  • 我仍然断言它是重复的;你可以改变/澄清你原来的问题,你知道吗?发布两个完全相同的问题只是......为了声誉。
  • 您是否认为这两个问题是相互排斥的?一个是要求汇编答案,另一个不是。另外,我的知识是与编程/开发应用程序相关的所有事情都太少了,以至于我什至无法梦想获得任何声誉。我经常看问题。 1% 的简单问题会立即得到解答,其他 99% 的问题我无能为力。
猜你喜欢
  • 2013-04-29
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
  • 2013-01-15
  • 1970-01-01
  • 2010-11-26
  • 1970-01-01
相关资源
最近更新 更多