【发布时间】:2015-05-13 01:10:00
【问题描述】:
我的汇编技能相当差,但我一直在努力更好地理解汇编,以提高我对分析会话和优化编译器工作原理的理解。
在研究 Windows 的 64 位调用约定时,我从未停下来真正思考过的一件事是:
struct BigUdt
{
double buf[16]; // exceeds 64 bits
};
struct BigUdt create_big_udt();
...如果我正确理解文档,create_big_udt 通常会为struct BigUdt 分配内存(我假设在堆栈上)并将地址返回到rax 中的内存。
所以,从汇编的角度来看,我的问题是:就职责而言,调用者在哪里?我假设有人有责任将sizeof(BidUdt) 添加回来在某个时候到rsp。对于大小不是 64 位的倍数的类型,64 位堆栈对齐是否会成为这里的一个问题,或者 struct BigUdt's 填充会覆盖吗?
唷,我希望这是一个合理的问题。我发现调用者和被调用者之间的这些 ABI 合同以及调用约定非常令人生畏,并且是迄今为止学习汇编中最难的部分之一。
【问题讨论】:
-
一个简单的事情是构建简单的测试,组装和反汇编它们,看看符合该 abi 的编译器做了什么
-
一直在做这种逆向工程,试图弄清楚这些调用约定!对于上述这种情况,我发现令人困惑的一件事是,如果我正确理解了反汇编,那么在我们从调用者返回时,调用这样的函数似乎会使
rsp保持不变/恢复。因此,似乎不必将添加回rsp的责任留给被调用者,但也许它确实需要在将其覆盖到堆栈中之前立即使用该数据。优化器如何处理这个问题让我的大脑想爆炸。 -
啊,你说的是调用者而不是被调用者。只是一个猜测,我会假设被调用者将它设置在堆栈上并恢复堆栈,让它挂在风中,调用者如果它实际上想要该值将有一个变量,该变量将是本地或全局的,并且取决于将被分配某处。如果足够大,分配 ret=function() 将生成一个 memcpy()。但我还没有尝试过确认....
-
非常感谢——当我检查编译器的反汇编时,“悬在风中”的比喻似乎与我所看到的相符。这也更令人欣慰——我认为如果调用者事后忘记对
rsp做某事,那里可能会发生灾难。
标签: windows assembly 64-bit calling-convention