diff options
| -rw-r--r-- | tools/objtool/check.c | 37 |
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; |
