Я портировал newlib на мое очень маленькое ядро, и я в тупик: всякий раз, когда я , включил функцию, которая ссылается на системный вызов, моя программа будет вызывать ошибку страницы при выполнении. Если я вызываю функцию, которая не ссылается на системный вызов, например rand()
, ничего не пойдет не так.Ошибка страницы с функциями newlib
Примечание: Включая, я имею в виду, пока функция, например. printf()
или fopen()
, находится где-то внутри программы, даже если он не вызван через main()
.
Я имел эту проблему в течение достаточно долгого времени, и понятия не имеют, что может быть причиной этого:
- Я перестроен newlib много раз
- Modified мой ELF загрузчик для загрузки код из раздела заголовков вместо заголовков программы
- Пытались построить newlib/libgloss отдельно (который не удалось)
- Linked библиотеки (Libc, libnosys) через скрипт Л.Д., используя
GROUP
, GCC и Л.Д.
Я не совсем уверен, какую другую информацию я должен включить с этим, но я был бы рад включить то, что могу.
Редактирование: для проверки произошедших сбоев страниц не указаны адреса отказоустойчивых функций; они находятся в другом месте программы. Например, когда я звоню fopen()
, находящемуся в 0x08048170, я ошибаюсь при ошибке 0xA00A316C.
Edit 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;
}
Edit 3: Я заметил, что если я называю системный вызов, такой как write()
, а затем вызвать printf()
два или более раз, я получит неизвестное прерывание по порядку. Странный.
Можете ли вы использовать моральный эквивалент 'ldd/path/to/binary' для работы и неудачного исполняемого файла? – sarnold
@sarnold Я запускал 'objdump' и' readelf' (моя среда не имеет 'ldd'); в любом исполняемом файле нет динамического раздела, перемещений или раскрутки разделов. –