diff options
-rw-r--r-- | trunk/ChangeLog | 7 | ||||
-rw-r--r-- | trunk/src/cxx.c | 92 | ||||
-rw-r--r-- | trunk/src/get.c | 2 | ||||
-rw-r--r-- | trunk/src/prelink.c | 60 | ||||
-rw-r--r-- | trunk/src/prelink.h | 2 |
5 files changed, 110 insertions, 53 deletions
diff --git a/trunk/ChangeLog b/trunk/ChangeLog index 3c5f337..2bb9e03 100644 --- a/trunk/ChangeLog +++ b/trunk/ChangeLog @@ -1,5 +1,12 @@ 2007-10-09 Jakub Jelinek <jakub@redhat.com> + * src/prelink.h (struct prelink_conflict): Add next2 field. + (struct prelink_conflicts): Add hash2 field. + * src/get.c (prelink_record_relocations): Clear next2 fields. + * src/prelink.c (free_info): Also free hash2 table. + * src/cxx.c (remove_redundant_cxx_conflicts): Populate hash2 + if not populated yet, use it to speed up pltref checking. + * src/prelink.h (struct prelink_conflicts): New type. (struct prelink_info): Change type of conflicts and curconflicts fields to struct prelink_conflicts *. diff --git a/trunk/src/cxx.c b/trunk/src/cxx.c index 541ae4b..0268fc2 100644 --- a/trunk/src/cxx.c +++ b/trunk/src/cxx.c @@ -529,7 +529,7 @@ check_pltref: if (sym.st_shndx == SHN_UNDEF && sym.st_value) { struct prelink_symbol *s; - size_t maxidx = 1, l; + size_t maxidx, l; if (verbose > 4) error (0, 0, "Possible C++ conflict removal due to reference to binary's .plt at %s:%s+%d", @@ -537,36 +537,78 @@ check_pltref: (int) (info->conflict_rela[i].r_offset - fcs1.sym.st_value)); - if (info->conflicts[fcs1.n].hash - != &info->conflicts[fcs1.n].first) - maxidx = 251; for (s = &info->symbols[ndx]; s; s = s->next) if (s->reloc_class == RTYPE_CLASS_PLT) - { - for (l = 0; l < maxidx; l++) - for (conflict = info->conflicts[fcs1.n].hash[l]; - conflict; conflict = conflict->next) + break; + + if (s == NULL) + break; + + maxidx = 1; + if (info->conflicts[fcs1.n].hash + != &info->conflicts[fcs1.n].first) + { + if (info->conflicts[fcs1.n].hash2 == NULL) + { + info->conflicts[fcs1.n].hash2 + = calloc (sizeof (struct prelink_conflict *), 251); + if (info->conflicts[fcs1.n].hash2 != NULL) + { + for (l = 0; l < 251; l++) + for (conflict = info->conflicts[fcs1.n].hash[l]; + conflict; conflict = conflict->next) + if (conflict->reloc_class == RTYPE_CLASS_VALID + && conflict->conflict.ent) + { + size_t ccidx + = (conflict->lookup.ent->base + + conflict->lookupval) % 251; + conflict->next2 + = info->conflicts[fcs1.n].hash2[ccidx]; + info->conflicts[fcs1.n].hash2[ccidx] + = conflict; + } + } + } + if (info->conflicts[fcs1.n].hash2 != NULL) + { + size_t ccidx = info->conflict_rela[i].r_addend % 251; + for (conflict = info->conflicts[fcs1.n].hash2[ccidx]; + conflict; conflict = conflict->next2) if (conflict->lookup.ent->base + conflict->lookupval == info->conflict_rela[i].r_addend - && conflict->conflict.ent && (conflict->conflict.ent->base + conflict->conflictval - == s->u.ent->base + s->value) - && conflict->reloc_class == RTYPE_CLASS_VALID) - { - if (verbose > 3) - error (0, 0, "Removing C++ conflict due to reference to binary's .plt at %s:%s+%d", - fcs1.dso->filename, name, - (int) (info->conflict_rela[i].r_offset - - fcs1.sym.st_value)); - - info->conflict_rela[i].r_info = - GELF_R_INFO (1, GELF_R_TYPE (info->conflict_rela[i].r_info)); - ++removed; - goto pltref_check_done; - } - break; - } + == s->u.ent->base + s->value)) + goto pltref_remove; + break; + } + maxidx = 251; + } + + for (l = 0; l < maxidx; l++) + for (conflict = info->conflicts[fcs1.n].hash[l]; + conflict; conflict = conflict->next) + if (conflict->lookup.ent->base + conflict->lookupval + == info->conflict_rela[i].r_addend + && conflict->conflict.ent + && (conflict->conflict.ent->base + + conflict->conflictval == s->u.ent->base + s->value) + && conflict->reloc_class == RTYPE_CLASS_VALID) + { +pltref_remove: + if (verbose > 3) + error (0, 0, "Removing C++ conflict due to reference to binary's .plt at %s:%s+%d", + fcs1.dso->filename, name, + (int) (info->conflict_rela[i].r_offset + - fcs1.sym.st_value)); + + info->conflict_rela[i].r_info = + GELF_R_INFO (1, GELF_R_TYPE (info->conflict_rela[i].r_info)); + ++removed; + goto pltref_check_done; + } + pltref_check_done: break; } diff --git a/trunk/src/get.c b/trunk/src/get.c index 928e57c..cea3309 100644 --- a/trunk/src/get.c +++ b/trunk/src/get.c @@ -411,6 +411,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f, } conflict->next = info->conflicts[symowner].hash[idx]; + conflict->next2 = NULL; info->conflicts[symowner].hash[idx] = conflict; conflict->lookup.tls = tls; conflict->conflict.tls = tls; @@ -543,6 +544,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f, } conflict->next = info->conflicts[symowner].hash[idx]; + conflict->next2 = NULL; info->conflicts[symowner].hash[idx] = conflict; if (reloc_class != RTYPE_CLASS_TLS) { diff --git a/trunk/src/prelink.c b/trunk/src/prelink.c index 9b1998c..0d113b7 100644 --- a/trunk/src/prelink.c +++ b/trunk/src/prelink.c @@ -813,35 +813,39 @@ free_info (struct prelink_info *info) if (info->conflicts) { for (i = 0; i < info->ent->ndepends + 1; ++i) - if (info->conflicts[i].hash == &info->conflicts[i].first) - { - struct prelink_conflict *c = info->conflicts[i].first; - void *f; - - while (c != NULL) - { - f = c; - c = c->next; - free (f); - } - } - else - { - int j; - for (j = 0; j < 251; j++) - { - struct prelink_conflict *c = info->conflicts[i].hash[j]; - void *f; + { + if (info->conflicts[i].hash == &info->conflicts[i].first) + { + struct prelink_conflict *c = info->conflicts[i].first; + void *f; - while (c != NULL) - { - f = c; - c = c->next; - free (f); - } - } - free (info->conflicts[i].hash); - } + while (c != NULL) + { + f = c; + c = c->next; + free (f); + } + } + else + { + int j; + for (j = 0; j < 251; j++) + { + struct prelink_conflict *c = info->conflicts[i].hash[j]; + void *f; + + while (c != NULL) + { + f = c; + c = c->next; + free (f); + } + } + free (info->conflicts[i].hash); + } + if (info->conflicts[i].hash2 != NULL) + free (info->conflicts[i].hash2); + } free (info->conflicts); } if (info->sonames) diff --git a/trunk/src/prelink.h b/trunk/src/prelink.h index 770e345..1661779 100644 --- a/trunk/src/prelink.h +++ b/trunk/src/prelink.h @@ -389,6 +389,7 @@ struct prelink_symbol struct prelink_conflict { struct prelink_conflict *next; + struct prelink_conflict *next2; /* Object which it was relocated to. */ union { @@ -411,6 +412,7 @@ struct prelink_conflicts { struct prelink_conflict *first; struct prelink_conflict **hash; + struct prelink_conflict **hash2; size_t count; }; |