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 <jpoimboe@redhat.com>
Signed-off-by: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
This commit is contained in:
Kamalesh Babulal 2018-03-13 13:39:31 +05:30
parent 07c7200cc9
commit c61cb6776a

View File

@ -245,6 +245,7 @@ static int rela_equal(struct rela *rela1, struct rela *rela2)
#ifdef __powerpc__ #ifdef __powerpc__
struct section *toc_relasec1, *toc_relasec2; struct section *toc_relasec1, *toc_relasec2;
struct rela *r_toc_relasec1, *r_toc_relasec2; struct rela *r_toc_relasec1, *r_toc_relasec2;
unsigned long toc_data1, toc_data2;
#endif #endif
if (rela1->type != rela2->type || if (rela1->type != rela2->type ||
@ -288,16 +289,59 @@ static int rela_equal(struct rela *rela1, struct rela *rela2)
ERROR("cannot find .rela.toc"); ERROR("cannot find .rela.toc");
r_toc_relasec1 = find_rela_by_offset(toc_relasec1, rela1->addend); r_toc_relasec1 = find_rela_by_offset(toc_relasec1, rela1->addend);
if (!r_toc_relasec1) 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); ERROR(".toc entry not found %s + %x", rela1->sym->name, rela1->addend);
}
toc_relasec2 = rela2->sym->sec->rela; toc_relasec2 = rela2->sym->sec->rela;
if (!toc_relasec2) if (!toc_relasec2)
ERROR("cannot find .rela.toc"); ERROR("cannot find .rela.toc");
r_toc_relasec2 = find_rela_by_offset(toc_relasec2, rela2->addend); r_toc_relasec2 = find_rela_by_offset(toc_relasec2, rela2->addend);
if (!r_toc_relasec2) 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); 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) if (r_toc_relasec1->string)
return r_toc_relasec2->string && return r_toc_relasec2->string &&