这些无用的流水线从何而来? [复制]

Posted

技术标签:

【中文标题】这些无用的流水线从何而来? [复制]【英文标题】:Where are these useless Assembly lines come from? [duplicate] 【发布时间】:2020-05-23 23:20:05 【问题描述】:

我开始学习汇编,所以我使用命令gcc -S file.c 来获取我的 C 代码的汇编版本。

一切正常,但我注意到当我输入一个简单的代码时,例如:

void    ft_return_strlen(char *str)

    int     a;

    a = strlen(str);
    return (a);

gcc -S file.c 命令给了我这个:

_ft_return_strlen:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rdi
    callq   _ft_strlen
    movl    %eax, -12(%rbp)
    movl    -12(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    retq

即使这个函数没用,为什么 gcc 给我这些行?

    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rdi

他们不是没用吗?如果这些行真的没用,它们是来自我的代码还是来自 gcc?有什么办法可以改善吗?

【问题讨论】:

尝试优化:gcc -O3 它们不是没用的,它们的存在是有原因的,但它与优化级别有关,尝试 -O2 或赌博 -O3 确实你是对的,当我使用优化时它们会消失。我将阅读有关此优化标志的更多信息。谢谢! 【参考方案1】:

未优化,编译器为变量str分配空间,即-8(%rbp)。顶部的所有代码都是在寄存器 rbp 和 rsp 之间为局部变量在堆栈上腾出一个空间。

函数调用将它放在寄存器 rdi 中,但调试器需要在名为 str 的变量中看到它。如果在调试器中您要更改变量 str,则需要将该新值作为参数复制回 strlen。

同样的情况发生在变量 a,-12(%rbp),它必须从返回寄存器 rax 复制,然后复制回来以返回,以防你在调试器中编辑它。

通过优化,变量被完全丢弃,但调试器知道等价物在寄存器中。在最大优化下,整个函数可以被删除,或者用 jmp 替换为 strlen,但是你根本无法调试它!

【讨论】:

但调试器知道等价物在寄存器中不幸的是,您通常会得到“优化”,而不是编译器打印一个存在于寄存器中的变量。至少在带有 GDB 的 GNU/Linux 上。 @PeterCordes 是的,它在调试器中的价值有限,因为寄存器经常被重用,但我发现它偶尔会给出答案。 如果你正在查看 asm,当然你可以自己 print $rdi,但我通常发现当一个 var 被优化为寄存器时,GDB 根本不知道去哪里看.可能在大多数情况下,C var 已被优化并被 GCC 发明的临时替代。 (如果您使用 -fverbose-asm 查看 GCC asm 输出,您会看到类似 D.1234 的名称)。我曾假设调试信息格式可能甚至无法指示 C 变量在寄存器中,但可能不是这种情况。

以上是关于这些无用的流水线从何而来? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

这些 1k 线程从何而来

Java 内存:引用从何而来?

“纯虚函数调用”崩溃从何而来?

Linux系统启动过程的打印信息从何而来?

我的“存储 PD 容量”费用从何而来?

javadoc 中的@uml.property 标签从何而来?