From 1a3af2aaee85bd475bda44993b3e8dc1335497d5 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Thu, 10 Oct 2024 16:58:58 -0400 Subject: [PATCH 101/118] aarch64: create-diff-object implementation TODO Signed-off-by: Suraj Jitindar Singh Signed-off-by: Pete Swain Signed-off-by: Mihails Strasuns Signed-off-by: Joe Lawrence --- kpatch-build/create-diff-object.c | 104 ++++++++++++++++++++++++++---- kpatch-build/kpatch-elf.c | 8 +++ kpatch-build/kpatch-elf.h | 1 + 3 files changed, 101 insertions(+), 12 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 8170b18..e62880b 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -173,6 +173,8 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, struct symbol *sym) { switch(kelf->arch) { + case AARCH64: + return false; case PPC64: return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) && sym->sym.st_value == 8); @@ -230,6 +232,25 @@ static struct rela *toc_rela(const struct rela *rela) (unsigned int)rela->addend); } +/* + * Mapping symbols are used to mark and label the transitions between code and + * data in elf files. They begin with a "$" dollar symbol. Don't correlate them + * as they often all have the same name either "$x" to mark the start of code + * or "$d" to mark the start of data. + */ +static bool kpatch_is_mapping_symbol(struct kpatch_elf *kelf, struct symbol *sym) +{ + if (kelf->arch != AARCH64) + return false; + + if (sym->name && sym->name[0] == '$' && + sym->type == STT_NOTYPE && + sym->bind == STB_LOCAL) + return true; + + return false; +} + /* * When compiling with -ffunction-sections and -fdata-sections, almost every * symbol gets its own dedicated section. We call such symbols "bundled" @@ -667,6 +688,12 @@ static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr) switch(kelf->arch) { + case AARCH64: + /* Verify mov w2 */ + if ((insn[0] & 0b11111) == 0x2 && insn[3] == 0x52) + return true; + break; + case X86_64: /* arg2: mov $imm, %esi */ if (insn[0] == 0xbe) @@ -1076,15 +1103,15 @@ static void kpatch_correlate_sections(struct list_head *seclist_orig, } } -static void kpatch_correlate_symbols(struct list_head *symlist_orig, - struct list_head *symlist_patched) +static void kpatch_correlate_symbols(struct kpatch_elf *kelf_orig, + struct kpatch_elf *kelf_patched) { struct symbol *sym_orig, *sym_patched; - list_for_each_entry(sym_orig, symlist_orig, list) { + list_for_each_entry(sym_orig, &kelf_orig->symbols, list) { if (sym_orig->twin) continue; - list_for_each_entry(sym_patched, symlist_patched, list) { + list_for_each_entry(sym_patched, &kelf_patched->symbols, list) { if (kpatch_mangled_strcmp(sym_orig->name, sym_patched->name) || sym_orig->type != sym_patched->type || sym_patched->twin) continue; @@ -1104,6 +1131,9 @@ static void kpatch_correlate_symbols(struct list_head *symlist_orig, !strncmp(sym_orig->name, ".LC", 3)) continue; + if (kpatch_is_mapping_symbol(kelf_orig, sym_orig)) + continue; + /* group section symbols must have correlated sections */ if (sym_orig->sec && sym_orig->sec->sh.sh_type == SHT_GROUP && @@ -1509,7 +1539,7 @@ static void kpatch_correlate_elfs(struct kpatch_elf *kelf_orig, struct kpatch_elf *kelf_patched) { kpatch_correlate_sections(&kelf_orig->sections, &kelf_patched->sections); - kpatch_correlate_symbols(&kelf_orig->symbols, &kelf_patched->symbols); + kpatch_correlate_symbols(kelf_orig, kelf_patched); } static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf) @@ -1625,7 +1655,8 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) if (is_text_section(relasec->base) && !is_text_section(sym->sec) && - is_arch(X86_64) && rela->type == R_X86_64_32S && + ((is_arch(X86_64) && rela->type == R_X86_64_32S) || + (is_arch(AARCH64) && rela->type == R_AARCH64_ABS64)) && rela->addend == (long)sym->sec->sh.sh_size && end == (long)sym->sec->sh.sh_size) { @@ -1662,6 +1693,9 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) */ } else if (target_off == start && target_off == end) { + if(kpatch_is_mapping_symbol(kelf, sym)) + continue; + /* * Allow replacement for references to * empty symbols. @@ -2422,28 +2456,28 @@ static bool static_call_sites_group_filter(struct lookup_table *lookup, static struct special_section special_sections[] = { { .name = "__bug_table", - .arch = X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390, .group_size = bug_table_group_size, }, { .name = ".fixup", - .arch = X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390, .group_size = fixup_group_size, }, { .name = "__ex_table", /* must come after .fixup */ - .arch = X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390, .group_size = ex_table_group_size, }, { .name = "__jump_table", - .arch = X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390, .group_size = jump_table_group_size, .group_filter = jump_table_group_filter, }, { .name = ".printk_index", - .arch = X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390, .group_size = printk_index_group_size, }, { @@ -2458,7 +2492,7 @@ static struct special_section special_sections[] = { }, { .name = ".altinstructions", - .arch = X86_64 | S390, + .arch = AARCH64 | X86_64 | S390, .group_size = altinstructions_group_size, }, { @@ -3774,6 +3808,47 @@ static void kpatch_create_ftrace_callsite_sections(struct kpatch_elf *kelf, bool } switch(kelf->arch) { + case AARCH64: + unsigned char *insn; + + /* + * Assume ppc64le is built with -fpatchable-function-entry=2, which means that all 2 nops are + * after the entry point of the function. + * + * Disassembly of section .text.cmdline_proc_show: + * + * 0000000000000000 : + * 0: d503201f nop << << + * 4: d503201f nop + * + * Relocation section '.rela__patchable_function_entries' + * Offset Info Type Symbol's Value Symbol's Name + Addend + * 0000000000000008 0000000f00000101 R_AARCH64_ABS64 0000000000000000 .text.cmdline_proc_show + 0 + * ^ + */ + insn_offset = 0; + insn = sym->sec->data->d_buf + insn_offset; + + /* + * If BTI (Branch Target Identification) is enabled then there + * might be an additional 'BTI C' instruction before the two + * patchable function entry 'NOP's. + * i.e. 0xd503245f (little endian) + */ + if (insn[0] == 0x5f) { + if (insn[1] != 0x24 || insn[2] != 0x03 || insn[3] != 0xd5) + ERROR("%s: unexpected instruction in patch section of function\n", sym->name); + insn_offset += 4; + insn += 4; + } + for (int i=0; i<8; i+=4) { + /* We expect a NOP i.e. 0xd503201f (little endian) */ + if (insn[i] != 0x1f || insn[i + 1] != 0x20 || + insn[i + 2] != 0x03 || insn [i + 3] != 0xd5) + ERROR("%s: unexpected instruction in patch section of function\n", sym->name); + } + + break; case PPC64: { unsigned char *insn; @@ -4067,6 +4142,11 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) continue; switch(kelf->arch) { + case AARCH64: + if (kpatch_symbol_has_pfe_entry(kelf, sym)) { + sym->has_func_profiling = 1; + } + break; case PPC64: if (kpatch_symbol_has_pfe_entry(kelf, sym)) { sym->has_func_profiling = 1; diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 073b808..17c0491 100755 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -156,6 +156,8 @@ struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset) unsigned int absolute_rela_type(struct kpatch_elf *kelf) { switch(kelf->arch) { + case AARCH64: + return R_AARCH64_ABS64; case PPC64: return R_PPC64_ADDR64; case X86_64: @@ -225,6 +227,7 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, struct section *sec = relasec->base; switch(kelf->arch) { + case AARCH64: case PPC64: add_off = 0; break; @@ -274,6 +277,8 @@ unsigned int insn_length(struct kpatch_elf *kelf, void *addr) char *insn = addr; switch(kelf->arch) { + case AARCH64: + return 4; case X86_64: insn_init(&decoded_insn, addr, 1); @@ -604,6 +609,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name) if (!gelf_getehdr(kelf->elf, &ehdr)) ERROR("gelf_getehdr"); switch (ehdr.e_machine) { + case EM_AARCH64: + kelf->arch = AARCH64; + break; case EM_PPC64: kelf->arch = PPC64; break; diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 3389dfe..4a3617d 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -116,6 +116,7 @@ enum architecture { PPC64 = 0x1 << 0, X86_64 = 0x1 << 1, S390 = 0x1 << 2, + AARCH64 = 0x1 << 3, }; struct kpatch_elf { -- 2.48.1