2011-12-18 4 views
3

Я портировал 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() два или более раз, я получит неизвестное прерывание по порядку. Странный.

+0

Можете ли вы использовать моральный эквивалент 'ldd/path/to/binary' для работы и неудачного исполняемого файла? – sarnold

+1

@sarnold Я запускал 'objdump' и' readelf' (моя среда не имеет 'ldd'); в любом исполняемом файле нет динамического раздела, перемещений или раскрутки разделов. –

ответ

0

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

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

Сейчас он работает отлично.

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

Смежные вопросы