【问题标题】:converting for loop into assembly without initial test在没有初始测试的情况下将 for 循环转换为程序集
【发布时间】:2019-03-18 17:02:01
【问题描述】:

一个函数test_two有如下整体结构:

long test_two(unsigned long x) {

  long val = 0;
  int i;

  for(i=64; i != 0; i--) {
   val = (val<<1)|(x & 0x1);
   x>>=1;
  }

 return val;
}

gcc C 编译器生成以下汇编代码:

test_two:
 movl $64, %edx
 movl $0, %eax
.L10:
 movq %rdi, %rcx
 andl $1, %ecx
 addq %rax, %rax
 orq %rcx, %rax
 shrq %rdi
 subq $1, %rdx
 jne .L10
 rep ret

我误解了 cmp 指令。所以我编辑了我原来的问题,我希望有些人不会混淆我的问题。对不起他们。

【问题讨论】:

  • for(i=64 , i != 0 , i--) 无法编译。请发布显示问题的Minimal, Complete, and Verifiable example
  • addq 这样的指令不仅处理操作,它们还根据操作的结果设置一些标志,比如零标志。 jne 如果未设置零标志,则执行跳转。
  • 您的 asm 与您的 C 不匹配,即使您将 for 中的 , 更改为 ;short 在 x86-64 System V ABI 和 Windows x64 中都是 16 位类型,因此您会得到 subwgodbolt.org/z/Jq6EZb(但编译器可以将大多数其他操作提升为 dword 操作数大小以提高效率,因为有符号溢出是 UB。)更重要的是,结构不同:它以 movl $64, %edx 开头,然后像你一样将 EAX 归零期望来自 C 源代码。
  • @WeatherVane 是的,你是对的。我认为教科书不正确。

标签: c for-loop assembly x86-64


【解决方案1】:

条件跳转只检查条件代码(在本例中为 ZF),因此并不总是需要遵循cmp。条件码虽然由cmp设置,但也由其他操作设置,包括addsub,当结果为零时设置ZF标志。

似乎%rdi 对应于x,它遵循典型的参数传递约定。 val&lt;&lt;1 已转换为等效的 addq %rax, %rax

您可以看到按位和按位或指令(andl $1, %ecxorq %rcx, %rax)。对val 的分配是通过or 完成的。

然后你有x&gt;&gt;=1 作为shrq %rdi 后面跟着你的循环条件并返回。

【讨论】:

  • rdx=1 开头并使用addq $1, %rdx / jnz 作为循环条件将循环2^64 - 1 次。这不是一个等效循环(假设源应该是for(i=64 ; i != 0 ; i--)。这只是莫名其妙,也是问题被否决且无法回答的原因之一。与mov $65, %eax 相同。此代码看起来像gcc 输出(基于标签名称和使用单操作数shrq),它在test_two: 标签下,而不是test_two.ipo_clone.123 或其他任何东西,所以它是C 函数的独立定义,而不是过程间常量属性版本。
  • 我的工作是假设程序集实际上是正确的。事实上,这种假设是无效的。
  • 如果你切换前两个变量,我认为代码至少更接近正确。
  • 我已经根据我的 GCC 结果编辑了这个问题,这些结果相似,但在三个地方有所不同(将 short 改为 long 后)
  • 您忘记在编辑中将 short 更改为 long。为你解决了这个问题。我想知道 OP 是否手动输入并弄错了一堆东西?这可以解释缺少的逗号(直到我看到添加它们的编辑中的差异时我才注意到。)
猜你喜欢
  • 1970-01-01
  • 2019-02-16
  • 2015-02-22
  • 1970-01-01
  • 1970-01-01
  • 2019-11-21
  • 1970-01-01
  • 2021-07-12
  • 2014-05-26
相关资源
最近更新 更多