什么阻止g ++消除运行时未使用的临时std :: array?

 手机用户2502922083 发布于 2023-02-07 11:04

首先,很好的问题.

编辑:

我第一次没有正确阅读你的代码.您的代码中有一个重要的外部调用.这是在这个指令中e8 00 00 00 00 callq 2c <_Z3foov+0x2c>1.它不会提前调用地址 - 而是在链接时替换它的目标.这就是链接的工作方式 - 精灵文件会说"这样的指令会在链接时解析为这个目标." 汇编程序尚未完全列出,因此我们不知道此调用的地址.据推测它delete _value在代码中,但libstdc ++(与delet等)默认是动态链接的.您可以使用我的编译器标志来更改它,或者在gdb中进行列表(即链接后).

回到答案:

这是一个特殊情况,gcc程序员已经做出了不优化的选择.原因是运算符new和delete被标记为"弱符号",链接器将寻找备选方案,选择提供的用户或如果没有找到则退回.

以下是对此背后的基本原理的讨论.这些运营商旨在全球可更换,弱连接是一种解决方案.

静态链接不会改变这一点,因为glibc中的free和malloc仍然可以在链接时更改.

静态链接或使用链接时优化使用内置删除,但在这种情况下,如果您改为静态链接,则仍有机会丢失.然而,在你的原始例子中,没有这样的机会.

编译:

#include 
#include 
#include 

void * operator new(std::size_t n) throw(std::bad_alloc)
{
  return malloc(n);
}
void operator delete(void * p) throw()
{
if(p != nullptr)
  free(p);
}

class P {
  public:
    P() : _value(nullptr) {}
    ~P() { delete _value; }

  private:
   char *_value;
};

void foo() {
  if(std::array().size() != 4)
    assert(false);
}

int main(){
foo();
}

有了这个; g ++ -std = c ++ 11 -O3 -static -Wa,-alh test.cpp -o test

静态地链接到libstdc ++/glibc ,因此它应该知道free和malloc是什么,但是它并没有完全意识到foo是微不足道的.

然而,nm -gC test | grep free产生弱符号 __free_hook,我在这里找到了解释.因此,在使用gcc进行编译时,free和malloc(以及operator new和delete)的行为在链接时实际上总是可以更改.这就是阻止优化的原因 - 令人烦恼的是-fno-weak那些符号留在那里.

上面的段落是正确的,但是错过了优化的结果,而不是避免优化的原因.

通过链接时间优化,可以将gcc哄骗进行此优化,但首先必须使用-flto构建其他所有内容,包括libstdc ++.

这是静态构建示例时gcc为我做的最多:

Dump of assembler code for function _Z3foov:
0x08048ef0 <+0>:    push   %esi
0x08048ef1 <+1>:    push   %ebx
0x08048ef2 <+2>:    sub    $0x24,%esp
0x08048ef5 <+5>:    movl   $0x0,0x10(%esp)
0x08048efd <+13>:   lea    0x20(%esp),%ebx
0x08048f01 <+17>:   movl   $0x0,0x14(%esp)
0x08048f09 <+25>:   lea    0x10(%esp),%esi
0x08048f0d <+29>:   movl   $0x0,0x18(%esp)
0x08048f15 <+37>:   movl   $0x0,0x1c(%esp)
0x08048f1d <+45>:   lea    0x0(%esi),%esi
0x08048f20 <+48>:   sub    $0x4,%ebx
0x08048f23 <+51>:   mov    (%ebx),%eax
0x08048f25 <+53>:   test   %eax,%eax
0x08048f27 <+55>:   je     0x8048f31 <_Z3foov+65>
0x08048f29 <+57>:   mov    %eax,(%esp)
0x08048f2c <+60>:   call   0x804dea0 
0x08048f31 <+65>:   cmp    %esi,%ebx
0x08048f33 <+67>:   jne    0x8048f20 <_Z3foov+48>
0x08048f35 <+69>:   add    $0x24,%esp
0x08048f38 <+72>:   pop    %ebx
0x08048f39 <+73>:   pop    %esi
0x08048f3a <+74>:   ret  

对免费的呼吁不会随处可见.

如果是问题,请自行优化.模板使这很容易(假设std :: array作为模板参数传递,否则为什么要检查它的size()?).

#include 
#include 

class P {
  public:
    P() : _value(nullptr) {}
    ~P() { delete _value; }

  private:
   char *_value;
};

void foo() {
  if(std::tuple_size >::value != 4)
    assert(false);
}

int main(){
foo();
}

如果std::array是向量或其他东西,代码可以使其无声地失败,并回退到您的默认构造方法.

nm -C testW operator new(unsigned int, void*)当我添加时输出#include ,所以至少可以更改放置链接时间(它是一个弱符号) - 其他是特殊的,它们的最终目标位于libstdc ++中(同样,默认情况下它们是动态链接的).

1 个回答
  • 首先,很好的问题.

    编辑:

    我第一次没有正确阅读你的代码.您的代码中有一个重要的外部调用.这是在这个指令中e8 00 00 00 00 callq 2c <_Z3foov+0x2c>1.它不会提前调用地址 - 而是在链接时替换它的目标.这就是链接的工作方式 - 精灵文件会说"这样的指令会在链接时解析为这个目标." 汇编程序尚未完全列出,因此我们不知道此调用的地址.据推测它delete _value在代码中,但libstdc ++(与delet等)默认是动态链接的.您可以使用我的编译器标志来更改它,或者在gdb中进行列表(即链接后).

    回到答案:

    这是一个特殊情况,gcc程序员已经做出了不优化的选择.原因是运算符new和delete被标记为"弱符号",链接器将寻找备选方案,选择提供的用户或如果没有找到则退回.

    以下是对此背后的基本原理的讨论.这些运营商旨在全球可更换,弱连接是一种解决方案.

    静态链接不会改变这一点,因为glibc中的free和malloc仍然可以在链接时更改.

    静态链接或使用链接时优化使用内置删除,但在这种情况下,如果您改为静态链接,则仍有机会丢失.然而,在你的原始例子中,没有这样的机会.

    编译:

    #include <array>
    #include <cassert>
    #include <cstdlib>
    
    void * operator new(std::size_t n) throw(std::bad_alloc)
    {
      return malloc(n);
    }
    void operator delete(void * p) throw()
    {
    if(p != nullptr)
      free(p);
    }
    
    class P {
      public:
        P() : _value(nullptr) {}
        ~P() { delete _value; }
    
      private:
       char *_value;
    };
    
    void foo() {
      if(std::array<P, 4>().size() != 4)
        assert(false);
    }
    
    int main(){
    foo();
    }
    

    有了这个; g ++ -std = c ++ 11 -O3 -static -Wa,-alh test.cpp -o test

    静态地链接到libstdc ++/glibc ,因此它应该知道free和malloc是什么,但是它并没有完全意识到foo是微不足道的.

    然而,nm -gC test | grep free产生弱符号 __free_hook,我在这里找到了解释.因此,在使用gcc进行编译时,free和malloc(以及operator new和delete)的行为在链接时实际上总是可以更改.这就是阻止优化的原因 - 令人烦恼的是-fno-weak那些符号留在那里.

    上面的段落是正确的,但是错过了优化的结果,而不是避免优化的原因.

    通过链接时间优化,可以将gcc哄骗进行此优化,但首先必须使用-flto构建其他所有内容,包括libstdc ++.

    这是静态构建示例时gcc为我做的最多:

    Dump of assembler code for function _Z3foov:
    0x08048ef0 <+0>:    push   %esi
    0x08048ef1 <+1>:    push   %ebx
    0x08048ef2 <+2>:    sub    $0x24,%esp
    0x08048ef5 <+5>:    movl   $0x0,0x10(%esp)
    0x08048efd <+13>:   lea    0x20(%esp),%ebx
    0x08048f01 <+17>:   movl   $0x0,0x14(%esp)
    0x08048f09 <+25>:   lea    0x10(%esp),%esi
    0x08048f0d <+29>:   movl   $0x0,0x18(%esp)
    0x08048f15 <+37>:   movl   $0x0,0x1c(%esp)
    0x08048f1d <+45>:   lea    0x0(%esi),%esi
    0x08048f20 <+48>:   sub    $0x4,%ebx
    0x08048f23 <+51>:   mov    (%ebx),%eax
    0x08048f25 <+53>:   test   %eax,%eax
    0x08048f27 <+55>:   je     0x8048f31 <_Z3foov+65>
    0x08048f29 <+57>:   mov    %eax,(%esp)
    0x08048f2c <+60>:   call   0x804dea0 <free>
    0x08048f31 <+65>:   cmp    %esi,%ebx
    0x08048f33 <+67>:   jne    0x8048f20 <_Z3foov+48>
    0x08048f35 <+69>:   add    $0x24,%esp
    0x08048f38 <+72>:   pop    %ebx
    0x08048f39 <+73>:   pop    %esi
    0x08048f3a <+74>:   ret  
    

    对免费的呼吁不会随处可见.

    如果是问题,请自行优化.模板使这很容易(假设std :: array作为模板参数传递,否则为什么要检查它的size()?).

    #include <array>
    #include <cassert>
    
    class P {
      public:
        P() : _value(nullptr) {}
        ~P() { delete _value; }
    
      private:
       char *_value;
    };
    
    void foo() {
      if(std::tuple_size<std::array<P, 4> >::value != 4)
        assert(false);
    }
    
    int main(){
    foo();
    }
    

    如果std::array<P, 4>是向量或其他东西,代码可以使其无声地失败,并回退到您的默认构造方法.

    nm -C testW operator new(unsigned int, void*)当我添加时输出#include <new>,所以至少可以更改放置链接时间(它是一个弱符号) - 其他是特殊的,它们的最终目标位于libstdc ++中(同样,默认情况下它们是动态链接的).

    2023-02-07 11:06 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有