windows的用户栈和内核栈

来源:互联网 发布:中缅翻译软件 编辑:程序博客网 时间:2024/04/30 00:51

windows的用户栈和内核栈

1、简介

         普通的Win32线程有两个栈:一个是用户栈,另一个是内核栈;而如果是内核中创建的系统工作线程,则只有内核栈。只要代码在内核中运行,线程就一定是使用其内核栈的。栈的主要作用是维护函数调用帧,以及为局部变量提供空间。

         在Windows里,一个线程的用户空间的信息都记录在了TEB中,而TEB中又有一个域叫做NtTib,这里面就存放着有关用户站的信息。由于TEB结构过于复杂,这里只列举涉及到的,完整的定义在这一部分的末尾给出。

         typedef struct PEBTEB_STRUCT(_TEB) {

                  PEBTEB_STRUCT(NT_TIB) NtTib;

                  ….

                  …

                  …

         }

         typedef struct _NT_TIB {

             struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;

             PVOID StackBase;

             PVOID StackLimit;

             PVOID SubSystemTib;

             union {

                 PVOID FiberData;

                 ULONG Version;

             };

             PVOID ArbitraryUserPointer;

             struct _NT_TIB *Self;

         } NT_TIB;

         其中NtTib中的StackBase就是用户栈的基地址了。用户栈的大小只要用通过栈底地址和栈顶地址简单相减就可以得到了。

         而内核线程的一些信息存储在了KTHREAD结构体中,KTHREAD的大致结构如下:

         typedef struct _KTHREAD {

             ....

             // The following fields are referenced during trap, interrupts, or

             // context switches.

             //

             // N.B. The Teb address and TlsArray are loaded as a quadword quantity

             //      on MIPS and therefore must be on a quadword boundary.

             PVOID InitialStack;

             PVOID StackLimit;

             .....

             PVOID StackBase;

             KAPC SuspendApc;

             KSEMAPHORE SuspendSemaphore;

             LIST_ENTRY ThreadListEntry;

             ....

         } KTHREAD, *PKTHREAD, *RESTRICTED_POINTER PRKTHREAD;

 

2、一些需要注意的地方

         用户栈可以指定其大小,默认是1MB,通过编译指令/stack可改设其他值。

         普通内核栈的大小是固定的,由系统根据CPU架构而定,x86系统上为12KB,x64系统上为24KB,安腾系统上为32KB。对于GUI线程,普通内核栈空间可能不够,所以系统又定义了“大内核栈”概念,可以在需要的时候增长栈空间。只有GUI线程才能使用大内核栈,这也是系统规定的。

         Windows将GDI和USER模块,即“窗口与图形模块”的实现移到了内核中,称为Windows子系统内核服务,并形成一个win32k.sys内核文件。而用户层仅留调用接口,由User32.dll和GDI32.dll两个文件暴露出来。判断一个线程是不是GUI线程的依据,竟非常的简单:线程初建时,都是普通线程,第一次调用Windows子系统内核服务(只要用户程序调用了User32.dll和GDI32.dll中的函数,并导致相关内核服务在内核中被执行),系统即立刻将之转变为GUI线程,并从而切换到“大内核栈”;倘若至线程结束,并未有任何一个子系统内核服务被调用,那么它一直都是普通线程,一直使用普通内核栈。

        内核栈的问题,正是内核中使用C++的一个最大障碍。在实际编程时,为了尽量避免发生栈溢出错误,需要经常对栈剩余空间保持一份警惕,尤其在可能形成很深的调用栈(如递归调用)的情况下。内核函数IoGetStackLimits与IoGetRemainingStackSize分别用来获取当前内核栈的边界与剩余空间,可使用这两个函数实时控制栈状况。可在函数入口处包含下列代码。

// 如果当前内核栈空间小于150字节,就让函数返回

if(IoGetRemainingStackSize() < 150)

    return;                        // 如有可能,可指定一个特殊的错误值

 

节摘自http://blog.csdn.net/saict/article/category/498400

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 红米4a手机电池不耐用怎么办 红米6全网通联通网络不好怎么办 红米手机死机了怎么办不可拆卸电池 厦华电视指示灯亮但打不开机怎么办 oppo一体机的开机键坏了怎么办 小米手机长时间没用开不了机怎么办 红米2a充电坏了怎么办? 红米手机恢复出厂设置失败怎么办 红米关机强行恢复出厂失败怎么办 红米2a太卡了怎么办 红米2a上网好卡怎么办 红米1内部存储空间坏了怎么办 红米3s开关机键失灵怎么办 红米3s下面三个键失灵怎么办 红米3s手机掉水怎么办 红米手机用久了卡怎么办 红米4x手机不支持计步怎么办 红米4x手机耗电快怎么办 红米4a一体机手机死机怎么办 红米4x打王者卡怎么办 红米5 4g信号不稳定怎么办 红米3x玩游戏卡顿怎么办 红米3开不了机了怎么办 苹果手机装了sim卡没反应怎么办 小米手机打电话的图标没了怎么办 租房时和房东没签协议装修怎么办 三星安卓手机忘记锁屏密码怎么办 刷机了支付宝的余额宝钱没了怎么办 手机刷机支付宝里面的钱怎么办 支付宝宽带缴费交错账号了怎么办 电信宽带反回到翼支付里的钱怎么办 天猫盒子连接电视没反应怎么办 淘宝定制单发货之后是空物流怎么办 微信购买虚拟物品卖家不发货怎么办 虚拟商品确认收货后申请退款怎么办 手机换号码了淘宝怎么办又不能上网 美团酒店订单取消超时了怎么办 订单中快递单号填错了怎么办 高考动态口令卡页面找不到了怎么办 支付宝收钱码被别人扫了怎么办 上高速收费下高速免费卡怎么办