Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool fixes from Ingo Molnar:
"A handful of objtool fixes related to unreachable code, plus a build
fix for out of tree modules"

* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
objtool: Enclose contents of unreachable() macro in a block
objtool: Prevent GCC from merging annotate_unreachable()
objtool: Improve detection of BUG() and other dead ends
objtool: Fix CONFIG_STACK_VALIDATION=y warning for out-of-tree modules

+84 -23
+12 -12
Makefile
··· 910 910 endif 911 911 export mod_sign_cmd 912 912 913 + ifdef CONFIG_STACK_VALIDATION 914 + has_libelf := $(call try-run,\ 915 + echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0) 916 + ifeq ($(has_libelf),1) 917 + objtool_target := tools/objtool FORCE 918 + else 919 + $(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel") 920 + SKIP_STACK_VALIDATION := 1 921 + export SKIP_STACK_VALIDATION 922 + endif 923 + endif 924 + 913 925 914 926 ifeq ($(KBUILD_EXTMOD),) 915 927 core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ ··· 1048 1036 1049 1037 # All the preparing.. 1050 1038 prepare: prepare0 prepare-objtool 1051 - 1052 - ifdef CONFIG_STACK_VALIDATION 1053 - has_libelf := $(call try-run,\ 1054 - echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0) 1055 - ifeq ($(has_libelf),1) 1056 - objtool_target := tools/objtool FORCE 1057 - else 1058 - $(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel") 1059 - SKIP_STACK_VALIDATION := 1 1060 - export SKIP_STACK_VALIDATION 1061 - endif 1062 - endif 1063 1039 1064 1040 PHONY += prepare-objtool 1065 1041 prepare-objtool: $(objtool_target)
+1
arch/x86/kernel/vmlinux.lds.S
··· 346 346 /DISCARD/ : { 347 347 *(.eh_frame) 348 348 *(__func_stack_frame_non_standard) 349 + *(__unreachable) 349 350 } 350 351 } 351 352
+13 -1
include/linux/compiler-gcc.h
··· 197 197 #endif 198 198 #endif 199 199 200 + #ifdef CONFIG_STACK_VALIDATION 201 + #define annotate_unreachable() ({ \ 202 + asm("%c0:\t\n" \ 203 + ".pushsection __unreachable, \"a\"\t\n" \ 204 + ".long %c0b\t\n" \ 205 + ".popsection\t\n" : : "i" (__LINE__)); \ 206 + }) 207 + #else 208 + #define annotate_unreachable() 209 + #endif 210 + 200 211 /* 201 212 * Mark a position in code as unreachable. This can be used to 202 213 * suppress control flow warnings after asm blocks that transfer ··· 217 206 * this in the preprocessor, but we can live with this because they're 218 207 * unreleased. Really, we need to have autoconf for the kernel. 219 208 */ 220 - #define unreachable() __builtin_unreachable() 209 + #define unreachable() \ 210 + do { annotate_unreachable(); __builtin_unreachable(); } while (0) 221 211 222 212 /* Mark a function definition as prohibited from being cloned. */ 223 213 #define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
+2 -3
tools/objtool/arch.h
··· 31 31 #define INSN_CALL_DYNAMIC 8 32 32 #define INSN_RETURN 9 33 33 #define INSN_CONTEXT_SWITCH 10 34 - #define INSN_BUG 11 35 - #define INSN_NOP 12 36 - #define INSN_OTHER 13 34 + #define INSN_NOP 11 35 + #define INSN_OTHER 12 37 36 #define INSN_LAST INSN_OTHER 38 37 39 38 int arch_decode_instruction(struct elf *elf, struct section *sec,
-3
tools/objtool/arch/x86/decode.c
··· 118 118 op2 == 0x35) 119 119 /* sysenter, sysret */ 120 120 *type = INSN_CONTEXT_SWITCH; 121 - else if (op2 == 0x0b || op2 == 0xb9) 122 - /* ud2 */ 123 - *type = INSN_BUG; 124 121 else if (op2 == 0x0d || op2 == 0x1f) 125 122 /* nopl/nopw */ 126 123 *type = INSN_NOP;
+56 -4
tools/objtool/builtin-check.c
··· 51 51 unsigned int len, state; 52 52 unsigned char type; 53 53 unsigned long immediate; 54 - bool alt_group, visited; 54 + bool alt_group, visited, dead_end; 55 55 struct symbol *call_dest; 56 56 struct instruction *jump_dest; 57 57 struct list_head alts; ··· 324 324 if (!insn->func) 325 325 insn->func = func; 326 326 } 327 + } 328 + 329 + return 0; 330 + } 331 + 332 + /* 333 + * Find all uses of the unreachable() macro, which are code path dead ends. 334 + */ 335 + static int add_dead_ends(struct objtool_file *file) 336 + { 337 + struct section *sec; 338 + struct rela *rela; 339 + struct instruction *insn; 340 + bool found; 341 + 342 + sec = find_section_by_name(file->elf, ".rela__unreachable"); 343 + if (!sec) 344 + return 0; 345 + 346 + list_for_each_entry(rela, &sec->rela_list, list) { 347 + if (rela->sym->type != STT_SECTION) { 348 + WARN("unexpected relocation symbol type in .rela__unreachable"); 349 + return -1; 350 + } 351 + insn = find_insn(file, rela->sym->sec, rela->addend); 352 + if (insn) 353 + insn = list_prev_entry(insn, list); 354 + else if (rela->addend == rela->sym->sec->len) { 355 + found = false; 356 + list_for_each_entry_reverse(insn, &file->insn_list, list) { 357 + if (insn->sec == rela->sym->sec) { 358 + found = true; 359 + break; 360 + } 361 + } 362 + 363 + if (!found) { 364 + WARN("can't find unreachable insn at %s+0x%x", 365 + rela->sym->sec->name, rela->addend); 366 + return -1; 367 + } 368 + } else { 369 + WARN("can't find unreachable insn at %s+0x%x", 370 + rela->sym->sec->name, rela->addend); 371 + return -1; 372 + } 373 + 374 + insn->dead_end = true; 327 375 } 328 376 329 377 return 0; ··· 891 843 if (ret) 892 844 return ret; 893 845 846 + ret = add_dead_ends(file); 847 + if (ret) 848 + return ret; 849 + 894 850 add_ignores(file); 895 851 896 852 ret = add_jump_destinations(file); ··· 1089 1037 1090 1038 return 0; 1091 1039 1092 - case INSN_BUG: 1093 - return 0; 1094 - 1095 1040 default: 1096 1041 break; 1097 1042 } 1043 + 1044 + if (insn->dead_end) 1045 + return 0; 1098 1046 1099 1047 insn = next_insn_same_sec(file, insn); 1100 1048 if (!insn) {