From b72027c44e6865da4a2f1f56210ba110021ece2f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 20 Sep 2017 11:55:01 -0500 Subject: [PATCH] kpatch-build: do symbol/section bundling in create-diff-object kpatch-elf.c is used by binaries other than create-diff-object, but create-diff-object is the only one that cares about "bundling". Move the bundling to create-diff-object. Fixes #700. Signed-off-by: Josh Poimboeuf --- kpatch-build/create-diff-object.c | 99 +++++++++++++++++++++++++++++++ kpatch-build/kpatch-elf.c | 83 +------------------------- 2 files changed, 100 insertions(+), 82 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 4921487..cdc9e4c 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -81,6 +81,102 @@ struct special_section { * Functions * **********/ +static int is_bundleable(struct symbol *sym) +{ + if (sym->type == STT_FUNC && + !strncmp(sym->sec->name, ".text.",6) && + !strcmp(sym->sec->name + 6, sym->name)) + return 1; + + if (sym->type == STT_FUNC && + !strncmp(sym->sec->name, ".text.unlikely.",15) && + !strcmp(sym->sec->name + 15, sym->name)) + return 1; + + if (sym->type == STT_OBJECT && + !strncmp(sym->sec->name, ".data.",6) && + !strcmp(sym->sec->name + 6, sym->name)) + return 1; + + if (sym->type == STT_OBJECT && + !strncmp(sym->sec->name, ".rodata.",8) && + !strcmp(sym->sec->name + 8, sym->name)) + return 1; + + if (sym->type == STT_OBJECT && + !strncmp(sym->sec->name, ".bss.",5) && + !strcmp(sym->sec->name + 5, sym->name)) + return 1; + + return 0; +} + +#ifdef __powerpc__ +/* Symbol st_others value for powerpc */ +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) +#define PPC64_LOCAL_ENTRY_OFFSET(other) \ + (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) + +/* + * On ppc64le, the function prologue generated by GCC 6+ has the sequence: + * + * .globl my_func + * .type my_func, @function + * .quad .TOC.-my_func + * my_func: + * .reloc ., R_PPC64_ENTRY ; optional + * ld r2,-8(r12) + * add r2,r2,r12 + * .localentry my_func, .-my_func + * + * my_func is the global entry point, which, when called, sets up the TOC. + * .localentry is the local entry point, for calls to the function from within + * the object file. The local entry point is 8 bytes after the global entry + * point. + */ +static int is_localentry_sym(struct symbol *sym) +{ + if (sym->type != STT_FUNC || sym->sym.st_shndx == SHN_UNDEF) + return 0; + + if (sym->sym.st_value != 0x8) + return 0; + + if (!PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other)) + return 0; + + return 1; +} +#else +static int is_localentry_sym(struct symbol *sym) +{ + return 0; +} +#endif + +/* + * When compiling with -ffunction-sections and -fdata-sections, almost every + * symbol gets its own dedicated section. We call such symbols "bundled" + * symbols. They're indicated by "sym->sec->sym == sym". + */ +static void kpatch_bundle_symbols(struct kpatch_elf *kelf) +{ + struct symbol *sym; + + list_for_each_entry(sym, &kelf->symbols, list) { + if (is_bundleable(sym)) { + if (sym->sym.st_value != 0 && !is_localentry_sym(sym)) { + ERROR("symbol %s at offset %lu within section %s, expected 0", + sym->name, sym->sym.st_value, + sym->sec->name); + } + + sym->sec->sym = sym; + } + } +} + /* * This function detects whether the given symbol is a "special" static local * variable (for lack of a better term). @@ -2713,6 +2809,9 @@ int main(int argc, char *argv[]) kelf_base = kpatch_elf_open(arguments.args[0]); kelf_patched = kpatch_elf_open(arguments.args[1]); + kpatch_bundle_symbols(kelf_base); + kpatch_bundle_symbols(kelf_patched); + kpatch_compare_elf_headers(kelf_base->elf, kelf_patched->elf); kpatch_check_program_headers(kelf_base->elf); kpatch_check_program_headers(kelf_patched->elf); diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 72ed62f..54abad3 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -76,46 +76,6 @@ int is_debug_section(struct section *sec) !strncmp(name, ".eh_frame", 9); } -#ifdef __powerpc__ - -/* Symbol st_others value for powerpc */ -#define STO_PPC64_LOCAL_BIT 5 -#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) -#define PPC64_LOCAL_ENTRY_OFFSET(other) \ - (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) - -/* - * On ppc64le, the function prologue generated by GCC 6+ has the sequence: - * - * .globl my_func - * .type my_func, @function - * .quad .TOC.-my_func - * my_func: - * .reloc ., R_PPC64_ENTRY ; optional - * ld r2,-8(r12) - * add r2,r2,r12 - * .localentry my_func, .-my_func - * - * my_func is the global entry point, which, when called, sets up the TOC. - * .localentry is the local entry point, for calls to the function from within - * the object file. The local entry point is 8 bytes after the global entry - * point. - */ -static int is_localentry_sym(struct symbol *sym) -{ - if (sym->type != STT_FUNC || sym->sym.st_shndx == SHN_UNDEF) - return 0; - - if (sym->sym.st_value != 0x8) - return 0; - - if (!PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other)) - return 0; - - return 1; -} -#endif - struct section *find_section_by_index(struct list_head *list, unsigned int index) { struct section *sec; @@ -299,36 +259,6 @@ void kpatch_create_section_list(struct kpatch_elf *kelf) ERROR("expected NULL"); } -static int is_bundleable(struct symbol *sym) -{ - if (sym->type == STT_FUNC && - !strncmp(sym->sec->name, ".text.",6) && - !strcmp(sym->sec->name + 6, sym->name)) - return 1; - - if (sym->type == STT_FUNC && - !strncmp(sym->sec->name, ".text.unlikely.",15) && - !strcmp(sym->sec->name + 15, sym->name)) - return 1; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".data.",6) && - !strcmp(sym->sec->name + 6, sym->name)) - return 1; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".rodata.",8) && - !strcmp(sym->sec->name + 8, sym->name)) - return 1; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".bss.",5) && - !strcmp(sym->sec->name + 5, sym->name)) - return 1; - - return 0; -} - void kpatch_create_symbol_list(struct kpatch_elf *kelf) { struct section *symtab; @@ -367,18 +297,7 @@ void kpatch_create_symbol_list(struct kpatch_elf *kelf) ERROR("couldn't find section for symbol %s\n", sym->name); - if (is_bundleable(sym)) { - if (sym->sym.st_value != 0) { -#ifdef __powerpc__ - if (!is_localentry_sym(sym)) -#endif - ERROR("symbol %s at offset %lu within section %s, expected 0", - sym->name, sym->sym.st_value, sym->sec->name); - } - - sym->sec->sym = sym; - - } else if (sym->type == STT_SECTION) { + if (sym->type == STT_SECTION) { sym->sec->secsym = sym; /* use the section name as the symbol name */ sym->name = sym->sec->name;