1029223d3SJosh Poimboeuf // SPDX-License-Identifier: GPL-2.0-or-later 2029223d3SJosh Poimboeuf /* 3029223d3SJosh Poimboeuf * Emit the .klp.symid table which allows "objtool klp diff" to reliably 4029223d3SJosh Poimboeuf * disambiguate duplicate-named local symbols in vmlinux. 5029223d3SJosh Poimboeuf * 6029223d3SJosh Poimboeuf * Livepatch identifies a duplicate-named symbol by its position (sympos) 7029223d3SJosh Poimboeuf * among the same-named kallsyms entries, counted in ascending address order 8029223d3SJosh Poimboeuf * in the final linked vmlinux. That order can't be derived from vmlinux.o 9029223d3SJosh Poimboeuf * alone: the final link reorders sub-sections (.text.unlikely*, .data..*, 10029223d3SJosh Poimboeuf * etc). 11029223d3SJosh Poimboeuf * 12029223d3SJosh Poimboeuf * Bridge the gap with a table which survives the final link: a single 13029223d3SJosh Poimboeuf * non-alloc section containing an array of { id, addr } entries, where 14029223d3SJosh Poimboeuf * 'id' is a unique counter identifier and 'addr' has a relocation to the 15029223d3SJosh Poimboeuf * symbol. The linker copies 'id' verbatim and resolves 'addr' to the symbol's 16029223d3SJosh Poimboeuf * final address. 17029223d3SJosh Poimboeuf * 18029223d3SJosh Poimboeuf * The table is only emitted for vmlinux.o, and only when klp-build asks for it 19029223d3SJosh Poimboeuf * with KLP_SYMIDS=1, which adds --klp-symids to the vmlinux.o objtool run. 20029223d3SJosh Poimboeuf * 21029223d3SJosh Poimboeuf * It can't survive --gc-sections, which sweeps the whole section; klp-build 22029223d3SJosh Poimboeuf * rejects CONFIG_LD_DEAD_CODE_DATA_ELIMINATION. 23029223d3SJosh Poimboeuf */ 24029223d3SJosh Poimboeuf #include <linux/string.h> 25029223d3SJosh Poimboeuf 26029223d3SJosh Poimboeuf #include <objtool/objtool.h> 27029223d3SJosh Poimboeuf #include <objtool/warn.h> 28029223d3SJosh Poimboeuf #include <objtool/endianness.h> 29029223d3SJosh Poimboeuf #include <objtool/klp.h> 30029223d3SJosh Poimboeuf 31029223d3SJosh Poimboeuf static const char * const discarded_secs[] = { 32029223d3SJosh Poimboeuf ".discard", 33*6656cf1eSPuranjay Mohan ".exitcall.exit", 34029223d3SJosh Poimboeuf ".modinfo", 353a83d9cdSJosh Poimboeuf ".no_trim_symbol", 36029223d3SJosh Poimboeuf "__tracepoint_check", 37029223d3SJosh Poimboeuf }; 38029223d3SJosh Poimboeuf 39029223d3SJosh Poimboeuf static bool discarded_sec(struct section *sec) 40029223d3SJosh Poimboeuf { 41029223d3SJosh Poimboeuf if (!(sec->sh.sh_flags & SHF_ALLOC)) 42029223d3SJosh Poimboeuf return true; 43029223d3SJosh Poimboeuf 44029223d3SJosh Poimboeuf for (int i = 0; i < ARRAY_SIZE(discarded_secs); i++) 45029223d3SJosh Poimboeuf if (strstarts(sec->name, discarded_secs[i])) 46029223d3SJosh Poimboeuf return true; 47029223d3SJosh Poimboeuf 48029223d3SJosh Poimboeuf return false; 49029223d3SJosh Poimboeuf } 50029223d3SJosh Poimboeuf 51029223d3SJosh Poimboeuf static bool symid_needed(struct elf *elf, struct symbol *sym) 52029223d3SJosh Poimboeuf { 53029223d3SJosh Poimboeuf struct symbol *s; 54029223d3SJosh Poimboeuf 55029223d3SJosh Poimboeuf if (!is_local_sym(sym) || is_undef_sym(sym)) 56029223d3SJosh Poimboeuf return false; 57029223d3SJosh Poimboeuf 58029223d3SJosh Poimboeuf if (!is_func_sym(sym) && !is_object_sym(sym)) 59029223d3SJosh Poimboeuf return false; 60029223d3SJosh Poimboeuf 61029223d3SJosh Poimboeuf if (is_prefix_func(sym)) 62029223d3SJosh Poimboeuf return false; 63029223d3SJosh Poimboeuf 64029223d3SJosh Poimboeuf if (discarded_sec(sym->sec)) 65029223d3SJosh Poimboeuf return false; 66029223d3SJosh Poimboeuf 67029223d3SJosh Poimboeuf for_each_sym_by_name(elf, sym->name, s) { 68029223d3SJosh Poimboeuf if (s == sym || is_sec_sym(s) || is_file_sym(s) || is_undef_sym(s)) 69029223d3SJosh Poimboeuf continue; 70029223d3SJosh Poimboeuf return true; 71029223d3SJosh Poimboeuf } 72029223d3SJosh Poimboeuf 73029223d3SJosh Poimboeuf return false; 74029223d3SJosh Poimboeuf } 75029223d3SJosh Poimboeuf 76029223d3SJosh Poimboeuf int klp_create_symid_sections(struct objtool_file *file) 77029223d3SJosh Poimboeuf { 78029223d3SJosh Poimboeuf struct elf *elf = file->elf; 79029223d3SJosh Poimboeuf struct klp_symid *symids; 80029223d3SJosh Poimboeuf struct section *sec; 81029223d3SJosh Poimboeuf struct symbol *sym; 82029223d3SJosh Poimboeuf u64 nr = 0, i = 0; 83029223d3SJosh Poimboeuf 84029223d3SJosh Poimboeuf if (!str_ends_with(objname, "vmlinux.o")) 85029223d3SJosh Poimboeuf return 0; 86029223d3SJosh Poimboeuf 87029223d3SJosh Poimboeuf for_each_sym(elf, sym) 88029223d3SJosh Poimboeuf if (symid_needed(elf, sym)) 89029223d3SJosh Poimboeuf nr++; 90029223d3SJosh Poimboeuf 91029223d3SJosh Poimboeuf if (!nr) 92029223d3SJosh Poimboeuf return 0; 93029223d3SJosh Poimboeuf 94029223d3SJosh Poimboeuf sec = elf_create_section(elf, KLP_SYMID_SEC, 0, sizeof(struct klp_symid), 95029223d3SJosh Poimboeuf SHT_PROGBITS, 8, 0); 96029223d3SJosh Poimboeuf if (!sec) 97029223d3SJosh Poimboeuf return -1; 98029223d3SJosh Poimboeuf 99029223d3SJosh Poimboeuf symids = elf_add_data(elf, sec, NULL, nr * sizeof(struct klp_symid)); 100029223d3SJosh Poimboeuf if (!symids) 101029223d3SJosh Poimboeuf return -1; 102029223d3SJosh Poimboeuf 103029223d3SJosh Poimboeuf for_each_sym(elf, sym) { 104029223d3SJosh Poimboeuf if (!symid_needed(elf, sym)) 105029223d3SJosh Poimboeuf continue; 106029223d3SJosh Poimboeuf 107029223d3SJosh Poimboeuf symids[i].id = bswap_if_needed(elf, i); 108029223d3SJosh Poimboeuf 109029223d3SJosh Poimboeuf if (!elf_create_reloc(elf, sec, 110029223d3SJosh Poimboeuf i * sizeof(struct klp_symid) + 111029223d3SJosh Poimboeuf offsetof(struct klp_symid, addr), 112029223d3SJosh Poimboeuf sym, 0, R_ABS64)) 113029223d3SJosh Poimboeuf return -1; 114029223d3SJosh Poimboeuf 115029223d3SJosh Poimboeuf i++; 116029223d3SJosh Poimboeuf } 117029223d3SJosh Poimboeuf 118029223d3SJosh Poimboeuf return 0; 119029223d3SJosh Poimboeuf } 120