zoukankan      html  css  js  c++  java
  • x86-64栈帧中的“红色区域” red zone of stack frame on x86-64

    前几天看System V AMD64 ABI标准的时候发现栈帧的顶部后面有一块“red zone”,在学cs:app3e/深入理解操作系统的时候并没有遇到这个,总结一下。

    引用标准中的话:

    The 128-byte area beyond the location pointed to by %rsp is considered to be reserved and shall not be modified by signal or interrupt handlers. Therefore, functions may use this area for temporary data that is not needed across function calls. In particular, leaf functions may use this area for their entire stack frame, rather than adjusting the stack pointer in the prologue and epilogue. This area is known as the red zone.

    译:在%rsp指向的栈顶之后的128字节是被保留的——它不能被信号和终端处理程序使用。因此,函数可以在这个区域放一些临时的数据。特别地,叶子函数可能会将这128字节的区域作为它的整个栈帧,而不是像往常一样在进入函数和离开时靠移动栈指针获取栈帧和释放栈帧。这128字节被称作红色区域。


    简单点说,这个红色区域(red zone)就是一个优化。因为这个区域不会被信号或者中断侵占,函数可以在不移动栈指针的情况下使用它存取一些临时数据——于是两个移动rsp的指令就被节省下来了。

    然而,标准只说了不会被信号和终端处理程序侵占,red zone还是会被接下来的函数调用使用的,这也是为什么大多数情况下都是叶子函数(不会再调用别的函数)使用这种优化。下面我举一个例子:

    /*test.c*/
    
    long test2(long a, long b, long c)	/* 叶子函数 */
    {
    	return a*b + c;
    }
    
    long test1(long a, long b)
    {
    	return test2(b, a, 3);
    }
    
    int main(int argc, char const *argv[])
    {
    	return test1(1, 2);
    }
    

    编译汇编与反汇编:

    frank@under:~/tmp$ gcc test.c && objdump -d a.out
    

    得到test1test2对应的指令:

    00000000004004d6 <test2>:
      4004d6:	55                   	push   %rbp
      4004d7:	48 89 e5             	mov    %rsp,%rbp
      4004da:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
      4004de:	48 89 75 f0          	mov    %rsi,-0x10(%rbp)
      4004e2:	48 89 55 e8          	mov    %rdx,-0x18(%rbp)
      4004e6:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
      4004ea:	48 0f af 45 f0       	imul   -0x10(%rbp),%rax
      4004ef:	48 89 c2             	mov    %rax,%rdx
      4004f2:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
      4004f6:	48 01 d0             	add    %rdx,%rax
      4004f9:	5d                   	pop    %rbp
      4004fa:	c3                   	retq   
    
    00000000004004fb <test1>:
      4004fb:	55                   	push   %rbp
      4004fc:	48 89 e5             	mov    %rsp,%rbp
      4004ff:	48 83 ec 10          	sub    $0x10,%rsp
      400503:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
      400507:	48 89 75 f0          	mov    %rsi,-0x10(%rbp)
      40050b:	48 8b 4d f8          	mov    -0x8(%rbp),%rcx
      40050f:	48 8b 45 f0          	mov    -0x10(%rbp),%rax
      400513:	ba 03 00 00 00       	mov    $0x3,%edx
      400518:	48 89 ce             	mov    %rcx,%rsi
      40051b:	48 89 c7             	mov    %rax,%rdi
      40051e:	e8 b3 ff ff ff       	callq  4004d6 <test2>
      400523:	c9                   	leaveq 
      400524:	c3                   	retq  
    
    

    可以看到test1移动了栈顶指针来获取栈帧空间,即sub $xxx, %rsp + leaveq的组合。但是test2并没有移动栈顶指针,而是直接使用ebp/esp(此时它们两个相等,由于是叶子也不用考虑内存对齐的问题)存放要使用的数据。栈帧布局如下:


    最后提一点,Windows x64 ABI中并没有“red zone”这个概念,栈顶指针rsp的低地址处被认为是“volatile”和“unsafe”的——操作系统、调试器、终端处理程序等等都可能侵占该区域。

    参考:

    Stack frame layout on x86-64

  • 相关阅读:
    使用JavaScript让网页title动起来 TC
    Asp.net获取客户端登录者mac地址 TC
    HTTP错误 500.23Internal Server Error 检测到在集成的托管管道模式下不适用的ASP.NET设置 TC
    上下文字\图片滚动 无JS TC
    SQL语句优化(雷人代码) TC
    js获得url请求参数 TC
    HTTP状态码 TC
    Javascript之表格隔行变色 TC
    C# FTP上传文件报550异常解决方案 TC
    javascript 点击固定数据 隐藏或显示DIV TC
  • 原文地址:https://www.cnblogs.com/liqiuhao/p/7777723.html
Copyright © 2011-2022 走看看