module.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* MN10300 Kernel module helper routines
  2. *
  3. * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All Rights Reserved.
  4. * Written by Mark Salter (msalter@redhat.com)
  5. * - Derived from arch/i386/kernel/module.c
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public Licence as published by
  9. * the Free Software Foundation; either version 2 of the Licence, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public Licence for more details.
  16. *
  17. * You should have received a copy of the GNU General Public Licence
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include <linux/moduleloader.h>
  22. #include <linux/elf.h>
  23. #include <linux/vmalloc.h>
  24. #include <linux/fs.h>
  25. #include <linux/string.h>
  26. #include <linux/kernel.h>
  27. #include <linux/bug.h>
  28. #if 0
  29. #define DEBUGP printk
  30. #else
  31. #define DEBUGP(fmt, ...)
  32. #endif
  33. static void reloc_put16(uint8_t *p, uint32_t val)
  34. {
  35. p[0] = val & 0xff;
  36. p[1] = (val >> 8) & 0xff;
  37. }
  38. static void reloc_put24(uint8_t *p, uint32_t val)
  39. {
  40. reloc_put16(p, val);
  41. p[2] = (val >> 16) & 0xff;
  42. }
  43. static void reloc_put32(uint8_t *p, uint32_t val)
  44. {
  45. reloc_put16(p, val);
  46. reloc_put16(p+2, val >> 16);
  47. }
  48. /*
  49. * apply a RELA relocation
  50. */
  51. int apply_relocate_add(Elf32_Shdr *sechdrs,
  52. const char *strtab,
  53. unsigned int symindex,
  54. unsigned int relsec,
  55. struct module *me)
  56. {
  57. unsigned int i, sym_diff_seen = 0;
  58. Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
  59. Elf32_Sym *sym;
  60. Elf32_Addr relocation, sym_diff_val = 0;
  61. uint8_t *location;
  62. uint32_t value;
  63. DEBUGP("Applying relocate section %u to %u\n",
  64. relsec, sechdrs[relsec].sh_info);
  65. for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
  66. /* this is where to make the change */
  67. location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
  68. + rel[i].r_offset;
  69. /* this is the symbol the relocation is referring to (note that
  70. * all undefined symbols have been resolved by the caller) */
  71. sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
  72. + ELF32_R_SYM(rel[i].r_info);
  73. /* this is the adjustment to be made */
  74. relocation = sym->st_value + rel[i].r_addend;
  75. if (sym_diff_seen) {
  76. switch (ELF32_R_TYPE(rel[i].r_info)) {
  77. case R_MN10300_32:
  78. case R_MN10300_24:
  79. case R_MN10300_16:
  80. case R_MN10300_8:
  81. relocation -= sym_diff_val;
  82. sym_diff_seen = 0;
  83. break;
  84. default:
  85. printk(KERN_ERR "module %s: Unexpected SYM_DIFF relocation: %u\n",
  86. me->name, ELF32_R_TYPE(rel[i].r_info));
  87. return -ENOEXEC;
  88. }
  89. }
  90. switch (ELF32_R_TYPE(rel[i].r_info)) {
  91. /* for the first four relocation types, we simply
  92. * store the adjustment at the location given */
  93. case R_MN10300_32:
  94. reloc_put32(location, relocation);
  95. break;
  96. case R_MN10300_24:
  97. reloc_put24(location, relocation);
  98. break;
  99. case R_MN10300_16:
  100. reloc_put16(location, relocation);
  101. break;
  102. case R_MN10300_8:
  103. *location = relocation;
  104. break;
  105. /* for the next three relocation types, we write the
  106. * adjustment with the address subtracted over the
  107. * value at the location given */
  108. case R_MN10300_PCREL32:
  109. value = relocation - (uint32_t) location;
  110. reloc_put32(location, value);
  111. break;
  112. case R_MN10300_PCREL16:
  113. value = relocation - (uint32_t) location;
  114. reloc_put16(location, value);
  115. break;
  116. case R_MN10300_PCREL8:
  117. *location = relocation - (uint32_t) location;
  118. break;
  119. case R_MN10300_SYM_DIFF:
  120. /* This is used to adjust the next reloc as required
  121. * by relaxation. */
  122. sym_diff_seen = 1;
  123. sym_diff_val = sym->st_value;
  124. break;
  125. case R_MN10300_ALIGN:
  126. /* Just ignore the ALIGN relocs.
  127. * Only interesting if kernel performed relaxation. */
  128. continue;
  129. default:
  130. printk(KERN_ERR "module %s: Unknown relocation: %u\n",
  131. me->name, ELF32_R_TYPE(rel[i].r_info));
  132. return -ENOEXEC;
  133. }
  134. }
  135. if (sym_diff_seen) {
  136. printk(KERN_ERR "module %s: Nothing follows SYM_DIFF relocation: %u\n",
  137. me->name, ELF32_R_TYPE(rel[i].r_info));
  138. return -ENOEXEC;
  139. }
  140. return 0;
  141. }