使用堆栈框架外部的堆栈空间在cygwin上输出gcc [英] gcc output on cygwin using stack space outside stack frame

查看:77
本文介绍了使用堆栈框架外部的堆栈空间在cygwin上输出gcc的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看'objdump -S'的程序集输出,并发现了一些奇怪的东西.该版本适用于Windows 10上cygwin/x86_64 v.1.5.3和gcc 9.3.0.

这是特定功能的汇编输出(该功能无用,仅是问题的说明):

  u_int64_t returnit(u_int64_t x){1004010b9:55推Rbp1004010ba:48 89 e5 mov rbp,rsp1004010bd:48 83 EC 10子RSP,0x101004010c1:48 89 4d 10 mov QWORD PTR [rbp + 0x10],rcxu_int64_t a = 1;1004010c5:48 c7 45 f8 01 00 00 mov QWORD PTR [rbp-0x8],0x11004010cc:00返回+ x;1004010cd:48 8b 55 f8 mov rdx,QWORD PTR [rbp-0x8]1004010d1:48 8b 45 10 mov rax,QWORD PTR [rbp + 0x10]1004010d5:48 01 d0添加rax,rdx}1004010d8:48 83 c4 10添加rsp,0x101004010dc:5d pop rbp1004010dd:c3 ret 

几乎所有事物看起来都很正常:设置堆栈框架,并为局部变量留出额外的空间,然后将传递的参数(寄存器rcx中的"x")复制到堆栈上的某个位置.

这是看起来很奇怪的部分:

  mov QWORD PTR [rbp + 0x10],rcx 

它正在将rcx的内容复制到当前堆栈帧之外.局部变量按原样应存储在当前堆栈帧中.

我在较旧版本的cygwin(32位,v.2.9.0,带有gcc 6.4.0)上尝试了此操作,并且其行为方式相同.

我也在其他平台上尝试过-具有内核4.4.0和gcc 5.3.1的较早版本的ubuntu linux liveboot,以及具有64位的clang 8.0.1的FreeBSD 12.1盒-并且它们可以满足您的期望,复制在本地堆栈帧内的寄存器中传递的参数的值.例如,这是FreeBSD上的相关行(它使用rdi而不是rcx):

  2012e8:89 7d fc mov DWORD PTR [rbp-0x4],edi 

在cygwin上采用这种方式是否有某些特殊原因?

解决方案

此行为符合Windows x64 ABI.

查看

Windows使用的Microsoft x64调用约定与Linux,OS X等在x86-64上使用的System V AMD64 ABI中看到的约定不同.


该示例显示了MSVC(不同的编译器,但仍以Windows为目标)中优化的效果.无需在堆栈上实际存储值,只需一条指令即可完成计算.

I was looking at the assembly output of 'objdump -S' and noticed something strange. This was on cygwin/x86_64 v. 3.1.5 with gcc 9.3.0 on Windows 10.

Here is the assembly output of a particular function (the function is not useful and is merely illustrative of the problem):

u_int64_t returnit(u_int64_t x) {
   1004010b9:   55                      push   rbp
   1004010ba:   48 89 e5                mov    rbp,rsp
   1004010bd:   48 83 ec 10             sub    rsp,0x10
   1004010c1:   48 89 4d 10             mov    QWORD PTR [rbp+0x10],rcx
        u_int64_t a = 1;
   1004010c5:   48 c7 45 f8 01 00 00    mov    QWORD PTR [rbp-0x8],0x1
   1004010cc:   00

        return a + x;
   1004010cd:   48 8b 55 f8             mov    rdx,QWORD PTR [rbp-0x8]
   1004010d1:   48 8b 45 10             mov    rax,QWORD PTR [rbp+0x10]
   1004010d5:   48 01 d0                add    rax,rdx
}
   1004010d8:   48 83 c4 10             add    rsp,0x10
   1004010dc:   5d                      pop    rbp
   1004010dd:   c3                      ret

Almost everything looks normal: set up the stack frame, with extra space for the local variable, and copy the passed argument ("x", in register rcx) to a position on the stack.

Here's the part that seems odd:

mov    QWORD PTR [rbp+0x10],rcx

It's copying the contents of rcx OUTSIDE the current stack frame. Local variable(s) are stored in the current stack frame, as they should be.

I tried this on an older installation of cygwin (32-bit, v. 2.9.0 with gcc 6.4.0) and it behaved the same way.

I also tried this on other platforms - an older ubuntu linux liveboot with kernel 4.4.0 and gcc 5.3.1, and a FreeBSD 12.1 box with clang 8.0.1, both 64-bit - and they do what one would expect, copying the value of the argument passed in a register inside the local stack frame. For example, here's the relevant line on FreeBSD (it uses rdi instead of rcx):

2012e8:       89 7d fc                mov    DWORD PTR [rbp-0x4],edi

Is there some particular reason it's done this way on cygwin?

解决方案

This behaviour conforms to the Windows x64 ABI.

Looking at the x64 stack usage page from Microsoft, we can see that the ABI specifies that space is reserved on the stack the four registers arguments, even if fewer arguments are used. These are the home addresses, which act as a shadow of the actual argument registers.

This area can be used to save arguments that would otherwise be overwritten, to aid in debugging, etc. Given the amount of work being done for an extremely simple operation, I'm assuming that this is unoptimised/debugging code. An optimised compilation of the code would likely skip these redundant stores and loads, and might not touch memory aside from the ret.

The Microsoft x64 calling convention used by Windows is different from the one seen in the System V AMD64 ABI used by Linux, OS X, etc. on x86-64.


This example shows the effects of optimisation in MSVC (different compiler, but still Windows-targetting). Without having to actually store values on the stack, the calculation can be done in a single instruction.

这篇关于使用堆栈框架外部的堆栈空间在cygwin上输出gcc的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆