在ARM体系结构中,C函数如何返回大小超过一个单词的值



在C程序中,内存布局由.BSS、.DATA、.TEXT、HEAP和STACK组成。当函数返回大小小于一个字的值时,它会进入R0寄存器,但如果返回值大于一个字,它会通过内存返回。例如:

LargeType t;
t = func(arg);

实现为:

LargeType t;
(void) func(&t,arg);

我的问题是编译器使用内存的哪一部分来过"t"?

ARM C++ABI基本上使用安腾C++ABI,但有例外。在该ABI中,按值返回大对象的调用约定是,调用者传递一个隐藏指针,函数使用该指针在return语句中创建对象。退货价值优化就是这样实现的。

现在,你提供的翻译是不正确的。您开始使用的代码使用赋值而不是初始化:

LargeType t;
t = func(arg);

编译器完成的翻译相当于:

LargeType t;
LargeType __tmp;
func(&__tmp,arg);
t.operator=(__tmp);
__tmp.~LargeType();

临时变量将在堆栈中创建,地址传递给将使用它创建对象的函数。然后赋值将发生,并且在完整表达式t = func(arg);的末尾,临时表达式将被销毁。

将其与初始化情况进行比较:

LargeType t = func(arg);

在这种情况下,编译器可以进行您提到的转换,翻译后的代码将是:

LargeType t;
func(&t,arg);

非常重要的区别在于初始化和赋值是完全不同的操作。在初始化的情况下,对象变成,什么都没有,现在有了。在赋值的情况下,对象已经,它有一个状态,并且可能正在管理资源。如果您建议的转换被允许,则此代码将泄漏内存:

struct Test {
   int *p;  // assume other members make this object large
   Test() : p(new int()) {}
   Test(int i) : p(new int) { *p = i; }
   Test(Test const & other) : p(new int) { *p = other->p; }
   ~Test() { delete p; }
   Test& operator=(Test const & other) { *p = other->p; }
};
Test f(int arg) {
    return Test(1)
}
Test t;
t = f(5);

转换后的代码将在哪里泄漏:

Test t;    // allocates a pointer
f(&t, 5);  // expands to:
           // __ret->p = new int;  // leak!
           // *(__ret->p) = 5;

调用func(&t,arg)将继续,并用所需值填充t的内存地址。因此,t必须在调用函数的堆栈上分配(除非您想对t进行动态分配,如t=malloc(sizeof(LargeType)),否则它将在堆上)。不确定编译器在这里要做什么。

/* Caller function */
...
LargeType t;     /* Allocated on caller's stack */
LargeType *t = malloc(sizeof(LargeType));    /* Allocation on heap */
(void) func(&t, arg);    /* Fills up t with required value */

最新更新