简体   繁体   English

为什么我的sbrk系统调用无法实现?

[英]Why my implementation of sbrk system call does not work?

I try to write a very simple os to better understand the basic principles. 我尝试编写一个非常简单的操作系统,以更好地理解基本原理。 And I need to implement user-space malloc. 而且我需要实现用户空间malloc。 So at first I want to implement and test it on my linux-machine. 因此,起初我想在我的linux机器上实现并测试它。

At first I have implemented the sbrk() function by the following way 首先,我通过以下方式实现了sbrk()函数

void* sbrk( int increment ) {
    return ( void* )syscall(__NR_brk, increment );
}

But this code does not work. 但是此代码不起作用。 Instead, when I use sbrk given by os, this works fine. 相反,当我使用os给定的sbrk时,这可以正常工作。

I have tryed to use another implementation of the 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 invoked from this function 从此函数调用的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;  
}  

This code also does not work, on the line (***) I get segmentation fault. 此代码也不起作用,在行(***)上出现分段错误。 Where is a problem ? 哪里有问题?

Thanks All. 谢谢大家 I have solved my problem using new implementation of the sbrk. 我已经使用sbrk的新实现解决了我的问题。 The given code works fine. 给定的代码工作正常。

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;
 }

The first sbrk should probably have a long increment . 第一个sbrk可能应具有long increment And you forgot to handle errors (and set errno ) 而且您忘记了处理错误(并设置了errno

The second sbrk function does not change the address space (as sbrk does). 第二个sbrk函数不会更改地址空间 (就像sbrk一样)。 You could use mmap to change it (but using mmap instead of sbrk won't update the kernel's view of data segment end as sbrk does). 你可以使用mmap改变它(但使用mmap而不是sbrk将不会更新数据片段结尾为内核的观点sbrk一样)。 You could use cat /proc/1234/maps to query the address space of process of pid 1234). 您可以使用cat /proc/1234/maps查询pid 1234进程的地址空间。 or even read (eg with fopen & fgets ) the /proc/self/maps from inside your program. 甚至从程序内部读取(例如,使用fopenfgets/proc/self/maps

BTW, sbrk is obsolete (most malloc implementations use mmap ), and by definition every system call (listed in syscalls(2) ) is executed by the kernel (for sbrk the kernel maintains the "data segment" limit!). 顺便说一句, sbrk已过时(大多数malloc实现使用mmap ),并且根据定义,每个系统调用 (在syscalls(2)中列出)均由内核执行(对于sbrk内核保持“数据段”限制!)。 So you cannot avoid the kernel, and I don't even understand why you want to emulate any system call. 因此,您无法避免使用内核,我什至不理解为什么要模拟任何系统调用。 Almost by definition, you cannot emulate syscalls since they are the only way to interact with the kernel from a user application. 几乎根据定义, 您无法模拟系统调用,因为它们是从用户应用程序与内核进行交互的唯一方法。 From the user application, every syscall is an atomic elementary operation (done by a single SYSENTER machine instruction with appropriate contents in machine registers). 在用户应用程序中,每个系统调用都是原子性的基本操作(由一条SYSENTER机器指令完成,并在机器寄存器中包含适当的内容)。

You could use strace(1) to understand the actual syscalls done by your running program. 您可以使用strace(1)来了解正在运行的程序执行的实际syscall。

BTW, the GNU libc is a free software . 顺便说一句, GNU libc是一个免费软件 You could look into its source code. 您可以查看其源代码。 musl-libc is a simpler libc and its code is more readable. musl-libc是更简单的libc ,其代码更易读。

At last compile with gcc -Wall -Wextra -g and use the gdb debugger (you can even query the registers, if you wanted to). 最后,使用gcc -Wall -Wextra -g编译并使用gdb调试器(如果需要,您甚至可以查询寄存器)。 Perhaps read the x86/64-ABI specification and the Linux Assembly HowTo . 也许阅读x86 / 64-ABI规范Linux Assembly HowTo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM