create-diff-object: support ppc64le relative jump labels

RHEL-9 integration tests revealed that the kernel now makes use of
R_PPC64_REL64 relocations in the jump table, but need_dynrela() contains
code to specifically skip any R_PPC64_REL64 type when determining if a
relocation should be turned into dynrela.

Kamalesh Babulal explains:

  I tried digging a little deeper and the upstream Kernel commit
  b0b3b2c78ec (powerpc: Switch to relative jump labels) in v5.13,
  introduced the change of generating relocation entries of type
  R_PPC64_REL64, instead of absolute relocation type R_PPC64_ADDR64:

  Relocation section '.rela__jump_table' at offset 0x1a87d8 contains 303 entries:
      Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
  ...
  00000000000003c8  000007910000002c R_PPC64_REL64          0000000000000000 __tracepoint_netif_receive_skb + 8
  ...

Relax the existing check in need_dynrela() for .rela__jump_table
R_PPC64_REL64 relocations in case we need dynrelas for them.

Fixes: #1212
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
This commit is contained in:
Joe Lawrence 2021-09-28 12:35:17 -04:00
parent cc5200fbf8
commit 4f51ee7fa3
1 changed files with 7 additions and 3 deletions

View File

@ -2993,7 +2993,7 @@ static int function_ptr_rela(const struct rela *rela)
rela->type == R_PPC64_TOC16_LO_DS));
}
static bool need_dynrela(struct lookup_table *table, const struct rela *rela)
static bool need_dynrela(struct lookup_table *table, struct section *sec, const struct rela *rela)
{
struct lookup_result symbol;
@ -3002,7 +3002,11 @@ static bool need_dynrela(struct lookup_table *table, const struct rela *rela)
* should never be converted to dynrelas.
*/
if (rela->type == R_PPC64_REL16_HA || rela->type == R_PPC64_REL16_LO ||
rela->type == R_PPC64_REL64 || rela->type == R_PPC64_ENTRY)
rela->type == R_PPC64_ENTRY)
return false;
/* v5.13+ kernels use relative jump labels */
if (rela->type == R_PPC64_REL64 && strcmp(sec->name, ".rela__jump_table"))
return false;
/*
@ -3192,7 +3196,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf,
* internal symbol function pointer check which is done
* via .toc indirection in need_dynrela().
*/
if (need_dynrela(table, rela))
if (need_dynrela(table, sec, rela))
toc_rela(rela)->need_dynrela = 1;
}
}