From: Lei Chen <[email protected]> Hi list, This patch intends to add support for aarch64. It works almost in the same way as does on x64. But there are still some difference, such as relocation types, and unknown symbols and sections, which confuses kpatch tools.
That's what this patch does. I need your comments. Thanks in advance. Lei Chen. BR. Signed-off-by: Lei Chen <[email protected]> --- kpatch-build/create-diff-object.c | 57 +++++++++++++++++++++++++---- kpatch-build/create-kpatch-module.c | 6 +-- kpatch-build/kpatch-elf.c | 16 ++++++++ kpatch-build/kpatch-elf.h | 9 +++++ 4 files changed, 77 insertions(+), 11 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 6bf2b17..36804d5 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -62,7 +62,9 @@ #ifdef __powerpc64__ #define ABSOLUTE_RELA_TYPE R_PPC64_ADDR64 -#else +#elif defined(__aarch64__) +#define ABSOLUTE_RELA_TYPE R_AARCH64_ABS64 +#elif defined(__x86_64__) #define ABSOLUTE_RELA_TYPE R_X86_64_64 #endif @@ -442,6 +444,12 @@ static void kpatch_compare_correlated_section(struct section *sec) goto out; } + if (!strcmp(sec->name, ".rela__patchable_function_entries") || + !strcmp(sec->name, "__patchable_function_entries")) { + sec->status = SAME; + goto out; + } + if (sec1->sh.sh_size != sec2->sh.sh_size || sec1->data->d_size != sec2->data->d_size) { sec->status = CHANGED; @@ -811,6 +819,10 @@ static void kpatch_correlate_symbols(struct list_head *symlist1, struct list_hea if (sym1->type == STT_NOTYPE && !strncmp(sym1->name, ".LC", 3)) continue; +#ifdef __aarch64__ + if (kpatch_is_arm_mapping_symbol(sym1)) + continue; +#endif /* group section symbols must have correlated sections */ if (sym1->sec && @@ -1285,7 +1297,7 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) continue; } -#ifdef __powerpc64__ +#if defined(__powerpc64__) || defined(__aarch64__) add_off = 0; #else if (rela->type == R_X86_64_PC32 || @@ -1317,7 +1329,11 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) end = sym->sym.st_value + sym->sym.st_size; if (!is_text_section(sym->sec) && +#ifdef __x86_64__ rela->type == R_X86_64_32S && +#elif defined(__aarch64__) + rela->type == R_AARCH64_ABS64 && +#endif rela->addend == (int)sym->sec->sh.sh_size && end == (int)sym->sec->sh.sh_size) { @@ -1371,6 +1387,9 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) log_debug("\n"); } +#ifdef __aarch64__ +static void kpatch_check_func_profiling_calls(struct kpatch_elf *kelf) {} +#else static void kpatch_check_func_profiling_calls(struct kpatch_elf *kelf) { struct symbol *sym; @@ -1389,6 +1408,7 @@ static void kpatch_check_func_profiling_calls(struct kpatch_elf *kelf) if (errs) DIFF_FATAL("%d function(s) can not be patched", errs); } +#endif static void kpatch_verify_patchability(struct kpatch_elf *kelf) { @@ -1835,6 +1855,22 @@ static int fixup_barrier_nospec_group_size(struct kpatch_elf *kelf, int offset) return 8; } #endif +#ifdef __aarch64__ +static int altinstructions_group_size(struct kpatch_elf *kelf, int offset) +{ + static int size = 0; + char *str; + + if (!size) { + str = getenv("ALT_STRUCT_SIZE"); + if (!str) + ERROR("ALT_STRUCT_SIZE not set"); + size = atoi(str); + } + + return size; +} +#endif /* * The rela groups in the .fixup section vary in size. The beginning of each @@ -1937,6 +1973,12 @@ static struct special_section special_sections[] = { .group_size = fixup_barrier_nospec_group_size, .unsupported = 1, }, +#endif +#ifdef __aarch64__ + { + .name = ".altinstructions", + .group_size = altinstructions_group_size, + }, #endif {}, }; @@ -3029,9 +3071,6 @@ static void kpatch_create_callbacks_objname_rela(struct kpatch_elf *kelf, char * } } -#ifdef __powerpc64__ -void kpatch_create_mcount_sections(struct kpatch_elf *kelf) { } -#else /* * This function basically reimplements the functionality of the Linux * recordmcount script, so that patched functions can be recognized by ftrace. @@ -3039,6 +3078,9 @@ void kpatch_create_mcount_sections(struct kpatch_elf *kelf) { } * TODO: Eventually we can modify recordmount so that it recognizes our bundled * sections as valid and does this work for us. */ +#if defined(__powerpc64__) || defined(__aarch64__) +void kpatch_create_mcount_sections(struct kpatch_elf *kelf) { } +#else static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) { int nr, index; @@ -3074,7 +3116,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) /* add rela in .rela__mcount_loc to fill in function pointer */ ALLOC_LINK(rela, &relasec->relas); rela->sym = sym; - rela->type = R_X86_64_64; + rela->type = ABSOLUTE_RELA_TYPE; rela->addend = 0; rela->offset = index * sizeof(*funcs); @@ -3089,7 +3131,6 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) rela = list_first_entry(&sym->sec->rela->relas, struct rela, list); - /* * R_X86_64_NONE is only generated by older versions of kernel/gcc * which use the mcount script. @@ -3097,7 +3138,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) if (rela->type == R_X86_64_NONE) { if (insn[0] != 0xf) ERROR("%s: unexpected instruction at the start of the function", - sym->name); + sym->name); insn[0] = 0xe8; insn[1] = 0; insn[2] = 0; diff --git a/kpatch-build/create-kpatch-module.c b/kpatch-build/create-kpatch-module.c index 67b16b0..b1bbbb8 100644 --- a/kpatch-build/create-kpatch-module.c +++ b/kpatch-build/create-kpatch-module.c @@ -102,14 +102,14 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section /* dest */ ALLOC_LINK(rela, &dynsec->rela->relas); rela->sym = sym; - rela->type = R_X86_64_64; + rela->type = ABSOLUTE_RELA_TYPE; rela->addend = dest_offset; rela->offset = index * sizeof(*dynrelas); /* name */ ALLOC_LINK(rela, &dynsec->rela->relas); rela->sym = strsec->secsym; - rela->type = R_X86_64_64; + rela->type = ABSOLUTE_RELA_TYPE; rela->addend = name_offset; rela->offset = index * sizeof(*dynrelas) + \ offsetof(struct kpatch_patch_dynrela, name); @@ -117,7 +117,7 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section /* objname */ ALLOC_LINK(rela, &dynsec->rela->relas); rela->sym = strsec->secsym; - rela->type = R_X86_64_64; + rela->type = ABSOLUTE_RELA_TYPE; rela->addend = objname_offset; rela->offset = index * sizeof(*dynrelas) + \ offsetof(struct kpatch_patch_dynrela, objname); diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 848a715..b2eece1 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -259,6 +259,17 @@ void kpatch_create_section_list(struct kpatch_elf *kelf) ERROR("expected NULL"); } +#ifdef __aarch64__ +int kpatch_is_arm_mapping_symbol(struct symbol *sym) +{ + if (sym->name && sym->name[0] == '$' + && sym->type == STT_NOTYPE \ + && sym->bind == STB_LOCAL) + return 1; + return 0; +} +#endif + void kpatch_create_symbol_list(struct kpatch_elf *kelf) { struct section *symtab; @@ -314,7 +325,11 @@ void kpatch_create_symbol_list(struct kpatch_elf *kelf) } + /* Check which functions have fentry/mcount calls; save this info for later use. */ +#ifdef __aarch64__ +static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) {} +#else static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) { struct symbol *sym; @@ -342,6 +357,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) #endif } } +#endif struct kpatch_elf *kpatch_elf_open(const char *name) { diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 590aa6c..2b247e5 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -31,6 +31,14 @@ #define SHF_RELA_LIVEPATCH 0x00100000 #define SHN_LIVEPATCH 0xff20 +#ifdef __powerpc64__ +#define ABSOLUTE_RELA_TYPE R_PPC64_ADDR64 +#elif defined(__aarch64__) +#define ABSOLUTE_RELA_TYPE R_AARCH64_ABS64 +#elif defined(__x86_64__) +#define ABSOLUTE_RELA_TYPE R_X86_64_64 +#endif + /******************* * Data structures * ****************/ @@ -166,4 +174,5 @@ void kpatch_rebuild_rela_section_data(struct section *sec); void kpatch_write_output_elf(struct kpatch_elf *kelf, Elf *elf, char *outfile); void kpatch_elf_teardown(struct kpatch_elf *kelf); void kpatch_elf_free(struct kpatch_elf *kelf); +int kpatch_is_arm_mapping_symbol(struct symbol *sym); #endif /* _KPATCH_ELF_H_ */ -- 2.17.1 _______________________________________________ kpatch mailing list [email protected] https://www.redhat.com/mailman/listinfo/kpatch
