int module_frob_arch_sections()

in kernel/module-plts.c [290:377]


int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
			      char *secstrings, struct module *mod)
{
	unsigned long core_plts = 0;
	unsigned long init_plts = 0;
	Elf64_Sym *syms = NULL;
	Elf_Shdr *pltsec, *tramp = NULL;
	int i;

	/*
	 * Find the empty .plt section so we can expand it to store the PLT
	 * entries. Record the symtab address as well.
	 */
	for (i = 0; i < ehdr->e_shnum; i++) {
		if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))
			mod->arch.core.plt_shndx = i;
		else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt"))
			mod->arch.init.plt_shndx = i;
		else if (!strcmp(secstrings + sechdrs[i].sh_name,
				 ".text.ftrace_trampoline"))
			tramp = sechdrs + i;
		else if (sechdrs[i].sh_type == SHT_SYMTAB)
			syms = (Elf64_Sym *)sechdrs[i].sh_addr;
	}

	if (!mod->arch.core.plt_shndx || !mod->arch.init.plt_shndx) {
		pr_err("%s: module PLT section(s) missing\n", mod->name);
		return -ENOEXEC;
	}
	if (!syms) {
		pr_err("%s: module symtab section missing\n", mod->name);
		return -ENOEXEC;
	}

	for (i = 0; i < ehdr->e_shnum; i++) {
		Elf64_Rela *rels = (void *)ehdr + sechdrs[i].sh_offset;
		int nents, numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela);
		Elf64_Shdr *dstsec = sechdrs + sechdrs[i].sh_info;

		if (sechdrs[i].sh_type != SHT_RELA)
			continue;

		/* ignore relocations that operate on non-exec sections */
		if (!(dstsec->sh_flags & SHF_EXECINSTR))
			continue;

		/*
		 * sort branch relocations requiring a PLT by type, symbol index
		 * and addend
		 */
		nents = partition_branch_plt_relas(syms, rels, numrels,
						   sechdrs[i].sh_info);
		if (nents)
			sort(rels, nents, sizeof(Elf64_Rela), cmp_rela, NULL);

		if (!str_has_prefix(secstrings + dstsec->sh_name, ".init"))
			core_plts += count_plts(syms, rels, numrels,
						sechdrs[i].sh_info, dstsec);
		else
			init_plts += count_plts(syms, rels, numrels,
						sechdrs[i].sh_info, dstsec);
	}

	pltsec = sechdrs + mod->arch.core.plt_shndx;
	pltsec->sh_type = SHT_NOBITS;
	pltsec->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
	pltsec->sh_addralign = L1_CACHE_BYTES;
	pltsec->sh_size = (core_plts  + 1) * sizeof(struct plt_entry);
	mod->arch.core.plt_num_entries = 0;
	mod->arch.core.plt_max_entries = core_plts;

	pltsec = sechdrs + mod->arch.init.plt_shndx;
	pltsec->sh_type = SHT_NOBITS;
	pltsec->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
	pltsec->sh_addralign = L1_CACHE_BYTES;
	pltsec->sh_size = (init_plts + 1) * sizeof(struct plt_entry);
	mod->arch.init.plt_num_entries = 0;
	mod->arch.init.plt_max_entries = init_plts;

	if (tramp) {
		tramp->sh_type = SHT_NOBITS;
		tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
		tramp->sh_addralign = __alignof__(struct plt_entry);
		tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
	}

	return 0;
}