前几天看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

x86-64栈帧中的“红色区域” red zone of stack frame on x86-64的更多相关文章

  1. X86-64寄存器和栈帧--牛掰降解汇编函数寄存器相关操作

    X86-64寄存器和栈帧 概要 说到x86-64,总不免要说说AMD的牛逼,x86-64是x86系列中集大成者,继承了向后兼容的优良传统,最早由AMD公司提出,代号AMD64:正是由于能向后兼容,AM ...

  2. X86-64寄存器和栈帧

    简介 通用寄存器可用于传送和暂存数据,也可参与算术逻辑运算,并保存运算结果.除此之外,它们还各自具有一些特殊功能.通用寄存器的长度取决于机器字长,汇编语言程序员必须熟悉每个寄存器的一般用途和特殊用途, ...

  3. JAVA栈帧

    简介 Java栈是一块线程私有的内存空间.java堆和程序数据相关,java栈就是和线程执行密切相关的,线程的执行的基本行为是函数调用,每次函数调用的数据都是通过java栈来传递的. Java栈与数据 ...

  4. 深入理解java虚拟机(十) Java 虚拟机运行时栈帧结构

    运行时栈帧结构 栈帧(Stack Frame) 是用于虚拟机执行时方法调用和方法执行时的数据结构,它是虚拟栈数据区的组成元素.每一个方法从调用到方法返回都对应着一个栈帧入栈出栈的过程. 每一个栈帧在编 ...

  5. Java虚拟机之栈帧

    写在前面的话:Java虚拟机是一门学问,是众多Java大神们的杰作,由于我个人水平有限,精力有限,不能保证所有的东西都是正确的,这里内容都是经过深思熟虑的,部分引用原著的内容,讲的已经很好了,不在累述 ...

  6. Java-JVM 栈帧(Stack Frame)

    一.概述 栈帧位置 JVM 执行 Java 程序时需要装载各种数据到内存中,不同的数据存放在不同的内存区中(逻辑上),这些数据内存区称作运行时数据区(Run-Time Data Areas). 其中 ...

  7. java 栈和栈帧

    文章转载自:http://www.tuicool.com/articles/URZrMnb jvm为每个新创建的线程都分配一个堆栈.堆栈以帧为单位保存线程的状态.jvm对堆栈只进行两种操作:以帧为单位 ...

  8. C函数调用过程原理及函数栈帧分析(转)

    在x86的计算机系统中,内存空间中的栈主要用于保存函数的参数,返回值,返回地址,本地变量等.一切的函数调用都要将不同的数据.地址压入或者弹出栈.因此,为了更好地理解函数的调用,我们需要先来看看栈是怎么 ...

  9. Linux内核调试方法总结之栈帧

    栈帧 栈帧和指针可以说是C语言的精髓.栈帧是一种特殊的数据结构,在C语言函数调用时,栈帧用来保存当前函数的父一级函数的栈底指针,当前函数的局部变量以及被调用函数返回后下一条汇编指令的地址.如下图所示: ...

随机推荐

  1. oracle 表查询(一)

    通过scott用户下的表来演示如何使用select语句,接下来对emp.dept.salgrade表结构进行解说. emp 雇员表字段名称   数据类型       是否为空   备注-------- ...

  2. TCHAR

    定义 TCHAR :通过define 定义的字符串宏 因为C++支持两种字符串:常规的ANSI编码 (使用""包裹).Unicode编码(使用L" "包裹).因 ...

  3. Oracle第一波

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  4. 使用http -server 搭建本地简易文件服务器

    安装 npm install http-server -g 使用 1. cd project . 2. hs [pwd] -o, 默认是当前路径 ./ 3. 其他选项 -p Port to use ( ...

  5. Chinese Rings hdu 2842 矩阵快速幂

    Chinese Rings Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  6. 1523. K-inversions URAL 求k逆序对,,,,DP加树状数组

    1523. K-inversions Time limit: 1.0 secondMemory limit: 64 MB Consider a permutation a1, a2, …, an (a ...

  7. Collecting Bugs poj2096 概率DP

                                                                Collecting Bugs Time Limit: 10000MS   Me ...

  8. Codeforces Round #425 (Div. 2)C

    题目连接:http://codeforces.com/contest/832/problem/C C. Strange Radiation time limit per test 3 seconds ...

  9. Excel更改单元格格式后无效

    问题描述: 比如修改了数据的自定义显示格式(日期显示 yyyy"年"m"月",手机号分段000-0000-0000),应用后发现只有部分生效,或者都不生效,再检 ...

  10. PHP和JS判断变量是否定义

    PHP中: 通过isset(变量名)来判断,定义返回true/未定义返回false JS中: 通过typeof来判断.