[kpatch] Fwd: [PATCH] Add support for aarch64

Lei Chen losemyheaven at gmail.com
Tue Jul 23 08:48:41 UTC 2019


From: Lei Chen <lennychen at tencent.com>
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 <lennychen at tencent.com>
---
 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




More information about the kpatch mailing list