2006年12月15日星期五

malloc的起始地址在LINUX和FREEBSD中的不同

Coolq搞懂了昨天讨论的FREEBSD bss结束地址问题,我来总结一下。
LINUX和FREEBSD在BSS结束地址(也可以说是malloc分配的起始地址)处理方面的不同:

LINUX:
malloc分配的起始地址是通过sys_brk(0)从内核获取,见代码

asmlinkage unsigned long sys_brk(unsigned long brk)

207 {

208 unsigned long rlim, retval;

209 unsigned long newbrk, oldbrk;

210 struct mm_struct *mm = current->mm;

211

212 down_write(&mm->mmap_sem);

213

214 if (brk <>end_code) <------------- 这里

215 goto out; <------------- 这里

216 newbrk = PAGE_ALIGN(brk);

217 oldbrk = PAGE_ALIGN(mm->brk);

218 if (oldbrk == newbrk)

219 goto set_brk;

220

221 /* Always allow shrinking brk. */

222 if (brk <= mm->brk) {

223 if (!do_munmap(mm, newbrk, oldbrk-newbrk))

224 goto set_brk;

225 goto out;

226 }

227

228 /* Check against rlimit.. */

229 rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;

230 if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)

231 goto out;

232

233 /* Check against existing mmap mappings. */

234 if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))

235 goto out;

236

237 /* Ok, looks good - let it rip. */

238 if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)

239 goto out;

240 set_brk:

241 mm->brk = brk;

242 out: <------------- 这里

243 retval = mm->brk; <------------- 这里

244 up_write(&mm->mmap_sem);

245 return retval;

246 }


FREEBSD:
malloc分配的起始地址是硬编码在binary中,见代码:

#if defined(SYSLIBC_SCCS) && !defined(lint)
.asciz "@(#)brk.s 5.2 (Berkeley) 12/17/90"
#endif /* SYSLIBC_SCCS and not lint */
#include
__FBSDID("$FreeBSD: src/lib/libc/i386/sys/brk.S,v 1.10 2002/03/23 02:10:28 obrien Exp $");

#include "SYS.h"

.globl HIDENAME(curbrk)
.globl HIDENAME(minbrk)
ENTRY(_brk)
jmp ok

ENTRY(brk)
#ifdef PIC
movl 4(%esp),%eax
PIC_PROLOGUE
movl PIC_GOT(HIDENAME(curbrk)),%edx # set up GOT addressing <------------- 这里
movl PIC_GOT(HIDENAME(minbrk)),%ecx # PIC_EPILOGUE <------------- 这里
cmpl %eax,(%ecx)
jbe ok
movl (%ecx),%eax
movl %eax,4(%esp)
ok:
mov $SYS_break,%eax <------------- 这里
KERNCALL
jb err
movl 4(%esp),%eax
movl %eax,(%edx)
movl $0,%eax
ret
err:
PIC_PROLOGUE
jmp PIC_PLT(HIDENAME(cerror))

#else

movl 4(%esp),%eax
cmpl %eax,HIDENAME(minbrk)
jbe ok
movl HIDENAME(minbrk),%eax
movl %eax,4(%esp)
ok:
mov $SYS_break,%eax
KERNCALL
jb err
movl 4(%esp),%eax
movl %eax,HIDENAME(curbrk)
movl $0,%eax
ret
err:
jmp HIDENAME(cerror)
#endif

因此,要对堆内存分配的起始地址进行随机,在LINUX只需在内核修改brk的初始值,而在FREEBSD中则必需在用户层做处理(可以改libc或ld)。

没有评论: