X86 程序集:为啥一个基本块有 cmp 和测试指令,似乎重复工作 [重复]

Posted

技术标签:

【中文标题】X86 程序集:为啥一个基本块有 cmp 和测试指令,似乎重复工作 [重复]【英文标题】:X86 assembly: Why a basic block has cmp and test instructions, seems duplicate of work [duplicate]X86 程序集:为什么一个基本块有 cmp 和测试指令,似乎重复工作 [重复] 【发布时间】:2020-12-19 03:03:44 【问题描述】:

这是我的 c 函数:

bool equalA = true;

for (int i = 0; i < 4; i++) 
    
    if (str[i] != 'a') 
        equalA = false; 
    

if (equalA == true) 
    if(str.compare(4, 6, "matches")) 
        printf("%s", "matches\n");
    

这是部分汇编代码:

movzbl  (%rax), %eax
cmpb    $97, %al
setne   %al
testb   %al, %al
je  .L5
movb    $0, -981(%rbp)
.L5:
addl    $1, -980(%rbp)
jmp .L6

上面的代码用'a'检查str[i],如果不相等,movb 将equalA 设置为false。如果相等,跳转到.L5。并继续循环。

我的问题是: 不应该

  cmpb  $97, %al
  je .L5 

会做同样的工作吗?

如果 str[i] == 'a', zflag 将被设置,je .L5 将采用分支。 如果 str[i] != 'a',zflag 将被清除。 je .L5 不会接受分支。

Compiler 为什么在 cmpb 指令后生成两行额外代码?

【问题讨论】:

如果没有优化,编译器按照字面意思解释代码是有意义的:创建一个标志,然后测试该标志。这就是你写的,所以这就是发生的事情,因为优化被关闭了。 你告诉编译器不要优化,所以它没有。碰巧选择将比较的bool结果物化到寄存器中,然后进行测试。由于-O0,它已经不得不将其存储到内存中。 @syacer 请don’t assume you know who voted;你问为什么这篇文章被否决了,有人试图给你反馈。不要将两者联系起来。投票是本网站的正常行为,因此请不要私自投票。 @syaet:请阅读我们的code of conduct,并将处理行为留给我们的版主。 【参考方案1】:

你是对的,它也应该这样做。我假设您没有在启用优化的情况下进行编译。很难解释为什么 C 编译器会生成某些代码。顺便说一句,不同的编译器可能生成了不同的代码。尽管启用了优化,但另一个可能会生成此代码。

但是,这是一种极端的过度简化,有关程序优化的更多详细信息,请参阅下面@PeterCordes 的精彩评论。

【讨论】:

是的,没有优化。 启用优化,这些额外的行很可能会消失。大多数 C/C++ 编译器的代码生成器会生成某种“模板代码”,其中留有优化空间,留给后一个优化阶段,该阶段可以更轻松地处理此类冗余并跨多个此类“模板”。 @Tom:这是一个过于简单的描述,以至于不准确。像这样的优化主要发生在程序逻辑的内部表示上,通常是SSA 形式。对于 GCC,它是 GIMPLE (SSA),然后是用于寄存器分配和东西的 RTL,最后是生成 asm。因此,它不会将您的源代码转换为 x86 asm 模板,然后 然后 会优化这些模板;当程序逻辑处于特定机器和寄存器分配细节较少的状态时,它会在生成 asm 之前进行优化。

以上是关于X86 程序集:为啥一个基本块有 cmp 和测试指令,似乎重复工作 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向x86 汇编 ( cmp 比较指令 | test 比较指令 )

Android 逆向x86 汇编 ( cmp 比较指令 | test 比较指令 )

带括号和地址的 x86 中的 CMP

在 c++ 中使用 x86 DIV 的这个 asm 块有啥用?

x86 cmp 寄存器和内存 - 中间数据保存在哪里?

求助!为啥X86以上的CPU指令集不提供给用户呢?比如X86-64,sSSE3等等。