C++ C++;在Linux/x86-84上传递大对象的调用约定

C++ C++;在Linux/x86-84上传递大对象的调用约定,c++,linux,assembly,x86-64,calling-convention,C++,Linux,Assembly,X86 64,Calling Convention,我试图理解在C++/Linux/x86-64平台中,通过值传递对象作为函数参数的开销 我用于探索的实验代码发布在下面和godbolt.org上: 假设函数是一元函数。我观察到的是: 如果参数对象的大小为8字节,则将其放入RDI中 如果参数的大小为16字节(每个8字节包含两个子对象),则这两个子对象将放入RDI和RSI 如果参数大于16字节,将通过堆栈传递 我只考虑整型和指针以及这些基本类型的组成类型。我知道传球花球/双打是不同的 std::function的大小为32字节(GCC/Linux实现

我试图理解在C++/Linux/x86-64平台中,通过值传递对象作为函数参数的开销

我用于探索的实验代码发布在下面和godbolt.org上:

假设函数是一元函数。我观察到的是:

  • 如果参数对象的大小为8字节,则将其放入RDI中
  • 如果参数的大小为16字节(每个8字节包含两个子对象),则这两个子对象将放入RDI和RSI
  • 如果参数大于16字节,将通过堆栈传递
  • <>我只考虑整型和指针以及这些基本类型的组成类型。我知道传球花球/双打是不同的

    std::function
    的大小为32字节(GCC/Linux实现,long+long+pointer+pointer=32字节)。因此,按值传递
    std::function
    应该类似于我的代码中定义的pass
    struct Person4
    。但是输出程序集显示pass
    std::function
    与pass
    struct Person3
    非常不同。看起来std::函数是通过指针传递的,对吗?为什么会有这样的差异

    #include <functional>
    
    struct Person0 {
      long name;
    };
    
    long GetName(Person0 p) {
      return p.name;
    }
    
    struct Person1 {
      long name;
      long age;
    };
    
    long GetName(Person1 p) {
      return p.name;
    }
    
    struct Person2 {
      long name;
      long age;
      long height;
    };
    
    long GetName(Person2 p) {
      return p.name;
    }
    
    struct Person3 {
      long name;
      long age;
      long height;
      long weight;
    };
    
    long GetName(Person3 p) {
      return p.name + sizeof(p);
    }
    
    long Invoke(std::function<long(long)> f) {
      return f(20) + sizeof(f);
    }
    
    
    int main() {
      Person3 p;
      p.name = 13;
      p.age = 23;
      p.height = 33;
      p.weight = 43;
      long n = GetName(p);
    
      std::function<long(long)> ff;
      Invoke(ff);
      return 0;
    }
    
    #包括
    结构Person0{
    长名称;
    };
    长GetName(Person0 p){
    返回p.name;
    }
    结构人1{
    长名称;
    年龄长;
    };
    长GetName(person1p){
    返回p.name;
    }
    结构人2{
    长名称;
    年龄长;
    高;
    };
    长GetName(person2p){
    返回p.name;
    }
    结构人3{
    长名称;
    年龄长;
    高;
    长重;
    };
    长GetName(Person3 p){
    返回p.name+sizeof(p);
    }
    长调用(std::函数f){
    返回f(20)+sizeof(f);
    }
    int main(){
    人3p;
    p、 姓名=13;
    p、 年龄=23岁;
    p、 高度=33;
    p、 重量=43;
    长n=GetName(p);
    std::函数ff;
    调用(ff);
    返回0;
    }
    
    您要阅读的文档是,特别是第3.2.3节 «参数通过»

    大于32字节的结构,总是放在堆栈上。
    对于您描述的结构,引用的是
    struct Person4
    ,但您的代码中没有。是否是
    std::function
    的类型擦除使编译器执行此操作?(可能只是增加了混淆-有趣的问题)@Peter struct Person4应该是struct Person3,谢谢你指出这一点。TL:DR:在SSE/SSEUP的东西上,是一个结构或其他对象,由所有
    float
    /
    成员组成(例如
    \u m128
    )如果大小合适,可以使用XMM或YMM reg;否则,它就像任何物体一样。是的,最后一个能做到。事实上,如果您向
    Person3
    添加复制构造函数或析构函数,则其行为与
    std::function
    相同。非常感谢您的解释。