为什么我实现的sbrk系统调用不起作用



我试着写一个非常简单的操作系统来更好地理解基本原理。我需要实现用户空间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;
 }

第一个sbrk可能应该有一个long increment。您忘记处理错误(并设置errno

第二个sbrk函数不改变地址空间(与sbrk一样)。您可以使用mmap来更改它(但使用mmap而不是sbrk不会像sbrk那样更新内核的数据段结束视图)。您可以使用cat /proc/1234/maps查询pid 1234的进程的地址空间)。或者甚至从程序内部读取(例如用fopen&fgets/proc/self/maps

顺便说一句,sbrk是过时的(大多数malloc实现使用mmap),根据定义,每个系统调用(在syscalls(2)中列出)都由内核执行(对于sbrk内核保持"数据段"限制!)。所以你不能回避内核,我甚至不明白你为什么要模拟任何系统调用。几乎根据定义,您不能模拟系统调用,因为它们是从用户应用程序与内核交互的唯一方式。从用户应用程序来看,每个系统调用都是一个原子基本操作(由机器寄存器中具有适当内容的单个SYSENTER机器指令完成)。

您可以使用strace(1)来理解运行中的程序所执行的实际系统调用。

顺便说一句,GNU libc是一个自由软件。你可以查看它的源代码。musl-libc是一个更简单的libc,它的代码可读性更强。

最后使用gcc -Wall -Wextra -g进行编译,并使用gdb调试器(如果需要,您甚至可以查询寄存器)。也许可以阅读x86/64-ABI规范和Linux程序集HowTo。

相关内容

  • 没有找到相关文章

最新更新