我一直在将newlib移植到我的小内核中,我很难过:每当我包含一个引用系统调用的函数时,我的程序会在执行时出错页面。如果我调用一个不引用系统调用的函数,比如rand()
,那么什么都不会出错。
注意:通过包含,我的意思是只要功能,例如printf()
或fopen()
位于程序内部,即使它未通过main()
调用。
我已经有这个问题已经有一段时间了,并且不知道是什么导致这个:
GROUP
,gcc和ld 我不太确定我应该包含哪些其他信息,但我很乐意将我能做的事情包括在内。
编辑:要验证,发生的页面错误不在失败功能的地址;他们在该计划的其他地方。例如,当我调用位于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()
两次或更多次,我将得到一个未知的操作码中断。奇。
答案 0 :(得分:0)
糟糕!弄清楚:当我映射虚拟地址时,我应该每次都分配一个新页面,如下所示:
map(mapaddr, PMMAllocPage(), flags | PAGE_USER);
现在它运作正常。
对于那些好奇为什么它不起作用:当我不包括printf()
时,程序的大小在0x1000字节以下,所以只有一页的映射是可以的。当我加入printf()
或fopen()
时,程序的大小要大得多,这就是导致问题的原因。