int module_finalize()

in kernel/module.c [856:970]


int module_finalize(const Elf_Ehdr *hdr,
		    const Elf_Shdr *sechdrs,
		    struct module *me)
{
	int i;
	unsigned long nsyms;
	const char *strtab = NULL;
	const Elf_Shdr *s;
	char *secstrings;
	int symindex = -1;
	Elf_Sym *newptr, *oldptr;
	Elf_Shdr *symhdr = NULL;
#ifdef DEBUG
	Elf_Fdesc *entry;
	u32 *addr;

	entry = (Elf_Fdesc *)me->init;
	printk("FINALIZE, ->init FPTR is %p, GP %lx ADDR %lx\n", entry,
	       entry->gp, entry->addr);
	addr = (u32 *)entry->addr;
	printk("INSNS: %x %x %x %x\n",
	       addr[0], addr[1], addr[2], addr[3]);
	printk("got entries used %ld, gots max %ld\n"
	       "fdescs used %ld, fdescs max %ld\n",
	       me->arch.got_count, me->arch.got_max,
	       me->arch.fdesc_count, me->arch.fdesc_max);
#endif

	register_unwind_table(me, sechdrs);

	/* haven't filled in me->symtab yet, so have to find it
	 * ourselves */
	for (i = 1; i < hdr->e_shnum; i++) {
		if(sechdrs[i].sh_type == SHT_SYMTAB
		   && (sechdrs[i].sh_flags & SHF_ALLOC)) {
			int strindex = sechdrs[i].sh_link;
			symindex = i;
			/* FIXME: AWFUL HACK
			 * The cast is to drop the const from
			 * the sechdrs pointer */
			symhdr = (Elf_Shdr *)&sechdrs[i];
			strtab = (char *)sechdrs[strindex].sh_addr;
			break;
		}
	}

	pr_debug("module %s: strtab %p, symhdr %p\n",
	       me->name, strtab, symhdr);

	if(me->arch.got_count > MAX_GOTS) {
		printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d)\n",
				me->name, me->arch.got_count, MAX_GOTS);
		return -EINVAL;
	}

	kfree(me->arch.section);
	me->arch.section = NULL;

	/* no symbol table */
	if(symhdr == NULL)
		return 0;

	oldptr = (void *)symhdr->sh_addr;
	newptr = oldptr + 1;	/* we start counting at 1 */
	nsyms = symhdr->sh_size / sizeof(Elf_Sym);
	pr_debug("OLD num_symtab %lu\n", nsyms);

	for (i = 1; i < nsyms; i++) {
		oldptr++;	/* note, count starts at 1 so preincrement */
		if(strncmp(strtab + oldptr->st_name,
			      ".L", 2) == 0)
			continue;

		if(newptr != oldptr)
			*newptr++ = *oldptr;
		else
			newptr++;

	}
	nsyms = newptr - (Elf_Sym *)symhdr->sh_addr;
	pr_debug("NEW num_symtab %lu\n", nsyms);
	symhdr->sh_size = nsyms * sizeof(Elf_Sym);

	/* find .altinstructions section */
	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
		void *aseg = (void *) s->sh_addr;
		char *secname = secstrings + s->sh_name;

		if (!strcmp(".altinstructions", secname))
			/* patch .altinstructions */
			apply_alternatives(aseg, aseg + s->sh_size, me->name);

#ifdef CONFIG_DYNAMIC_FTRACE
		/* For 32 bit kernels we're compiling modules with
		 * -ffunction-sections so we must relocate the addresses in the
		 *  ftrace callsite section.
		 */
		if (symindex != -1 && !strcmp(secname, FTRACE_CALLSITE_SECTION)) {
			int err;
			if (s->sh_type == SHT_REL)
				err = apply_relocate((Elf_Shdr *)sechdrs,
							strtab, symindex,
							s - sechdrs, me);
			else if (s->sh_type == SHT_RELA)
				err = apply_relocate_add((Elf_Shdr *)sechdrs,
							strtab, symindex,
							s - sechdrs, me);
			if (err)
				return err;
		}
#endif
	}
	return 0;
}