From b5745d7ea68ad13c98c7180d4b6b69e43ef33d55 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 5 Jul 2019 11:45:50 -0500 Subject: [PATCH] Add support for R_X86_64_PLT32 Starting with binutils 2.31, the Linux kernel may have R_X86_64_PLT32 relocations. Make sure we support them. This should be as simple as treating R_X86_64_PLT32 exactly like R_X86_64_PC32 everywhere. For more details see upstream commit torvalds/linux@b21ebf2. This also fixes the following issue seen on Fedora 29: ``` $ kpatch-build/kpatch-build -t vmlinux ./test/integration/fedora-27/convert-global-local.patch Using cache at /home/jpoimboe/.kpatch/src Testing patch file(s) Reading special section data Building original source Building patched source Extracting new and modified ELF sections ERROR: slub.o: 1 function(s) can not be patched slub.o: function __kmalloc has no fentry/mcount call, unable to patch /home/jpoimboe/git/kpatch/kpatch-build/create-diff-object: unreconcilable difference ERROR: 1 error(s) encountered. Check /home/jpoimboe/.kpatch/build.log for more details. ``` Fixes #975. Signed-off-by: Josh Poimboeuf --- kmod/core/core.c | 1 + kpatch-build/create-diff-object.c | 3 ++- kpatch-build/kpatch-elf.c | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/kmod/core/core.c b/kmod/core/core.c index a91d417..4d60d79 100644 --- a/kmod/core/core.c +++ b/kmod/core/core.c @@ -700,6 +700,7 @@ static int kpatch_write_relocations(struct kpatch_module *kpmod, case R_X86_64_NONE: continue; case R_X86_64_PC32: + case R_X86_64_PLT32: loc = dynrela->dest; val = (u32)(dynrela->src + dynrela->addend - dynrela->dest); diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 61fc571..3b366fe 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1288,7 +1288,8 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) #ifdef __powerpc64__ add_off = 0; #else - if (rela->type == R_X86_64_PC32) { + if (rela->type == R_X86_64_PC32 || + rela->type == R_X86_64_PLT32) { struct insn insn; rela_insn(sec, rela, &insn); add_off = (long)insn.next_byte - diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 7f90e36..848a715 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -332,7 +332,9 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) #else rela = list_first_entry(&sym->sec->rela->relas, struct rela, list); - if ((rela->type != R_X86_64_NONE && rela->type != R_X86_64_PC32) || + if ((rela->type != R_X86_64_NONE && + rela->type != R_X86_64_PC32 && + rela->type != R_X86_64_PLT32) || strcmp(rela->sym->name, "__fentry__")) continue;