免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3146 | 回复: 7
打印 上一主题 下一主题

[求助] 关于栈的扩展 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-12 23:27 |只看该作者 |倒序浏览
5可用积分
记得在linux内核的do_page_fault中, 如果产生缺页异常的地址不超过栈的增长方向若干(32)字节, 则内核让栈自动增长.

而应用程序编译后, 进入一个函数时总是直接就通过add esp把栈上的变量划好了(栈上的变量应该不限于32字节).

那么, 什么情况下会通过do_page_fault来扩展栈呢? 函数调用时, 如果esp超出了栈的范围, 栈会得到扩展吗?

望指点, 感激不尽~

最佳答案

查看完整内容

Linux kernel判断的是,如果你fault的address < esp - 32,认为是非法的。因为访问< esp的地址都是非法的,除了pusha, 它是先访问栈,然后在decrease esp,所以kernel加了32byte的余量。(看了一下最新的kernel, 又有了点变化,好像有了新的指令"enter",也和pusha一样,但是有可能会access栈下65536+32*4的地方)你说的情况是,栈上的局部变量,这些变量的地址不可能 < esp (先decrease esp, 然后再访问着些变量,产生page fault, k ...

论坛徽章:
0
2 [报告]
发表于 2009-08-12 23:27 |只看该作者

回复 #1 kouu 的帖子

Linux kernel判断的是,如果你fault的address < esp - 32,认为是非法的。因为访问< esp的地址都是非法的,除了pusha, 它是先访问栈,然后在decrease esp,所以kernel加了32byte的余量。

(看了一下最新的kernel, 又有了点变化,好像有了新的指令"enter",也和pusha一样,但是有可能会access栈下65536+32*4的地方)

你说的情况是,栈上的局部变量,这些变量的地址不可能 < esp (先decrease esp, 然后再访问着些变量,产生page fault, kernel expand stack)。expand stack的话,根据vma->start 和 fault的address决定expand几个page。
        
        vma = find_vma(mm, address);
        if (!vma)
                goto bad_area;
        if (vma->vm_start <= address)
                goto good_area;
        if (!(vma->vm_flags & VM_GROWSDOWN))
                goto bad_area;
        if (error_code & 4) {
                /*
                 * accessing the stack below %esp is always a bug.
                 * The "+ 32" is there due to some instructions (like
                 * pusha) doing post-decrement on the stack and that
                 * doesn't show up until later..
                 */
                if (address + 32 < regs->esp)
                        goto bad_area;
        }
        if (expand_stack(vma, address))
                goto bad_area;

[ 本帖最后由 eexplorer 于 2009-8-13 09:40 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2009-08-12 23:36 |只看该作者
你说的是用户态的栈吧? 内核态的好像是固定的。

论坛徽章:
0
4 [报告]
发表于 2009-08-13 09:21 |只看该作者
lz的问题我也没想通,关注。
个人感觉这样应该会造成段错误。
另外,貌似现在用户堆栈扩展的大小已经不限于32字节了
而是65536 + 32 * sizeof(unsigned long),
do_page_fault注释写的清楚,这是因为x86的enter指令的引入
这么大的限制应该不太容易越界了吧。。。

论坛徽章:
0
5 [报告]
发表于 2009-08-13 09:46 |只看该作者

回复 #4 eexplorer 的帖子

To ls
栈上局部变量地址确实不会<esp,但是在进入函数的时候esp是直接加上一个数来给局部变量留出空间的,假如局部变量很多的话,这时esp可能指向堆栈合法空间之下很远的位置,如果在这个函数中直接访问最低地址的变量不是就会超出linux给定的栈扩展限制么?

论坛徽章:
0
6 [报告]
发表于 2009-08-13 09:55 |只看该作者
原帖由 peimichael 于 2009-8-13 09:46 发表
To ls
栈上局部变量地址确实不会


在acct_stack_growth()会check你说的这种情况,

        if (size > rlim[RLIMIT_STACK].rlim_cur)
                return -ENOMEM;

论坛徽章:
0
7 [报告]
发表于 2009-08-13 10:36 |只看该作者
哦,明白了,非常感谢 eexplorer 兄~

之前最大的误解就是: 处理缺页异常时,不是以vma来判断栈的大小,而是以当时的esp。

那么,esp是可以由用户态程序自由控制增减的,do_page_fault应该不能判断esp的当前值是不是被用户程序恶意加减过。 这里应该就只有靠 rlim 来限制了。 是这样吧?

论坛徽章:
0
8 [报告]
发表于 2009-08-13 10:48 |只看该作者

回复 #7 kouu 的帖子

> 那么,esp是可以由用户态程序自由控制增减的,do_page_fault应该不能判断esp的当前值是不是
> 被用户程序恶意加减过。 这里应该就只有靠 rlim 来限制了。 是这样吧?

这个kernel应该判断不了,acct_stack_growth会判断
1. 有没有超过address space limit (RLIMIT_AS)
2. stack limit (RLIMIT_STACK)
3. 有没有enough free memory

如果out of memory的话,kernel应该会首先kill掉这个process
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP