我的装配技能相当差,但我一直在努力更好地理解装配,以提高我对分析会话的理解以及优化编译器的工作方式。
在研究Windows的64位调用约定时,我从未停止在机器级别考虑过的事情之一就是给出类似这样的东西:
struct BigUdt
{
double buf[16]; // exceeds 64 bits
};
struct BigUdt create_big_udt();
...如果我理解文档正确,create_big_udt
通常会为struct BigUdt
分配内存(我假设在堆栈上)并将地址返回到{{1}中的内存1}}。
因此,从集会的角度来看,我的问题是:在职责范围内离开调用者的地方是什么?我假设有人负责添加{{ 1}}在某些时候回到rax
。对于尺寸不是64位的倍数的类型,还是sizeof(BidUdt)
填充覆盖的类型,64位堆栈对齐也会成为一个问题吗?
答案 0 :(得分:1)
documentation非常明确:
否则,调用者承担分配内存的责任 并将返回值的指针作为第一个参数传递。 然后,后续参数将一个参数移到右侧。该 RAX中的被调用者必须返回相同的指针。
所以基本上foo bar(...)
变成了foo* bar(foo* retval, ...)
。指针可以指向调用者想要结果的位置(通常它将是调用者堆栈帧中的局部变量的地址),这当然不受调用中涉及的堆栈操作的影响,并且始终是有效的内存,堆栈或除此以外。它永远不会“悬在风中”(如果我理解这个术语的话),因为那确实会成为一场灾难。