1 // SPDX-License-Identifier: GPL-2.0-or-later 2 #include <string.h> 3 4 #include <arch/special.h> 5 #include <objtool/special.h> 6 #include <objtool/builtin.h> 7 #include <objtool/warn.h> 8 #include <asm/cpufeatures.h> 9 10 /* cpu feature name array generated from cpufeatures.h */ 11 #include "cpu-feature-names.c" 12 13 /* 14 * An alternative with an empty replacement, e.g. the second entry of 15 * 16 * ALTERNATIVE_2("orig", "repl", ft1, "", ft2) 17 * 18 * still gets a relocation for its replacement offset. But the label it points 19 * at is the end of the previous entry's replacement, which is also the 20 * beginning of the *next* entry's replacement. The value is meaningless: it's 21 * only ever used with a length of zero. 22 */ 23 bool arch_alt_ignore_new_reloc(struct section *sec, unsigned long offset) 24 { 25 unsigned long entry_off; 26 27 if (strcmp(sec->name, ".altinstructions")) 28 return false; 29 30 entry_off = offset - (offset % ALT_ENTRY_SIZE); 31 32 if (offset - entry_off != ALT_NEW_OFFSET) 33 return false; 34 35 return !*(unsigned char *)(sec->data->d_buf + entry_off + 36 ALT_NEW_LEN_OFFSET); 37 } 38 39 void arch_handle_alternative(struct special_alt *alt) 40 { 41 static struct special_alt *group, *prev; 42 43 /* 44 * Recompute orig_len for nested ALTERNATIVE()s. 45 */ 46 if (group && group->orig_sec == alt->orig_sec && 47 group->orig_off == alt->orig_off) { 48 49 struct special_alt *iter = group; 50 for (;;) { 51 unsigned int len = max(iter->orig_len, alt->orig_len); 52 iter->orig_len = alt->orig_len = len; 53 54 if (iter == prev) 55 break; 56 57 iter = list_next_entry(iter, list); 58 } 59 60 } else group = alt; 61 62 prev = alt; 63 } 64 65 bool arch_support_alt_relocation(struct special_alt *special_alt, 66 struct instruction *insn, 67 struct reloc *reloc) 68 { 69 return true; 70 } 71 72 /* 73 * There are 3 basic jump table patterns: 74 * 75 * 1. jmpq *[rodata addr](,%reg,8) 76 * 77 * This is the most common case by far. It jumps to an address in a simple 78 * jump table which is stored in .rodata. 79 * 80 * 2. jmpq *[rodata addr](%rip) 81 * 82 * This is caused by a rare GCC quirk, currently only seen in three driver 83 * functions in the kernel, only with certain obscure non-distro configs. 84 * 85 * As part of an optimization, GCC makes a copy of an existing switch jump 86 * table, modifies it, and then hard-codes the jump (albeit with an indirect 87 * jump) to use a single entry in the table. The rest of the jump table and 88 * some of its jump targets remain as dead code. 89 * 90 * In such a case we can just crudely ignore all unreachable instruction 91 * warnings for the entire object file. Ideally we would just ignore them 92 * for the function, but that would require redesigning the code quite a 93 * bit. And honestly that's just not worth doing: unreachable instruction 94 * warnings are of questionable value anyway, and this is such a rare issue. 95 * 96 * 3. mov [rodata addr],%reg1 97 * ... some instructions ... 98 * jmpq *(%reg1,%reg2,8) 99 * 100 * This is a fairly uncommon pattern which is new for GCC 6. As of this 101 * writing, there are 11 occurrences of it in the allmodconfig kernel. 102 * 103 * As of GCC 7 there are quite a few more of these and the 'in between' code 104 * is significant. Esp. with KASAN enabled some of the code between the mov 105 * and jmpq uses .rodata itself, which can confuse things. 106 * 107 * TODO: Once we have DWARF CFI and smarter instruction decoding logic, 108 * ensure the same register is used in the mov and jump instructions. 109 * 110 * NOTE: MITIGATION_RETPOLINE made it harder still to decode dynamic jumps. 111 */ 112 struct reloc *arch_find_switch_table(struct objtool_file *file, 113 struct instruction *insn, 114 unsigned long *table_size) 115 { 116 struct reloc *text_reloc, *rodata_reloc; 117 struct section *table_sec; 118 unsigned long table_offset; 119 120 /* look for a relocation which references .rodata */ 121 text_reloc = find_reloc_by_dest_range(file->elf, insn->sec, 122 insn->offset, insn->len); 123 if (!text_reloc || !is_sec_sym(text_reloc->sym) || 124 !text_reloc->sym->sec->rodata) 125 return NULL; 126 127 table_offset = reloc_addend(text_reloc); 128 table_sec = text_reloc->sym->sec; 129 130 if (reloc_type(text_reloc) == R_X86_64_PC32) 131 table_offset += 4; 132 133 /* 134 * Make sure the .rodata address isn't associated with a 135 * symbol. GCC jump tables are anonymous data. 136 * 137 * Also support C jump tables which are in the same format as 138 * switch jump tables. For objtool to recognize them, they 139 * need to be placed in the C_JUMP_TABLE_SECTION section. They 140 * have symbols associated with them. 141 */ 142 if (find_symbol_containing(table_sec, table_offset) && 143 strcmp(table_sec->name, C_JUMP_TABLE_SECTION)) 144 return NULL; 145 146 /* 147 * Each table entry has a rela associated with it. The rela 148 * should reference text in the same function as the original 149 * instruction. 150 */ 151 rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset); 152 if (!rodata_reloc) 153 return NULL; 154 155 /* 156 * Use of RIP-relative switch jumps is quite rare, and 157 * indicates a rare GCC quirk/bug which can leave dead 158 * code behind. 159 */ 160 if (!file->ignore_unreachables && reloc_type(text_reloc) == R_X86_64_PC32) { 161 WARN_INSN(insn, "ignoring unreachables due to jump table quirk"); 162 file->ignore_unreachables = true; 163 } 164 165 *table_size = 0; 166 return rodata_reloc; 167 } 168 169 const char *arch_cpu_feature_name(int feature_number) 170 { 171 return (feature_number < ARRAY_SIZE(cpu_feature_names)) ? 172 cpu_feature_names[feature_number] : NULL; 173 } 174