From c61cb6776a3255e9f6578db89a1f1fcef3bb0e0a Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Tue, 13 Mar 2018 13:39:31 +0530 Subject: [PATCH] create-diff-object: Add support for .toc constants .toc section entries are mostly place holder for relocation entries, specified in .rela.toc section. Sometimes, .toc section may have constants as entries. These constants are not reference to any symbols, but plain instructions mostly due to some arthimetics in the functions referring them. They are referred by the functions like normal .toc entries, these entries can not be resolved to any symbols. This patch creates a list of constants if available for .toc sections and compares them in rela_equal() to ensure their is no mismatch in the generated constants for original and patched .o files. Cc: Josh Poimboeuf Signed-off-by: Kamalesh Babulal --- kpatch-build/create-diff-object.c | 52 ++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 49d0aa9..2af7454 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -245,6 +245,7 @@ static int rela_equal(struct rela *rela1, struct rela *rela2) #ifdef __powerpc__ struct section *toc_relasec1, *toc_relasec2; struct rela *r_toc_relasec1, *r_toc_relasec2; + unsigned long toc_data1, toc_data2; #endif if (rela1->type != rela2->type || @@ -288,16 +289,59 @@ static int rela_equal(struct rela *rela1, struct rela *rela2) ERROR("cannot find .rela.toc"); r_toc_relasec1 = find_rela_by_offset(toc_relasec1, rela1->addend); - if (!r_toc_relasec1) - ERROR(".toc entry not found %s + %x", rela1->sym->name, rela1->addend); + if (!r_toc_relasec1) { + /* + * .toc section entries are mostly place holder for relocation entries, specified + * in .rela.toc section. Sometimes, .toc section may have constants as entries. + * These constants are not reference to any symbols, but plain instructions mostly + * due to some arithmetics in the functions referring them. + * + * They are referred by the functions like normal .toc entries, these entries can + * not be resolved to any symbols. + * + * Disassembly of section .toc: + * + * 0000000000000000 <.toc>: + * ... + * 148: R_PPC64_ADDR64 .data.capacity_margin + * 150: 0b d7 a3 70 andi. r3,r5,55051 + * 154: 3d 0a d7 a3 lhz r30,2621(r23) + * 158: R_PPC64_ADDR64 sched_max_numa_distance + * + * Relocation section '.rela.toc' at offset 0xadac0 contains 160 entries: + * Offset Info Type Symbol's Value Symbol's Name + Addend + * ... + * 0000000000000148 0000009100000026 R_PPC64_ADDR64 0000000000000000 .data.capacity_margin + 0 + * 0000000000000158 000001a500000026 R_PPC64_ADDR64 0000000000000000 sched_max_numa_distance + 0 + * + * Relocation section '.rela.text.select_task_rq_fair' at offset 0x90e98 contains 37 entries: + * Offset Info Type Symbol's Value Symbol's Name + Addend + * ... + * 0000000000000498 000000c90000000a R_PPC64_REL24 0000000000000000 __update_load_avg_blocked_se.isra.0 + 0 + * 00000000000004a0 0000008800000032 R_PPC64_TOC16_HA 0000000000000000 .toc + 148 + * 00000000000004ac 0000008800000040 R_PPC64_TOC16_LO_DS 0000000000000000 .toc + 148 + * 0000000000000514 0000008800000032 R_PPC64_TOC16_HA 0000000000000000 .toc + 150 + * 000000000000051c 0000008800000040 R_PPC64_TOC16_LO_DS 0000000000000000 .toc + 150 + * 00000000000005e0 000001870000000a R_PPC64_REL24 0000000000000000 __bitmap_intersects + 0 + */ + memcpy(&toc_data1, rela1->sym->sec->data->d_buf + rela1->addend, sizeof(toc_data1)); + if (!toc_data1) + ERROR(".toc entry not found %s + %x", rela1->sym->name, rela1->addend); + } toc_relasec2 = rela2->sym->sec->rela; if (!toc_relasec2) ERROR("cannot find .rela.toc"); r_toc_relasec2 = find_rela_by_offset(toc_relasec2, rela2->addend); - if (!r_toc_relasec2) - ERROR(".toc entry not found %s + %x", rela2->sym->name, rela2->addend); + if (!r_toc_relasec2) { + memcpy(&toc_data2, rela2->sym->sec->data->d_buf + rela2->addend, sizeof(toc_data2)); + if (!toc_data2) + ERROR(".toc entry not found %s + %x", rela2->sym->name, rela2->addend); + } + + if (!r_toc_relasec1 && !r_toc_relasec2) + return toc_data1 == toc_data2; if (r_toc_relasec1->string) return r_toc_relasec2->string &&