From 311d6917c4589f113e24e983361a83a153cfb9d9 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sat, 22 Nov 2008 13:23:39 +0200 Subject: [PATCH] Fixed a few errors with pager-mapping of elf file pages. Added expansion of elf segments during segment marking. --- tasks/mm0/include/memory.h | 2 +- tasks/mm0/src/lib/elf/elf.c | 142 ++++++++++++++++++++++-------------- tasks/mm0/src/memory.c | 10 ++- 3 files changed, 95 insertions(+), 59 deletions(-) diff --git a/tasks/mm0/include/memory.h b/tasks/mm0/include/memory.h index a04ff60..4607ccb 100644 --- a/tasks/mm0/include/memory.h +++ b/tasks/mm0/include/memory.h @@ -29,5 +29,5 @@ void pager_unmap_pages(void *addr, unsigned long npages); void *pager_map_page(struct vm_file *f, unsigned long page_offset); void pager_unmap_page(void *addr); void *pager_map_file_range(struct vm_file *f, unsigned long byte_offset, - ` unsigned long size); + unsigned long size); #endif /* __MEMORY_H__ */ diff --git a/tasks/mm0/src/lib/elf/elf.c b/tasks/mm0/src/lib/elf/elf.c index 140b215..1788926 100644 --- a/tasks/mm0/src/lib/elf/elf.c +++ b/tasks/mm0/src/lib/elf/elf.c @@ -25,6 +25,68 @@ int elf_probe(struct elf_header *header) return -1; } +/* + * Sets or expands a segment region if it has the given type and flags + * For expansion we assume any new section must come consecutively + * after the existing segment, otherwise we ignore it for simplicity. + */ +int elf_test_expand_segment(struct elf_section_header *section, + unsigned int sec_type, unsigned int sec_flags, + unsigned int sec_flmask, unsigned long *start, + unsigned long *end, unsigned long *offset) +{ + if (section->sh_type == sec_type && + (section->sh_flags & sec_flmask) == sec_flags) { + /* Set new section */ + if (!*start) { + *offset = section->sh_offset; + *start = section->sh_addr; + *end = section->sh_addr + section->sh_size; + /* Expand existing section from the end */ + } else if (*end == section->sh_addr) + *end = section->sh_addr + section->sh_size; + } + + return 0; +} +/* + * Sift through sections and copy their marks to tcb and efd + * if they are recognised and loadable sections. + * + * NOTE: There may be multiple sections of same kind, in + * consecutive address regions. Then we need to increase + * that region's marks. + */ +int elf_mark_segments(struct elf_section_header *sect_header, int nsections, + struct tcb *task, struct exec_file_desc *efd) +{ + for (int i = 0; i < nsections; i++) { + struct elf_section_header *section = §_header[i]; + + /* Text + read-only data segments */ + elf_test_expand_segment(section, SHT_PROGBITS, SHF_ALLOC, + SHF_ALLOC | SHF_WRITE, &task->text_start, + &task->text_end, &efd->text_offset); + + /* Data segment */ + elf_test_expand_segment(section, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, + SHF_ALLOC | SHF_WRITE, &task->data_start, + &task->data_end, &efd->data_offset); + + /* Bss segment */ + elf_test_expand_segment(section, SHT_NOBITS, SHF_ALLOC | SHF_WRITE, + SHF_ALLOC | SHF_WRITE, &task->bss_start, + &task->bss_end, &efd->bss_offset); + } + + if (!task->text_start || !task->data_start || !task->bss_start) { + printf("%s: NOTE: Could not find one of text, data or " + "bss segments in elf file.\n", __FUNCTION__); + } + + return 0; +} + /* * Loading an ELF file: * @@ -38,23 +100,34 @@ int elf_probe(struct elf_header *header) int elf_parse_executable(struct tcb *task, struct vm_file *file, struct exec_file_desc *efd) { - int err; - struct elf_header *elf_header = pager_map_page(file, 0); + struct elf_header elf_header, *elf_headerp = pager_map_page(file, 0); struct elf_program_header *prg_header_start, *prg_header_load; struct elf_section_header *sect_header; - unsigned long sect_start, sect_end; - unsigned long prg_start, prg_end; + unsigned long sect_offset, sect_size; + unsigned long prg_offset, prg_size; + int err; /* Test that it is a valid elf file */ - if ((err = elf_probe(elf_header)) < 0) + if ((err = elf_probe(elf_headerp)) < 0) return err; + /* Copy the elf header and unmap first page */ + memcpy(&elf_header, elf_headerp, sizeof(elf_header)); + pager_unmap_page(elf_headerp); + + /* Find the markers for section and program header tables */ + sect_offset = elf_header.e_shoff; + sect_size = elf_header.e_shentsize * elf_header.e_shnum; + + prg_offset = elf_header.e_phoff; + prg_size = elf_header.e_phentsize * elf_header.e_phnum; + /* Get the program header table */ prg_header_start = (struct elf_program_header *) - ((void *)elf_header + elf_header->e_phoff); + pager_map_file_range(file, prg_offset, prg_size); - /* Get the first loadable segment */ - for (int i = 0; i < elf_header->e_phnum; i++) { + /* Get the first loadable segment. We currently just stare at it */ + for (int i = 0; i < elf_header.e_phnum; i++) { if (prg_header_start[i].p_type == PT_LOAD) { prg_header_load = &prg_header_start[i]; break; @@ -62,55 +135,16 @@ int elf_parse_executable(struct tcb *task, struct vm_file *file, } /* Get the section header table */ - if (__pfn(elf_header->e_shoff) > 0) { + sect_header = (struct elf_section_header *) + pager_map_file_range(file, sect_offset, sect_size); - } - sect_header = pager_map_file_offset(file, elf_header->e_shoff); - else - sect_header = (struct elf_section_header *) - ((void *)elf_header + elf_header->e_shoff); + elf_mark_segments(sect_header, elf_header.e_shnum, task, efd); - /* Determine if we cross a page boundary during traversal */ - if (elf_header->e_shentsize * elf_header->e_shnum > TILL_PAGE_ENDS(sect_header)) + /* Unmap program header table */ + pager_unmap_pages(prg_header_start, __pfn(page_align_up(prg_size))); - /* - * Sift through sections and copy their marks to tcb and efd - * if they are recognised and loadable sections. - * - * NOTE: There may be multiple sections of same kind, in - * consecutive address regions. Then we need to increase - * that region's marks. - */ - for (int i = 0; i < elf_header->e_shnum; i++) { - struct elf_section_header *section = §_header[i]; - - /* Text section */ - if (section->sh_type == SHT_PROGBITS && - section->sh_flags & SHF_ALLOC && - section->sh_flags & SHF_EXECINSTR) { - efd->text_offset = section->sh_offset; - task->text_start = section->sh_addr; - task->text_end = section->sh_addr + section->sh_size; - } - - /* Data section */ - if (section->sh_type == SHT_PROGBITS && - section->sh_flags & SHF_ALLOC && - section->sh_flags & SHF_WRITE) { - efd->data_offset = section->sh_offset; - task->data_start = section->sh_addr; - task->data_end = section->sh_addr + section->sh_size; - } - - /* BSS section */ - if (section->sh_type == SHT_NOBITS && - section->sh_flags & SHF_ALLOC && - section->sh_flags & SHF_WRITE) { - efd->bss_offset = section->sh_offset; - task->bss_start = section->sh_addr; - task->bss_end = section->sh_addr + section->sh_size; - } - } + /* Unmap section header table */ + pager_unmap_pages(sect_header, __pfn(page_align_up(sect_size))); return 0; } diff --git a/tasks/mm0/src/memory.c b/tasks/mm0/src/memory.c index bfa1049..8584e74 100644 --- a/tasks/mm0/src/memory.c +++ b/tasks/mm0/src/memory.c @@ -157,7 +157,7 @@ void *pager_map_pages(struct vm_file *f, unsigned long page_offset, unsigned lon /* Map pages contiguously one by one */ for (unsigned long pfn = page_offset; pfn < page_offset + npages; pfn++) { - BUG_ON(!(p = find_page(&f->vm_obj, page_offset))) + BUG_ON(!(p = find_page(&f->vm_obj, pfn))) l4_map((void *)page_to_phys(p), addr, 1, MAP_USR_RW_FLAGS, self_tid()); addr += PAGE_SIZE; } @@ -184,10 +184,12 @@ void pager_unmap_pages(void *addr, unsigned long npages) * returns pointer to byte offset in the file. */ void *pager_map_file_range(struct vm_file *f, unsigned long byte_offset, - ` unsigned long size) + unsigned long size) { - void *page = pager_map_pages(f, __pfn(byte_offset), __pfn(size)); + unsigned long mapsize = (byte_offset & PAGE_MASK) + size; - return (void *)((unsigned long)page | (PAGE_MASK & f_offset)); + void *page = pager_map_pages(f, __pfn(byte_offset), __pfn(page_align_up(mapsize))); + + return (void *)((unsigned long)page | (PAGE_MASK & byte_offset)); }