我一直在将 newlib 移植到我非常小的内核中,但我很困惑:每当我包含一个引用系统调用的函数时,我的程序都会在执行时出现页面错误。如果我调用一个不引用系统调用的函数,比如rand()
,什么都不会出错。
注意:包含,我的意思是只要函数,例如printf()
or fopen()
,在程序内部的某个地方,即使它不是通过 调用的main()
。
这个问题我已经有一段时间了,不知道是什么原因造成的:
- 我已经多次重建 newlib
- 修改了我的 ELF 加载器以从节头而不是程序头加载代码
- 尝试单独构建 newlib/libgloss(失败)
GROUP
使用、gcc 和 ld通过 ld 脚本链接库(libc、libnosys)
我不太确定我应该包含哪些其他信息,但我很乐意包含我可以包含的信息。
编辑:为了验证,发生的页面错误不在失败函数的地址;他们在程序的其他地方。例如,当我调用fopen()
位于 0x08048170 的 时,我将在 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()
两次或更多次,我会得到一个未知的操作码中断。奇怪的。