Esempio n. 1
0
static int elf_mod_parse(uintptr_t elf, const char *name, int export_symbol, 
        uintptr_t * common_data, uint32_t * common_size,
        uintptr_t * mod_load_ptr, uintptr_t * mod_unload_ptr) {
    uint32_t i, x;
    uintptr_t reloc_addr;
    void * mem_addr;

    struct elfhdr *eh;
    struct secthdr *sh;
    struct reloc_a_s *reloc;
    struct symtab_s *symtab;

    uintptr_t cur_common_alloc = 0;
    uintptr_t cur_common_align = 1;

    eh = (struct elfhdr *)elf;

    kprintf("[ II ] shnum = %d, shsize = %d\n", eh->e_shnum, eh->e_shentsize);

    for (i = 0; i < eh->e_shnum; i++) {
        sh = (struct secthdr*)(elf + eh->e_shoff + (i * eh->e_shentsize));
        kprintf("[ II ] sh type = %d\n", sh->sh_type);
        if (sh->sh_type == SH_TYPE_SYMTAB) {
            for (x = 0; x < sh->sh_size; x += sh->sh_entsize) {
                symtab = (struct symtab_s *)(elf + sh->sh_offset + x);
                kprintf("[ II ] found sym: [%s] info[%02x] size[%d] addr[%08x]\n",
                        get_symbol_string(elf, symtab->sym_name),
                        symtab->sym_info,
                        symtab->sym_size,
                        symtab->sym_address);
                if (symtab->sym_shndx != SHN_UNDEF && symtab->sym_shndx < 0xff00) {
                    kprintf("[ II ]     value offset [%08x]\n", get_section_offset(elf, symtab->sym_shndx) + symtab->sym_address);
                    const char * sym_name = get_symbol_string(elf, symtab->sym_name);
                    switch (GET_SYMTAB_BIND(symtab->sym_info)) {
                        case STB_GLOBAL:
                            kprintf("[ II ]     global symbol\n");
                        case STB_LOCAL:
                            if (strcmp(sym_name, MOD_INIT_MODULE) == 0) {
                                *mod_load_ptr = get_section_offset(elf, symtab->sym_shndx) + symtab->sym_address + elf;
                            } else if (strcmp(sym_name, MOD_CLEANUP_MODULE) == 0) {
                                *mod_unload_ptr = get_section_offset(elf, symtab->sym_shndx) + symtab->sym_address + elf;
                            }

                            // global
                            if (GET_SYMTAB_BIND(symtab->sym_info) == 1 && export_symbol) {
                                mod_touch_symbol(sym_name, (void *)(get_section_offset(elf, symtab->sym_shndx) + symtab->sym_address + elf), 0);
                            }
                            break;

                        case STB_WEAK:
                            kprintf("[ II ]     weak symbol\n");
                            if (export_symbol) {
                                elf_mod_create_symbol(sym_name, (void *)(symtab->sym_address + elf), 0);
                            }
                            break;
                    }
                } else if (symtab->sym_shndx == SHN_COMMON) {
                    // TODO: implement SHN_COMMON
                    kprintf("[ EE ] not implemented\n");
                } else {
                    kprintf("[ II ] shndx[%04x]\n", symtab->sym_shndx);
                }
            }
        } else if (sh->sh_type == SH_TYPE_NOBITS) {
            kprintf("[ II ] bss section, alloc %d byte align 0x%x\n", sh->sh_size, sh->sh_addralign);
            if (bsf(sh->sh_addralign != bsr(sh->sh_addralign))) {
                error(" bad align\n");
                return -1;
            }
            if (sh->sh_addralign > cur_common_align) {
                cur_common_align = sh->sh_addralign;
            }
            cur_common_alloc = ((cur_common_alloc - 1) | (sh->sh_addralign - 1)) + 1;
            sh->sh_addr = cur_common_alloc;
            cur_common_alloc += sh->sh_size;
        }
    }

    uintptr_t common_space;
    if (cur_common_align > PGSIZE) {
        error("align failed\n");
        return -1;
    } else if (cur_common_alloc > 0) {
        // TODO: kmalloc would return non-kernel-area memory pointer, which would cause PG FAULT
        common_space = (uintptr_t)kmalloc(cur_common_alloc);
        memset((void*)common_space, 0, cur_common_alloc);

        *common_data = common_space;
        *common_size = cur_common_alloc;
    } else {
        *common_data = 0;
        *common_size = 0;
    }

    // fill the relocation entries
    for (i = 0; i < eh->e_shnum; i++) {
        sh = (struct secthdr *)(elf + eh->e_shoff + (i * eh->e_shentsize));

        if (sh->sh_type == SH_TYPE_RELA) {
            for (x = 0; x < sh->sh_size; x += sh->sh_entsize) {
                reloc = (struct reloc_a_s *)(elf + sh->sh_offset + x);
                symtab = fill_symbol_struct(elf, GET_RELOC_SYM(reloc->rl_info));

                kprintf("[ II ] reloc[%02x] offset[%08x] for [%s], sym offset[%08x]\n",
                        GET_RELOC_TYPE(reloc->rl_info),
                        reloc->rl_offset,
                        get_symbol_string(elf, symtab->sym_name),
                        symtab->sym_address);

                mem_addr = (void *)(elf + reloc->rl_offset + get_section_offset(elf, sh->sh_info));

                /* external reference (kernel symbol most likely) */
                if (symtab->sym_shndx == SHN_UNDEF) {
                    const char *sym_name = get_symbol_string(elf, symtab->sym_name);
                    int idx = find_export_sym(sym_name, 0);
                    if (idx == -1) {
                        if (strcmp(sym_name, name) == 0) {
                            reloc_addr = elf;
                        } else {
                            error("unresolved symbol \"%s\", set with 0\n", sym_name);
                            reloc_addr = 0;
                        }
                    } else {
                        kprintf("external symbol %s addr = %p\n", sym_name, ex_sym_ptr[idx]);
                        reloc_addr = ex_sym_ptr[idx];
                    }
                } else if (symtab->sym_shndx < 0xff00) {
                    kprintf("section offset %16x, addr %16x\n", get_section_offset(elf, symtab->sym_shndx), symtab->sym_address);
                    if (((struct secthdr *)(elf + eh->e_shoff + (symtab->sym_shndx * eh->e_shentsize)))->sh_type == SH_TYPE_NOBITS) {
                        reloc_addr = common_space;
                    } else {
                        reloc_addr = elf;
                    }
                    reloc_addr += get_section_offset(elf, symtab->sym_shndx);
                    reloc_addr += symtab->sym_address;
                } else if (symtab->sym_shndx == SHN_COMMON) {
                    reloc_addr = common_space + symtab->sym_address;
                } else {
                    error("unhandled syn_shndx\n");
                }
                
                switch (GET_RELOC_TYPE(reloc->rl_info)) {
                    case 0x02:      // S + A - P
                        reloc_addr = reloc_addr - (uintptr_t)mem_addr;
                        //*(uintptr_t *)mem_addr = reloc_addr + *(uintptr_t *)mem_addr;
                        *(uint32_t *)mem_addr = reloc_addr + reloc->rl_addend;
                        kprintf("fill rel address %08x to %08x\n", *(uint32_t *)mem_addr, mem_addr);
                        break;

                    case 0x0b:      // S + A
                        *(uint32_t *)mem_addr = reloc_addr + reloc->rl_addend;
                        kprintf("fill rel address %08x to %08x\n", *(uint32_t *)mem_addr, mem_addr);
                        break;

                    default:
                        error("unsupported relocation type (%x)\n", GET_RELOC_TYPE(reloc->rl_info));
                        break;

                }
            }
        } else if (sh->sh_type == SH_TYPE_REL) {
            kprintf("[ EE ] relocation SH_TYPE_REL not implemented\n");
        }
    }

    return 0;
}
Esempio n. 2
0
int arch_specific_parse_elf_module(uint8_t * buf, addr_t *entry, addr_t *exiter, addr_t *deps)
{
	uint32_t i, x;
	uint32_t module_entry=0, reloc_addr, mem_addr, module_exiter=0, module_deps=0;
	elf32_header_t * eh;
	elf32_section_header_t * sh;
	elf32_reloc_entry_t * reloc;
	elf32_symtab_entry_t * symtab;
	int error=0;
	eh = (elf32_header_t *)buf;
	
	/* grab the functions we'll need */
	for(i = 0; i < eh->shnum; i++)
	{  
		sh = (elf32_section_header_t*)(buf + eh->shoff + (i * eh->shsize));
		if(sh->type == 2)
		{
			for(x = 0; x < sh->size; x += sh->sect_size)
			{
				symtab = (elf32_symtab_entry_t*)(buf + sh->offset + x);
				if(!memcmp((uint8_t*)get_symbol_string(buf, symtab->name), 
						(uint8_t*)"module_install", 14))
					module_entry = get_section_offset(buf, symtab->shndx) + 
						symtab->address + (uint32_t)buf;
				if(!memcmp((uint8_t*)get_symbol_string(buf, symtab->name), 
						(uint8_t*)"module_exit", 11))
					module_exiter = get_section_offset(buf, symtab->shndx) + 
						symtab->address + (uint32_t)buf;
				if(!memcmp((uint8_t*)get_symbol_string(buf, symtab->name), 
						(uint8_t*)"module_deps", 11))
					module_deps = get_section_offset(buf, symtab->shndx) + 
						symtab->address + (uint32_t)buf;
			}
		}
	}
	
	if(!module_entry)
	{
		printk(KERN_INFO, "[mod]: module_install() entry point was not found\n");
		return 1;
	}
	
	*entry = module_entry;
	*exiter = module_exiter;
	*deps = module_deps;
	
	/* fix up the relocation entries */
	for(i = 0; i < eh->shnum; i++)
	{  
		sh = (elf32_section_header_t*)(buf + eh->shoff + (i * eh->shsize));
		if(sh->type == 9)
		{
			for(x = 0; x < sh->size; x += sh->sect_size)
			{
				reloc = (elf32_reloc_entry_t*)(buf + sh->offset + x);
				symtab = fill_symbol_struct(buf, GET_RELOC_SYM(reloc->info));
				
				/* absolute physical address */
				if(GET_RELOC_TYPE(reloc->info) == 0x01)
				{
					mem_addr = (uint32_t)buf + reloc->offset;
					mem_addr += get_section_offset(buf, sh->info);
					/* external reference (kernel symbol most likely) */
					if(symtab->shndx == 0)
					{
						reloc_addr = find_kernel_function(get_symbol_string(buf, symtab->name));
						if(!reloc_addr)
						{
							printk(KERN_INFO, "[mod]: *ABS* unresolved dependency \"%s\"\n", 
									get_symbol_string(buf, symtab->name));
							error++;
						}
					}
					else
					{
						reloc_addr = (uint32_t)buf + symtab->address + *(intptr_t*)mem_addr;
						reloc_addr += get_section_offset(buf, symtab->shndx);
					}
					*(intptr_t*)mem_addr = reloc_addr;
				}
				/* relative physical address */
				else if(GET_RELOC_TYPE(reloc->info) == 0x02)
				{
					mem_addr = (uint32_t)buf + reloc->offset;
					mem_addr += get_section_offset(buf, sh->info);
					/* external reference (kernel symbol most likely) */
					if(symtab->shndx == 0)
					{
						reloc_addr = find_kernel_function(get_symbol_string(buf, 
								symtab->name));
						if(!reloc_addr)
						{
							printk(KERN_INFO, "[mod]: *REL* unresolved dependency \"%s\"\n", 
									get_symbol_string(buf, symtab->name));
							error++;
						}
					}
					else
					{
						reloc_addr = (uint32_t)buf + symtab->address;
						reloc_addr += get_section_offset(buf, symtab->shndx);
					}
					/* we need to make this relative to the memory address */
					reloc_addr = mem_addr - reloc_addr + 4;
					*(intptr_t*)mem_addr = -reloc_addr;
				}
				else
				{
					printk(KERN_INFO, "[mod]: invalid relocation type (%x)\n", 
							GET_RELOC_TYPE(reloc->info));
					error++;
				}
			}
		}
	}
	
	return error;
}