There's elf/arch-specific code identical in both functions, with some in section_rel() only. In order to factor that out, generalize the different relocation types Elf_Rela/Elf_Rel (relocation with/without an addend) with the Elf_Rela type, that is just Elf_Rel with a '.r_addend' field. Most of this code only uses Elf_Rel fields ('.r_offset' and '.r_info'). Make usage of '.r_addend' conditional on section header type SHT_RELA. (Note, though, that '.r_addend' is used on SHT_REL in some archs/formats for the _output_ relocation entry, but this is fine and existing code.) This change also seems to help with readability of section_rel[a](). Signed-off-by: Mauricio Faria de Oliveira <mfo@xxxxxxxxxxxxx> --- scripts/mod/modpost.c | 141 +++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a0f59d7a8875..4c1038dccae0 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1716,13 +1716,90 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) #define R_RISCV_SUB32 39 #endif +/* + * RelX: refers to usage of Elf_Rela or Elf_Rel interchangeably where possible. + * + * The usage of Elf_Rela (relocation with an addend) even for Elf_Rel (without) + * as an input parameter is possible for .r_offset and .r_info (same offset on + * both struct types) *BUT* .r_addend can ONLY be accessed on SHT_RELA headers + * (i.e., where it is valid in the input). + * + * Note: .r_addend on SHT_REL is calculated/accessed for the _output_ parameter, + * via the addend_ARCH_rel() functions, but that is fine, as it's not the input. + * + * Return value 1 indicates to skip further processing on this relocation entry. + * + * Output parameters: + * - 'r' is the relocation entry (i.e., replace data at 'r.r_offset' in section + * w/ header 'sechdr' w/ data from symbol w/ symbol table index in 'r.r_info', + * w/ possible relocation addend 'r.r_addend'). + * - 'sym' is that symbol (a pointer to the symbol table + symbol table index). + */ +static int get_relx_sym(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *rela, + Elf_Rela *out_r, Elf_Sym **out_sym) +{ + Elf_Sym *sym; + Elf_Rela r; + unsigned int r_sym; + + /* Get .r_offset/.r_info and r_sym */ + r.r_offset = TO_NATIVE(rela->r_offset); +#if KERNEL_ELFCLASS == ELFCLASS64 + if (elf->hdr->e_machine == EM_MIPS) { + unsigned int r_typ; + + r_sym = ELF64_MIPS_R_SYM(rela->r_info); + r_sym = TO_NATIVE(r_sym); + r_typ = ELF64_MIPS_R_TYPE(rela->r_info); + r.r_info = ELF64_R_INFO(r_sym, r_typ); + } else { + r.r_info = TO_NATIVE(rela->r_info); + r_sym = ELF_R_SYM(r.r_info); + } +#else + r.r_info = TO_NATIVE(rela->r_info); + r_sym = ELF_R_SYM(r.r_info); +#endif + + /* Get .r_addend (only output on SHT_REL) */ + if (sechdr->sh_type == SHT_RELA) { + r.r_addend = TO_NATIVE(rela->r_addend); + } else if (sechdr->sh_type == SHT_REL) { + r.r_addend = 0; + switch (elf->hdr->e_machine) { + case EM_386: + if (addend_386_rel(elf, sechdr, &r)) + return 1; + break; + case EM_ARM: + if (addend_arm_rel(elf, sechdr, &r)) + return 1; + break; + case EM_MIPS: + if (addend_mips_rel(elf, sechdr, &r)) + return 1; + break; + } + } + + sym = elf->symtab_start + r_sym; + + /* Skip special sections */ + if (is_shndx_special(sym->st_shndx)) + return 1; + + /* Done */ + *out_r = r; + *out_sym = sym; + return 0; +} + static void section_rela(const char *modname, struct elf_info *elf, Elf_Shdr *sechdr) { Elf_Sym *sym; Elf_Rela *rela; Elf_Rela r; - unsigned int r_sym; const char *fromsec; Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; @@ -1735,23 +1812,9 @@ static void section_rela(const char *modname, struct elf_info *elf, return; for (rela = start; rela < stop; rela++) { - r.r_offset = TO_NATIVE(rela->r_offset); -#if KERNEL_ELFCLASS == ELFCLASS64 - if (elf->hdr->e_machine == EM_MIPS) { - unsigned int r_typ; - r_sym = ELF64_MIPS_R_SYM(rela->r_info); - r_sym = TO_NATIVE(r_sym); - r_typ = ELF64_MIPS_R_TYPE(rela->r_info); - r.r_info = ELF64_R_INFO(r_sym, r_typ); - } else { - r.r_info = TO_NATIVE(rela->r_info); - r_sym = ELF_R_SYM(r.r_info); - } -#else - r.r_info = TO_NATIVE(rela->r_info); - r_sym = ELF_R_SYM(r.r_info); -#endif - r.r_addend = TO_NATIVE(rela->r_addend); + if (get_relx_sym(elf, sechdr, rela, &r, &sym)) + continue; + switch (elf->hdr->e_machine) { case EM_RISCV: if (!strcmp("__ex_table", fromsec) && @@ -1759,10 +1822,7 @@ static void section_rela(const char *modname, struct elf_info *elf, continue; break; } - sym = elf->symtab_start + r_sym; - /* Skip special sections */ - if (is_shndx_special(sym->st_shndx)) - continue; + if (is_second_extable_reloc(start, rela, fromsec)) find_extable_entry_size(fromsec, &r); check_section_mismatch(modname, elf, &r, sym, fromsec); @@ -1775,7 +1835,6 @@ static void section_rel(const char *modname, struct elf_info *elf, Elf_Sym *sym; Elf_Rel *rel; Elf_Rela r; - unsigned int r_sym; const char *fromsec; Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; @@ -1788,41 +1847,9 @@ static void section_rel(const char *modname, struct elf_info *elf, return; for (rel = start; rel < stop; rel++) { - r.r_offset = TO_NATIVE(rel->r_offset); -#if KERNEL_ELFCLASS == ELFCLASS64 - if (elf->hdr->e_machine == EM_MIPS) { - unsigned int r_typ; - r_sym = ELF64_MIPS_R_SYM(rel->r_info); - r_sym = TO_NATIVE(r_sym); - r_typ = ELF64_MIPS_R_TYPE(rel->r_info); - r.r_info = ELF64_R_INFO(r_sym, r_typ); - } else { - r.r_info = TO_NATIVE(rel->r_info); - r_sym = ELF_R_SYM(r.r_info); - } -#else - r.r_info = TO_NATIVE(rel->r_info); - r_sym = ELF_R_SYM(r.r_info); -#endif - r.r_addend = 0; - switch (elf->hdr->e_machine) { - case EM_386: - if (addend_386_rel(elf, sechdr, &r)) - continue; - break; - case EM_ARM: - if (addend_arm_rel(elf, sechdr, &r)) - continue; - break; - case EM_MIPS: - if (addend_mips_rel(elf, sechdr, &r)) - continue; - break; - } - sym = elf->symtab_start + r_sym; - /* Skip special sections */ - if (is_shndx_special(sym->st_shndx)) + if (get_relx_sym(elf, sechdr, (Elf_Rela *)rel, &r, &sym) continue; + if (is_second_extable_reloc(start, rel, fromsec)) find_extable_entry_size(fromsec, &r); check_section_mismatch(modname, elf, &r, sym, fromsec); -- 2.25.1