@@ -298,24 +298,23 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec,
struct module *me)
{
- Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
- int (*handler)(struct module *me, void *location, Elf_Addr v);
- Elf_Sym *sym;
- void *location;
- unsigned int i, type;
- Elf_Addr v;
- int res;
+ Elf_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+ unsigned int entries = sechdrs[relsec].sh_size / sizeof(*rel);
+ unsigned int i;
pr_debug("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
- for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
- /* This is where to make the change */
- location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
- + rel[i].r_offset;
- /* This is the symbol it is referring to */
- sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ for (i = 0; i < entries; i++) {
+ Elf_Sym *sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ ELF_RISCV_R_SYM(rel[i].r_info);
+ Elf_Addr loc = sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rel[i].r_offset;
+ unsigned int type = ELF_RISCV_R_TYPE(rel[i].r_info);
+ int (*handler)(struct module *me, void *location, Elf_Addr v);
+ Elf_Addr v;
+ int res;
+
if (IS_ERR_VALUE(sym->st_value)) {
/* Ignore unresolved weak symbol */
if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
@@ -325,8 +324,6 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
return -ENOENT;
}
- type = ELF_RISCV_R_TYPE(rel[i].r_info);
-
if (type < ARRAY_SIZE(reloc_handlers_rela))
handler = reloc_handlers_rela[type];
else
@@ -343,48 +340,36 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) {
unsigned int j;
- for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) {
- unsigned long hi20_loc =
- sechdrs[sechdrs[relsec].sh_info].sh_addr
+ /* find the corresponding HI20 entry */
+ for (j = 0; j < entries; j++) {
+ Elf_Sym *hi20_sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ + ELF_RISCV_R_SYM(rel[j].r_info);
+ Elf_Addr hi20_loc = sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[j].r_offset;
- u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info);
-
- /* Find the corresponding HI20 relocation entry */
- if (hi20_loc == sym->st_value
- && (hi20_type == R_RISCV_PCREL_HI20
- || hi20_type == R_RISCV_GOT_HI20)) {
- s32 hi20, lo12;
- Elf_Sym *hi20_sym =
- (Elf_Sym *)sechdrs[symindex].sh_addr
- + ELF_RISCV_R_SYM(rel[j].r_info);
- unsigned long hi20_sym_val =
- hi20_sym->st_value
- + rel[j].r_addend;
-
- /* Calculate lo12 */
- size_t offset = hi20_sym_val - hi20_loc;
- if (IS_ENABLED(CONFIG_MODULE_SECTIONS)
- && hi20_type == R_RISCV_GOT_HI20) {
- offset = module_emit_got_entry(
- me, hi20_sym_val);
- offset = offset - hi20_loc;
- }
- hi20 = (offset + 0x800) & 0xfffff000;
- lo12 = offset - hi20;
- v = lo12;
-
- break;
- }
- }
- if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
- pr_err(
- "%s: Can not find HI20 relocation information\n",
- me->name);
- return -EINVAL;
+ unsigned int hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info);
+
+ if (hi20_loc != sym->st_value ||
+ (hi20_type != R_RISCV_PCREL_HI20 &&
+ hi20_type != R_RISCV_GOT_HI20))
+ continue;
+
+ /* calculate relative offset */
+ v = hi20_sym->st_value + rel[j].r_addend;
+
+ if (IS_ENABLED(CONFIG_MODULE_SECTIONS) &&
+ hi20_type == R_RISCV_GOT_HI20)
+ v = module_emit_got_entry(me, v);
+
+ v -= hi20_loc;
+ goto handle_reloc;
}
- }
- res = handler(me, location, v);
+ pr_err("%s: Cannot find HI20 relocation information\n",
+ me->name);
+ return -EINVAL;
+ }
+handle_reloc:
+ res = handler(me, (void *)loc, v);
if (res)
return res;
}
Signed-off-by: Emil Renner Berthing <kernel@esmil.dk> --- arch/riscv/kernel/module.c | 93 ++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 54 deletions(-)