aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/objtool/check.c37
1 files changed, 12 insertions, 25 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f4bbce838433..3a31b238f885 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -905,40 +905,19 @@ static struct rela *find_switch_table(struct objtool_file *file,
905 struct instruction *orig_insn = insn; 905 struct instruction *orig_insn = insn;
906 unsigned long table_offset; 906 unsigned long table_offset;
907 907
908 /* case 1 & 2 */
909 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
910 if (text_rela && text_rela->sym == file->rodata->sym &&
911 !find_symbol_containing(file->rodata, text_rela->addend)) {
912
913 table_offset = text_rela->addend;
914 if (text_rela->type == R_X86_64_PC32) {
915 /* case 2 */
916 table_offset += 4;
917 file->ignore_unreachables = true;
918 }
919
920 rodata_rela = find_rela_by_dest(file->rodata, table_offset);
921 if (!rodata_rela)
922 return NULL;
923
924 return rodata_rela;
925 }
926
927 /* case 3 */
928 /* 908 /*
929 * Backward search using the @first_jump_src links, these help avoid 909 * Backward search using the @first_jump_src links, these help avoid
930 * much of the 'in between' code. Which avoids us getting confused by 910 * much of the 'in between' code. Which avoids us getting confused by
931 * it. 911 * it.
932 */ 912 */
933 for (insn = list_prev_entry(insn, list); 913 for (;
934
935 &insn->list != &file->insn_list && 914 &insn->list != &file->insn_list &&
936 insn->sec == func->sec && 915 insn->sec == func->sec &&
937 insn->offset >= func->offset; 916 insn->offset >= func->offset;
938 917
939 insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { 918 insn = insn->first_jump_src ?: list_prev_entry(insn, list)) {
940 919
941 if (insn->type == INSN_JUMP_DYNAMIC) 920 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
942 break; 921 break;
943 922
944 /* allow small jumps within the range */ 923 /* allow small jumps within the range */
@@ -965,10 +944,18 @@ static struct rela *find_switch_table(struct objtool_file *file,
965 if (find_symbol_containing(file->rodata, table_offset)) 944 if (find_symbol_containing(file->rodata, table_offset))
966 continue; 945 continue;
967 946
968 /* mov [rodata addr], %reg */
969 rodata_rela = find_rela_by_dest(file->rodata, table_offset); 947 rodata_rela = find_rela_by_dest(file->rodata, table_offset);
970 if (rodata_rela) 948 if (rodata_rela) {
949 /*
950 * Use of RIP-relative switch jumps is quite rare, and
951 * indicates a rare GCC quirk/bug which can leave dead
952 * code behind.
953 */
954 if (text_rela->type == R_X86_64_PC32)
955 file->ignore_unreachables = true;
956
971 return rodata_rela; 957 return rodata_rela;
958 }
972 } 959 }
973 960
974 return NULL; 961 return NULL;