^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/moduleloader.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/elf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) int apply_relocate_add(Elf32_Shdr *sechdrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) const char *strtab,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) unsigned int symindex,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) unsigned int relsec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct module *me)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) pr_debug("Applying relocate section %u to %u\n", relsec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) sechdrs[relsec].sh_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /* This is where to make the change */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) uint32_t *loc =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) (uint32_t *)(sechdrs[sechdrs[relsec].sh_info].sh_addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) + rela[i].r_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* This is the symbol it is referring to. Note that all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) undefined symbols have been resolved. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) Elf32_Sym *sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) + ELF32_R_SYM(rela[i].r_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) uint32_t v = sym->st_value + rela[i].r_addend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) switch (ELF32_R_TYPE(rela[i].r_info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) case R_H8_DIR24R8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) loc = (uint32_t *)((uint32_t)loc - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) case R_H8_DIR24A8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (ELF32_R_SYM(rela[i].r_info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *loc += v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) case R_H8_DIR32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) case R_H8_DIR32A16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) *loc += v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) case R_H8_PCREL16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) v -= (unsigned long)loc + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if ((Elf32_Sword)v > 0x7fff ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) (Elf32_Sword)v < -(Elf32_Sword)0x8000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) goto overflow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *(unsigned short *)loc = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) case R_H8_PCREL8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) v -= (unsigned long)loc + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if ((Elf32_Sword)v > 0x7f ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) (Elf32_Sword)v < -(Elf32_Sword)0x80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) goto overflow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *(unsigned char *)loc = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) pr_err("module %s: Unknown relocation: %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) me->name, ELF32_R_TYPE(rela[i].r_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) overflow:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) pr_err("module %s: relocation offset overflow: %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) me->name, rela[i].r_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }