我尝试编写一个非常简单的操作系统来更好地理解基本原理。我需要实现用户空间malloc。所以一开始我想在我的linux机器上实现并测试它。
首先,我通过以下方式实现了sbrk()函数
void* sbrk( int increment ) {
return ( void* )syscall(__NR_brk, increment );
}
但是这段代码不起作用。相反,当我使用os给出的sbrk时,这样可以正常工作。
我尝试使用sbrk()的另一个实现
static void *sbrk(signed increment)
{
size_t newbrk;
static size_t oldbrk = 0;
static size_t curbrk = 0;
if (oldbrk == 0)
curbrk = oldbrk = brk(0);
if (increment == 0)
return (void *) curbrk;
newbrk = curbrk + increment;
if (brk(newbrk) == curbrk)
return (void *) -1;
oldbrk = curbrk;
curbrk = newbrk;
return (void *) oldbrk;
}
从这个函数调用的sbrk
static Header *morecore(unsigned nu)
{
char *cp;
Header *up;
if (nu < NALLOC)
nu = NALLOC;
cp = sbrk(nu * sizeof(Header));
if (cp == (char *) -1)
return NULL;
up = (Header *) cp;
up->s.size = nu; // ***Segmentation fault
free((void *)(up + 1));
return freep;
}
此代码也不起作用,就行(***)我得到分段错误。 哪里有问题?
全部谢谢。我已经使用sbrk的新实现解决了我的问题。给定的代码工作正常。
void* __sbrk__(intptr_t increment)
{
void *new, *old = (void *)syscall(__NR_brk, 0);
new = (void *)syscall(__NR_brk, ((uintptr_t)old) + increment);
return (((uintptr_t)new) == (((uintptr_t)old) + increment)) ? old :
(void *)-1;
}
答案 0 :(得分:2)
第一个sbrk
应该有一个long increment
。而你忘了处理错误(并设置errno
)
第二个sbrk
函数不会更改address space(如sbrk
那样)。您可以使用mmap
进行更改(但使用mmap
代替sbrk
将不会像sbrk
那样更新内核的数据段结束视图。您可以使用cat /proc/1234/maps
来查询pid 1234进程的地址空间。或甚至从您的计划内阅读(例如fopen
&amp; fgets
)/proc/self/maps
。
BTW,sbrk
已过时(大多数malloc实现使用mmap
),根据定义,每个system call(在syscalls(2)中列出)由内核执行(for { {1}} 内核维护“数据段”限制!)。所以你无法避免内核,我甚至不明白为什么要模拟任何系统调用。几乎按照定义,您无法模拟系统调用,因为它们是从用户应用程序与内核交互的唯一方式。在用户应用程序中,每个系统调用都是一个原子初级操作(由单个sbrk
机器指令完成,并在机器寄存器中包含适当的内容。)
您可以使用strace(1)来了解正在运行的程序所执行的实际系统调用。
顺便说一句,GNU libc
是free software。你可以查看它的源代码。 musl-libc更简单libc,其代码更易读。
最后使用SYSENTER
进行编译并使用gcc -Wall -Wextra -g
调试器(如果需要,甚至可以查询寄存器)。也许请阅读x86/64-ABI specification和Linux Assembly HowTo。