From 59e4e35a001e9291de7e771682cd4b04980f417b Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Wed, 6 Oct 2021 12:49:33 -0700 Subject: [PATCH] kpatch-build: Enable ARM64 support Add the final support required for aarch64 and enable building on that arch. Signed-off-by: Suraj Jitindar Singh --- README.md | 2 +- kpatch-build/Makefile | 1 + kpatch-build/create-diff-object.c | 71 +++++++++++++++++++++++-------- kpatch-build/kpatch-build | 47 ++++++++++++++++++++ 4 files changed, 102 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 3488a0385..45a515afe 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Supported Architectures - [x] x86-64 - [x] ppc64le -- [ ] arm64 +- [x] arm64 - [ ] s390 Installation diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile index 50899b644..9273de12d 100644 --- a/kpatch-build/Makefile +++ b/kpatch-build/Makefile @@ -22,6 +22,7 @@ GCC_PLUGINS_DIR := $(shell gcc -print-file-name=plugin) PLUGIN_CFLAGS := $(filter-out -Wconversion, $(CFLAGS)) PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \ -Igcc-plugins -fPIC -fno-rtti -O2 -Wall +else ifeq ($(ARCH),aarch64) else $(error Unsupported architecture ${ARCH}, check https://github.com/dynup/kpatch/#supported-architectures) endif diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 537ce9325..11a5f9468 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 @@ -214,6 +216,22 @@ static struct rela *toc_rela(const struct rela *rela) (unsigned int)rela->addend); } +#ifdef __aarch64__ +static int kpatch_is_mapping_symbol(struct symbol *sym) +{ + if (sym->name && sym->name[0] == '$' + && sym->type == STT_NOTYPE \ + && sym->bind == STB_LOCAL) + return 1; + return 0; +} +#else +static int kpatch_is_mapping_symbol(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" @@ -563,6 +581,13 @@ static void kpatch_compare_correlated_section(struct section *sec) goto out; } + /* As above but for aarch64 */ + 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; @@ -1027,6 +1052,9 @@ static void kpatch_correlate_symbols(struct list_head *symlist_orig, !strncmp(sym_orig->name, ".LC", 3)) continue; + if (kpatch_is_mapping_symbol(sym_orig)) + continue; + /* group section symbols must have correlated sections */ if (sym_orig->sec && sym_orig->sec->sh.sh_type == SHT_GROUP && @@ -1536,7 +1564,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 || @@ -1568,7 +1596,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 == (long)sym->sec->sh.sh_size && end == (long)sym->sec->sh.sh_size) { @@ -2073,35 +2105,36 @@ static int parainstructions_group_size(struct kpatch_elf *kelf, int offset) return size; } -static int altinstructions_group_size(struct kpatch_elf *kelf, int offset) +static int smp_locks_group_size(struct kpatch_elf *kelf, int offset) +{ + return 4; +} + +static int static_call_sites_group_size(struct kpatch_elf *kelf, int offset) { static int size = 0; char *str; if (!size) { - str = getenv("ALT_STRUCT_SIZE"); + str = getenv("STATIC_CALL_STRUCT_SIZE"); if (!str) - ERROR("ALT_STRUCT_SIZE not set"); + ERROR("STATIC_CALL_STRUCT_SIZE not set"); size = atoi(str); } return size; } - -static int smp_locks_group_size(struct kpatch_elf *kelf, int offset) -{ - return 4; -} - -static int static_call_sites_group_size(struct kpatch_elf *kelf, int offset) +#endif +#if defined(__x86_64__) || defined(__aarch64__) +static int altinstructions_group_size(struct kpatch_elf *kelf, int offset) { static int size = 0; char *str; if (!size) { - str = getenv("STATIC_CALL_STRUCT_SIZE"); + str = getenv("ALT_STRUCT_SIZE"); if (!str) - ERROR("STATIC_CALL_STRUCT_SIZE not set"); + ERROR("ALT_STRUCT_SIZE not set"); size = atoi(str); } @@ -2215,15 +2248,17 @@ static struct special_section special_sections[] = { .name = ".parainstructions", .group_size = parainstructions_group_size, }, - { - .name = ".altinstructions", - .group_size = altinstructions_group_size, - }, { .name = ".static_call_sites", .group_size = static_call_sites_group_size, }, #endif +#if defined(__x86_64__) || defined(__aarch64__) + { + .name = ".altinstructions", + .group_size = altinstructions_group_size, + }, +#endif #ifdef __powerpc64__ { .name = "__ftr_fixup", diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index eedf383d7..254eacb39 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -375,10 +375,57 @@ find_special_section_data_ppc64le() { return } +find_special_section_data_aarch64() { + [[ "$CONFIG_JUMP_LABEL" -eq 0 ]] && AWK_OPTIONS="-vskip_j=1" + [[ "$CONFIG_PRINTK_INDEX" -eq 0 ]] && AWK_OPTIONS="$AWK_OPTIONS -vskip_i=1" + + SPECIAL_VARS="$(readelf -wi "$VMLINUX" | + gawk --non-decimal-data $AWK_OPTIONS ' + BEGIN { a = b = p = e = o = j = s = i = 0 } + + # Set state if name matches + a == 0 && /DW_AT_name.* alt_instr[[:space:]]*$/ {a = 1; next} + b == 0 && /DW_AT_name.* bug_entry[[:space:]]*$/ {b = 1; next} + e == 0 && /DW_AT_name.* exception_table_entry[[:space:]]*$/ {e = 1; next} + j == 0 && /DW_AT_name.* jump_entry[[:space:]]*$/ {j = 1; next} + i == 0 && /DW_AT_name.* pi_entry[[:space:]]*$/ {i = 1; next} + + # Reset state unless this abbrev describes the struct size + a == 1 && !/DW_AT_byte_size/ { a = 0; next } + b == 1 && !/DW_AT_byte_size/ { b = 0; next } + e == 1 && !/DW_AT_byte_size/ { e = 0; next } + j == 1 && !/DW_AT_byte_size/ { j = 0; next } + i == 1 && !/DW_AT_byte_size/ { i = 0; next } + + # Now that we know the size, stop parsing for it + a == 1 {printf("export ALT_STRUCT_SIZE=%d\n", $4); a = 2} + b == 1 {printf("export BUG_STRUCT_SIZE=%d\n", $4); b = 2} + e == 1 {printf("export EX_STRUCT_SIZE=%d\n", $4); e = 2} + j == 1 {printf("export JUMP_STRUCT_SIZE=%d\n", $4); j = 2} + i == 1 {printf("export PRINTK_INDEX_STRUCT_SIZE=%d\n", $4); i = 2} + + # Bail out once we have everything + a == 2 && b == 2 && e == 2 && (j == 2 || skip_j) && (i == 2 || skip_i) {exit}')" + + [[ -n "$SPECIAL_VARS" ]] && eval "$SPECIAL_VARS" + + [[ -z "$ALT_STRUCT_SIZE" ]] && die "can't find special struct alt_instr size" + [[ -z "$BUG_STRUCT_SIZE" ]] && die "can't find special struct bug_entry size" + [[ -z "$EX_STRUCT_SIZE" ]] && die "can't find special struct paravirt_patch_site size" + [[ -z "$JUMP_STRUCT_SIZE" && "$CONFIG_JUMP_LABEL" -ne 0 ]] && die "can't find special struct jump_entry size" + [[ -z "$PRINTK_INDEX_STRUCT_SIZE" && "$CONFIG_PRINTK_INDEX" -ne 0 ]] && die "can't find special struct pi_entry size" + + return + +} + find_special_section_data() { if [[ "$ARCH" = "ppc64le" ]]; then find_special_section_data_ppc64le return + elif [[ "$ARCH" = "aarch64" ]]; then + find_special_section_data_aarch64 + return fi [[ "$CONFIG_PARAVIRT" -eq 0 ]] && AWK_OPTIONS="-vskip_p=1"