Skip to content

Commit

Permalink
kpatch-build: Enable ARM64 support
Browse files Browse the repository at this point in the history
Add the final support required for aarch64 and enable building on that arch.

Signed-off-by: Suraj Jitindar Singh <[email protected]>
  • Loading branch information
Suraj Jitindar Singh committed Nov 3, 2021
1 parent a636944 commit 59e4e35
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Supported Architectures

- [x] x86-64
- [x] ppc64le
- [ ] arm64
- [x] arm64
- [ ] s390

Installation
Expand Down
1 change: 1 addition & 0 deletions kpatch-build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
71 changes: 53 additions & 18 deletions kpatch-build/create-diff-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 &&
Expand Down Expand Up @@ -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 ||
Expand Down Expand Up @@ -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) {

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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",
Expand Down
47 changes: 47 additions & 0 deletions kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 59e4e35

Please sign in to comment.