special.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <string.h>
  3. #include <objtool/special.h>
  4. #include <objtool/warn.h>
  5. bool arch_support_alt_relocation(struct special_alt *special_alt,
  6. struct instruction *insn,
  7. struct reloc *reloc)
  8. {
  9. return false;
  10. }
  11. struct table_info {
  12. struct list_head jump_info;
  13. unsigned long insn_offset;
  14. unsigned long rodata_offset;
  15. };
  16. static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,
  17. struct instruction *insn,
  18. unsigned long *table_size)
  19. {
  20. struct section *rsec;
  21. struct reloc *reloc;
  22. struct list_head table_list;
  23. struct table_info *orig_table;
  24. struct table_info *next_table;
  25. unsigned long tmp_insn_offset;
  26. unsigned long tmp_rodata_offset;
  27. bool is_valid_list = false;
  28. rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
  29. if (!rsec)
  30. return;
  31. INIT_LIST_HEAD(&table_list);
  32. for_each_reloc(rsec, reloc) {
  33. if (reloc->sym->sec->rodata)
  34. continue;
  35. if (strcmp(insn->sec->name, reloc->sym->sec->name))
  36. continue;
  37. orig_table = malloc(sizeof(struct table_info));
  38. if (!orig_table) {
  39. WARN("malloc failed");
  40. return;
  41. }
  42. orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc);
  43. reloc++;
  44. orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc);
  45. list_add_tail(&orig_table->jump_info, &table_list);
  46. if (reloc_idx(reloc) + 1 == sec_num_entries(rsec))
  47. break;
  48. if (strcmp(insn->sec->name, (reloc + 1)->sym->sec->name)) {
  49. list_for_each_entry(orig_table, &table_list, jump_info) {
  50. if (orig_table->insn_offset == insn->offset) {
  51. is_valid_list = true;
  52. break;
  53. }
  54. }
  55. if (!is_valid_list) {
  56. list_del_init(&table_list);
  57. continue;
  58. }
  59. break;
  60. }
  61. }
  62. list_for_each_entry(orig_table, &table_list, jump_info) {
  63. next_table = list_next_entry(orig_table, jump_info);
  64. list_for_each_entry_from(next_table, &table_list, jump_info) {
  65. if (next_table->rodata_offset < orig_table->rodata_offset) {
  66. tmp_insn_offset = next_table->insn_offset;
  67. tmp_rodata_offset = next_table->rodata_offset;
  68. next_table->insn_offset = orig_table->insn_offset;
  69. next_table->rodata_offset = orig_table->rodata_offset;
  70. orig_table->insn_offset = tmp_insn_offset;
  71. orig_table->rodata_offset = tmp_rodata_offset;
  72. }
  73. }
  74. }
  75. list_for_each_entry(orig_table, &table_list, jump_info) {
  76. if (insn->offset == orig_table->insn_offset) {
  77. next_table = list_next_entry(orig_table, jump_info);
  78. if (&next_table->jump_info == &table_list) {
  79. *table_size = 0;
  80. return;
  81. }
  82. while (next_table->rodata_offset == orig_table->rodata_offset) {
  83. next_table = list_next_entry(next_table, jump_info);
  84. if (&next_table->jump_info == &table_list) {
  85. *table_size = 0;
  86. return;
  87. }
  88. }
  89. *table_size = next_table->rodata_offset - orig_table->rodata_offset;
  90. }
  91. }
  92. }
  93. static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
  94. struct instruction *insn,
  95. unsigned long *table_size)
  96. {
  97. struct section *rsec;
  98. struct reloc *reloc;
  99. unsigned long offset;
  100. rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
  101. if (!rsec)
  102. return NULL;
  103. for_each_reloc(rsec, reloc) {
  104. if (reloc->sym->sec->rodata)
  105. continue;
  106. if (strcmp(insn->sec->name, reloc->sym->sec->name))
  107. continue;
  108. offset = reloc->sym->offset + reloc_addend(reloc);
  109. if (insn->offset == offset) {
  110. get_rodata_table_size_by_table_annotate(file, insn, table_size);
  111. reloc++;
  112. return reloc;
  113. }
  114. }
  115. return NULL;
  116. }
  117. static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,
  118. unsigned long offset,
  119. unsigned long *table_size)
  120. {
  121. struct section *rsec;
  122. struct reloc *reloc;
  123. rsec = sec->rsec;
  124. if (!rsec)
  125. return NULL;
  126. for_each_reloc(rsec, reloc) {
  127. if (reloc_offset(reloc) > offset)
  128. break;
  129. if (!strcmp(reloc->sym->sec->name, C_JUMP_TABLE_SECTION)) {
  130. *table_size = 0;
  131. return reloc;
  132. }
  133. }
  134. return NULL;
  135. }
  136. struct reloc *arch_find_switch_table(struct objtool_file *file,
  137. struct instruction *insn,
  138. unsigned long *table_size)
  139. {
  140. struct reloc *annotate_reloc;
  141. struct reloc *rodata_reloc;
  142. struct section *table_sec;
  143. unsigned long table_offset;
  144. annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
  145. if (!annotate_reloc) {
  146. annotate_reloc = find_reloc_of_rodata_c_jump_table(
  147. insn->sec, insn->offset, table_size);
  148. if (!annotate_reloc)
  149. return NULL;
  150. }
  151. table_sec = annotate_reloc->sym->sec;
  152. table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
  153. /*
  154. * Each table entry has a rela associated with it. The rela
  155. * should reference text in the same function as the original
  156. * instruction.
  157. */
  158. rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
  159. if (!rodata_reloc)
  160. return NULL;
  161. return rodata_reloc;
  162. }
  163. const char *arch_cpu_feature_name(int feature_number)
  164. {
  165. return NULL;
  166. }