- 论坛徽章:
- 0
|
在C开发中,内存问题是很难定位的,尤其那种跨模块的小李飞刀,多个模块用一个分配器来分配内存,一个模块分配使用后释放了,或者本模块还保留个悬挂指针,或者传给了别的模块,其它模块再分配了这块内存后,造成多个模块使用同一块内存,这种问题一般不多,但一旦出现极难搞。在应用开发中,不同进程间可以提供保护,windows还可以创建不同的heap,在一定程度上减少这种情况的出现,而在传统的嵌入式中,各进程间内存是共享的,互相可以访问,内存分配器一般也是一个,当应用复杂到一定程度了,维护就越来越困难了。
现在很多嵌入式使用LINUX,我们公司就有产品用了,Kernel hacking中有很多调试选项,内存方面大体上有这几个:CONFIG_SLUB_DEBUG_ON,CONFIG_DEBUG_HIGHMEM,CONFIG_DEBUG_VM,CONFIG_DEBUG_PAGEALLOC,但好像对“飞刀”都不太有效,本来LINUX的策略是内核相信自己,而且内核黑客的水平都很高,不太容易出太多问题。但现在国内开发水平实在不敢恭维,看过我们LINUX产品组写的经验案例,居然案例写的都是错的,比如说在一个核上不能死锁,他不知道异常和中断之间不能用锁来保护,wait_queue用法不对,造成死等,这个还是个老员工写的,真是晕死了,应届生混几个月就敢写内核代码,全组几十人好像还没有谁看完《深入理解》的,不说这些没用的了,还是回到技术上吧。
对付飞刀大概有两类方法,一个大类是在线检测,又再分为purify这种分析可执行文件插入目标代码的,bounds checker(GCC bounds checking)编译时插入tree中间代码编译进去的,Valgrind使用虚拟机边分析边动态编译执行的,我所知的就这3种。另一种是利用硬件页表、TLB(MIPS没有硬件页表等)机制的,用户态进程就是通过这个来实现保护的。这个实质上是执行不同模块的代码,使用不同的页表,内核代码也可以按模块等来组织,执行某一模块代码时,它所分配的内存页表置_PAGE_PRESENT位,执行完后清掉,这个想法很简单,在非SMP上也是可行的,但在SMP上就不行了,一个核上运行某模块代码时,其它核上其它模块的代码也可以意外访问不属于它的内存,一种办法上不同的核使用不同的内核页表,这个需要从初始化改起,工作量大问题也可能多,另一种办法是我想采用的,让页表总是清_PAGE_PRESENT位,在page fault异常中检测该页内存是否属于该段代码,如属于则置_PAGE_PRESENT位后更新TLB并装入TLB(访问一下地址就行),然后马上再清掉,但不更新TLB了,靠原来的TLB来访问内存,因为TLB是属于单个核的,这样各CPU共享一个页表也没问题了,相对来说MIPS这种使用软页表的,应该更容易改,先从X86做起吧。下面是一点验证代码,注意清页表后不刷新TLB时访问内存不异常,刷新后再访问就异常了。我想做一个内存保护的kernel hacking选项,需要考虑的东西也很多,比如alloc_pages、kmalloc、vmalloc这些都需要修改,还有不同的CPU模式,有兴趣的大家一起讨论。
[ 本帖最后由 bjhpf 于 2008-10-17 21:56 编辑 ] |
|