module.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Kernel module loader for Hexagon
  4. *
  5. * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
  6. */
  7. #include <asm/module.h>
  8. #include <linux/elf.h>
  9. #include <linux/module.h>
  10. #include <linux/moduleloader.h>
  11. #include <linux/vmalloc.h>
  12. #if 0
  13. #define DEBUGP printk
  14. #else
  15. #define DEBUGP(fmt , ...)
  16. #endif
  17. /*
  18. * module_frob_arch_sections - tweak got/plt sections.
  19. * @hdr - pointer to elf header
  20. * @sechdrs - pointer to elf load section headers
  21. * @secstrings - symbol names
  22. * @mod - pointer to module
  23. */
  24. int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
  25. char *secstrings,
  26. struct module *mod)
  27. {
  28. unsigned int i;
  29. int found = 0;
  30. /* Look for .plt and/or .got.plt and/or .init.plt sections */
  31. for (i = 0; i < hdr->e_shnum; i++) {
  32. DEBUGP("Section %d is %s\n", i,
  33. secstrings + sechdrs[i].sh_name);
  34. if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0)
  35. found = i+1;
  36. if (strcmp(secstrings + sechdrs[i].sh_name, ".got.plt") == 0)
  37. found = i+1;
  38. if (strcmp(secstrings + sechdrs[i].sh_name, ".rela.plt") == 0)
  39. found = i+1;
  40. }
  41. /* At this time, we don't support modules comiled with -shared */
  42. if (found) {
  43. printk(KERN_WARNING
  44. "Module '%s' contains unexpected .plt/.got sections.\n",
  45. mod->name);
  46. /* return -ENOEXEC; */
  47. }
  48. return 0;
  49. }
  50. /*
  51. * apply_relocate_add - perform rela relocations.
  52. * @sechdrs - pointer to section headers
  53. * @strtab - some sort of start address?
  54. * @symindex - symbol index offset or something?
  55. * @relsec - address to relocate to?
  56. * @module - pointer to module
  57. *
  58. * Perform rela relocations.
  59. */
  60. int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
  61. unsigned int symindex, unsigned int relsec,
  62. struct module *module)
  63. {
  64. unsigned int i;
  65. Elf32_Sym *sym;
  66. uint32_t *location;
  67. uint32_t value;
  68. unsigned int nrelocs = sechdrs[relsec].sh_size / sizeof(Elf32_Rela);
  69. Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
  70. Elf32_Word sym_info = sechdrs[relsec].sh_info;
  71. Elf32_Sym *sym_base = (Elf32_Sym *) sechdrs[symindex].sh_addr;
  72. void *loc_base = (void *) sechdrs[sym_info].sh_addr;
  73. DEBUGP("Applying relocations in section %u to section %u base=%p\n",
  74. relsec, sym_info, loc_base);
  75. for (i = 0; i < nrelocs; i++) {
  76. /* Symbol to relocate */
  77. sym = sym_base + ELF32_R_SYM(rela[i].r_info);
  78. /* Where to make the change */
  79. location = loc_base + rela[i].r_offset;
  80. /* `Everything is relative'. */
  81. value = sym->st_value + rela[i].r_addend;
  82. DEBUGP("%d: value=%08x loc=%p reloc=%d symbol=%s\n",
  83. i, value, location, ELF32_R_TYPE(rela[i].r_info),
  84. sym->st_name ?
  85. &strtab[sym->st_name] : "(anonymous)");
  86. switch (ELF32_R_TYPE(rela[i].r_info)) {
  87. case R_HEXAGON_B22_PCREL: {
  88. int dist = (int)(value - (uint32_t)location);
  89. if ((dist < -0x00800000) ||
  90. (dist >= 0x00800000)) {
  91. printk(KERN_ERR
  92. "%s: %s: %08x=%08x-%08x %s\n",
  93. module->name,
  94. "R_HEXAGON_B22_PCREL reloc out of range",
  95. dist, value, (uint32_t)location,
  96. sym->st_name ?
  97. &strtab[sym->st_name] : "(anonymous)");
  98. return -ENOEXEC;
  99. }
  100. DEBUGP("B22_PCREL contents: %08X.\n", *location);
  101. *location &= ~0x01ff3fff;
  102. *location |= 0x00003fff & dist;
  103. *location |= 0x01ff0000 & (dist<<2);
  104. DEBUGP("Contents after reloc: %08x\n", *location);
  105. break;
  106. }
  107. case R_HEXAGON_HI16:
  108. value = (value>>16) & 0xffff;
  109. fallthrough;
  110. case R_HEXAGON_LO16:
  111. *location &= ~0x00c03fff;
  112. *location |= value & 0x3fff;
  113. *location |= (value & 0xc000) << 8;
  114. break;
  115. case R_HEXAGON_32:
  116. *location = value;
  117. break;
  118. case R_HEXAGON_32_PCREL:
  119. *location = value - (uint32_t)location;
  120. break;
  121. case R_HEXAGON_PLT_B22_PCREL:
  122. case R_HEXAGON_GOTOFF_LO16:
  123. case R_HEXAGON_GOTOFF_HI16:
  124. printk(KERN_ERR "%s: GOT/PLT relocations unsupported\n",
  125. module->name);
  126. return -ENOEXEC;
  127. default:
  128. printk(KERN_ERR "%s: unknown relocation: %u\n",
  129. module->name,
  130. ELF32_R_TYPE(rela[i].r_info));
  131. return -ENOEXEC;
  132. }
  133. }
  134. return 0;
  135. }