module.c 1.9 KB

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