newlib函数的页面错误

时间:2011-12-18 01:24:13

标签: porting page-fault newlib

我一直在将newlib移植到我的小内核中,我很难过:每当我包含一个引用系统调用的函数时,我的程序会在执行时出错页面。如果我调用一个不引用系统调用的函数,比如rand(),那么什么都不会出错。

注意:通过包含,我的意思是只要功能,例如printf()fopen()位于程序内部,即使它未通过main()调用。

我已经有这个问题已经有一段时间了,并且不知道是什么导致这个:

  • 我已多次重建newlib
  • 修改了我的ELF加载程序以加载 来自节标题而不是程序标题的代码
  • 尝试单独构建newlib / libgloss(失败)
  • 使用GROUP,gcc和ld
  • 通过ld脚本链接库(libc,libnosys)

我不太确定我应该包含哪些其他信息,但我很乐意将我能做的事情包括在内。

编辑:要验证,发生的页面错误不在失败功能的地址;他们在该计划的其他地方。例如,当我调用位于0x08048170的fopen()时,我将在0xA00A316C处寻呼错误。

编辑2: 加载ELF的相关代码:

int krun(u8int *name) {
    int fd = kopen(name); 
    Elf32_Ehdr *ehdr = kmalloc(sizeof(Elf32_Ehdr*));
    read(fd, ehdr, sizeof(Elf32_Ehdr));

    if (ehdr->e_ident[0] != 0x7F || ehdr->e_ident[1] != 'E' || ehdr->e_ident[2] != 'L' || ehdr->e_ident[3] != 'F') {
        kfree(ehdr);
        return -1; 
    }

    int pheaders    = ehdr->e_phnum;
    int phoff       = ehdr->e_phoff;
    int phsize      = ehdr->e_phentsize;

    int sheaders    = ehdr->e_shnum;
    int shoff       = ehdr->e_shoff;
    int shsize      = ehdr->e_shentsize; 

    for (int i = 0; i < pheaders; i++) {
        lseek(fd, phoff + phsize * i, SEEK_SET);

        Elf32_Phdr *phdr = kmalloc(sizeof(Elf32_Phdr*));
        read(fd, phdr, sizeof(Elf32_Phdr)); 

        u32int page = PMMAllocPage();

        int flags = 0; 
        if (phdr->p_flags & PF_R) flags |= PAGE_PRESENT;
        if (phdr->p_flags & PF_W) flags |= PAGE_WRITE; 

        int pages = (phdr->p_memsz / 0x1000) + 1;
        while (pages >= 0) {
            u32int mapaddr = (phdr->p_vaddr + (pages * 0x1000)) & 0xFFFFF000; 
            map(mapaddr, page, flags | PAGE_USER); 
            pages--; 
        }

        lseek(fd, phdr->p_offset, SEEK_SET);
        read(fd, (void *)phdr->p_vaddr, phdr->p_filesz);   

        kfree(phdr);
    }

    // Removed: code block that zeroes .bss: it's already zeroed whenever I check it anyways
    // Removed: code block that creates thread and adds it to scheduler 

    kfree(ehdr);                
    return 0; 
}

编辑3:我注意到如果我调用系统调用(例如write()),然后再调用printf()两次或更多次,我将得到一个未知的操作码中断。奇。

1 个答案:

答案 0 :(得分:0)

糟糕!弄清楚:当我映射虚拟地址时,我应该每次都分配一个新页面,如下所示:

map(mapaddr, PMMAllocPage(), flags | PAGE_USER); 

现在它运作正常。

对于那些好奇为什么它不起作用:当我不包括printf()时,程序的大小在0x1000字节以下,所以只有一页的映射是可以的。当我加入printf()fopen()时,程序的大小要大得多,这就是导致问题的原因。