Ошибка страницы с функциями newlib - PullRequest
3 голосов
/ 18 декабря 2011

Я портировал newlib на свое очень маленькое ядро, и я в замешательстве: всякий раз, когда я включаю функцию, которая ссылается на системный вызов, моя программа выдает страницу ошибки при выполнении.Если я вызываю функцию, которая не ссылается на системный вызов, например rand(), ничего не пойдет не так.

Примечание. Под включением я подразумеваю, пока функция, например, printf() или fopen(), находится где-то внутри программы, даже если она не вызывается через main().

У меня уже давно есть эта проблема, и я понятия не имею, что может быть причиной этого:

  • Я много раз перестраивал newlib
  • Модифицированный загрузчик ELF для загрузки кода из заголовков разделов вместо заголовков программ
  • Попытка построить newlib / libgloss отдельно (что не удалось)
  • Связаны библиотеки (libc, libnosys) через ldсценарий, использующий GROUP, gcc и ld

Я не совсем уверен, какую другую информацию я должен включить с этим, но я был бы рад включить то, что я могу.

Редактировать: Чтобы проверить, происходят ли сбои страниц не по адресам неисправных функций;они в другом месте в программе.Например, когда я звоню по номеру 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: I 'мы заметили, что если я вызову системный вызов, такой как write(), а затем вызову printf() два или более раз, я получу неизвестное прерывание кода операции.Странный.

1 Ответ

0 голосов
/ 21 декабря 2011

Упс! Понял: когда я сопоставляю виртуальный адрес, я должен каждый раз выделять новую страницу, например:

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

Теперь все работает нормально.

Для тех, кому интересно, почему это не сработало: когда я не включал printf(), размер программы был меньше 0x1000 байт, поэтому сопоставление только с одной страницей было нормальным. Когда я включаю printf() или fopen(), размер программы был намного больше, поэтому это и стало причиной проблемы.

...