xref: /linux/tools/objtool/arch/x86/special.c (revision 368cf60c36a3a311474de08e52dc6314df3b06ce)
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