stack 扩展机制
来源:互联网 发布:sqlserver 视图 union 编辑:程序博客网 时间:2024/05/17 01:06
windows中,每个线程都关联一个stack,stack的默认大小是1M,用于存放临时变量,函数参数,返回地址等。
但是当一个线程开始运行的时候不是其相关stack的内存就真正被提交,因为如果一个进程有10个线程,那么如果这10个线程的stack的内存都被提交,那么虚拟内存就占用了10M,就需要想对应的页表项等开销,而且这10M到底是否被真的使用还是个未知数,所以系统的策略是只提交几个页面,然后通过一个guard page来实现按需提交。
先看一下GUARD_PAGE:
TEB at 7ffdf000
ExceptionList: 0013fd0c
StackBase: 00140000
StackLimit: 0013e000
0: kd> dt _TEB 7ffdf000
ntdll!_TEB
......
+0xe0c DeallocationStack : 0x00040000
1M stack 范围 StackBase ~ DeallocationStack
0: kd> .formats(0x140000-0x40000)/0n1024
Evaluate expression:
Hex: 00000400
Decimal: 1024
Octal: 00000002000
Binary: 00000000 00000000 00000100 00000000
Chars: ....
Time: Thu Jan 01 08:17:04 1970
Float: low 1.43493e-042 high 0
Double: 5.05923e-321
stack 大小 1024KB --- 1M
StackBase ~ StackLimit: 0013e000 这个是 COMMIT 的页面
StackLimit 下个页面是 MEM_COMMIT | PAGE_READWRITE | PAGE_GUARD
StackLimit 再下一个页面是 MEM_RESERVE
也就是说TEB,确切说是TIB记录着线程的guard page。
当一个函数的局部变量过大,例如:char szBuffer[0x10000] = { 0 },那么线程被系统预先提交的页不满足使用了,那么编译器会在该函数的开头插入_chkstk,用以给该函数提交足够大的stack的页面用以装载很大的局部变量。
_chkstk的核心一个是使ESP减少,另一个就是提交页面,提交页面是个很有趣的过程:
test dword ptr [eax],eax; 可是这行代码仅仅是读了一下eax指向的内存, 这里的读操作将触发一个STATUS_GUARD_PAGE异常, 内核通过捕获这个异常,
从而知道你的线程已经越过了栈中已提交内存区域的边界, 这时应该增加新的页了。操作系统规定栈中的页commit必须逐页提交, 具体的实现是, 对已提交的内存区域的最后一个页设置
PAGE_GUARD属性,当这个页发生 STATUS_GUARD_PAGE异常时(这个异常会自动清除其 PAGE_GUARD属性), 再commit下一个页, 同时设置其 PAGE_GUARD属 性。
typedef struct _NT_TIB
{
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
PVOID StackBase; // 栈的最高地址 , 栈底
PVOID StackLimit; // 已经commit的栈的内存的最低地址, 栈顶,
.....
} NT_TIB;
栈的内存如此排布:
StackBase ----> |..............| <----- 高
|______| |
|..............| |
|______| |
|..............| Protect 00000004 PAGE_READWRITE
|______| State 00001000 MEM_COMMIT
|..............|
|______| |
|..............| |
|______| |
|..............| |
StackLimit ---> |______| <____|__
|..............| Protect 00000104 PAGE_READWRITE | PAGE_GUARD
|______| <___State 00001000 MEM_COMMIT
|..............| |
|______| |
|..............| |
|______| State 00002000 MEM_RESERVE (没有Commit的页谈不上Protect)
|..............| |
|______| |
|..............| <----
当一个线程被创建的时候, 操作系统会给它的栈reserve一块区域, 通常大小为1M, 然后立刻在栈顶commit n个pages。
前n-1 个Page是供线程立刻可以使用, 第二个page是守护页面(guard page), 当线程用完第一个页面的时候, 需要更多栈内存会访问到守护页面, 操作系统会得到通知。
系统会再commit一个页面,把下一个页面作为新的守护页面。
- stack 扩展机制
- gcc-stack-protector机制
- z-stack 各层间通信机制
- 扩展.net安全机制
- UML扩展机制
- UML扩展机制
- Objective_C扩展机制学习
- iOS扩展机制 - associative
- UML 可扩展机制
- jQuery事件扩展机制
- iOS 扩展机制 Associative
- iOS扩展机制
- CI的扩展机制
- *** stack smashing detected ***与GCC “stack smashing detected”机制
- java中使用LinkedList实现stack机制
- Z-stack中OSAL任务机制分析
- Z-stack中OSAL任务机制分析
- Linux系列- Linux权限机制、扩展机制
- 21世纪初最有影响力的20篇计算机视觉期刊论文
- 内联函数和宏
- Android 强制杀死某个应用程序的方法
- DOM解析xml
- 开源 免费 java CMS - FreeCMS-功能说明-静态化管理
- stack 扩展机制
- 数字电视复用器中的PCR校正技术
- 简单的QQ在线探测
- SAX 解析
- INLIST ITERATOR与CONCATENATION区别
- NewInt 4
- asp.net 用户控件中 使用相对路径的解决方法-------- 图片路径问题(用户控件、图片路径) ,ResolveUrl
- Android平台开发游戏
- ASP.NET Web页生命周期和执行的方法