summaryrefslogtreecommitdiffstats
path: root/trunk/src/get.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/get.c')
-rw-r--r--trunk/src/get.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/trunk/src/get.c b/trunk/src/get.c
index 05e0b54..fe32deb 100644
--- a/trunk/src/get.c
+++ b/trunk/src/get.c
@@ -241,7 +241,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
do
{
unsigned long long symstart, symoff, valstart[3], value[3];
- int reloc_class, len, type = 1;
+ int reloc_class, len, type = 1, ifunc = 0;
char *symname;
r = strchr (buffer, '\n');
@@ -276,7 +276,13 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
reloc_class = dso->arch->reloc_class (reloc_class);
else
{
- if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
+ if (reloc_class & 8)
+ {
+ reloc_class = ((reloc_class & ~8)
+ | dso->arch->rtype_class_valid);
+ ifunc = 1;
+ }
+ else if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
reloc_class |= RTYPE_CLASS_VALID;
else
reloc_class |= dso->arch->rtype_class_valid;
@@ -287,7 +293,8 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
ent = NULL;
tls = NULL;
if (symstart == deps[0].start
- || (reloc_class == RTYPE_CLASS_TLS && info->conflicts))
+ || ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts))
{
for (i = 0; i < ndeps; i++)
if (deps[i].start == valstart[0])
@@ -316,7 +323,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
}
}
- if (symstart == deps[0].start)
+ if (symstart == deps[0].start && (!ifunc || info->conflicts == NULL))
{
/* Only interested in relocations from the current object. */
if (symoff < info->symtab_start || symoff >= info->symtab_end)
@@ -326,7 +333,8 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- if (ent == info->ent && reloc_class != RTYPE_CLASS_TLS)
+ if (ent == info->ent
+ && reloc_class != RTYPE_CLASS_TLS)
value[0] = adjust_old_to_new (info->dso, value[0]);
s = &info->symbols[(symoff - info->symtab_start)
@@ -371,13 +379,14 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
s->next = NULL;
}
}
- else if (reloc_class == RTYPE_CLASS_TLS && info->conflicts)
+ else if ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts)
{
struct prelink_conflict *conflict;
int symowner;
size_t idx;
- for (symowner = 1; symowner < ndeps; symowner++)
+ for (symowner = 0; symowner < ndeps; symowner++)
if (deps[symowner].start == symstart)
break;
if (symowner == ndeps)
@@ -395,8 +404,12 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
if (conflict->symoff == symoff
&& conflict->reloc_class == reloc_class)
{
- if (conflict->lookup.tls != tls
- || conflict->conflict.tls != tls
+ if ((reloc_class != RTYPE_CLASS_TLS
+ && (conflict->lookup.ent != ent
+ || conflict->conflict.ent != ent))
+ || (reloc_class == RTYPE_CLASS_TLS
+ && (conflict->lookup.tls != tls
+ || conflict->conflict.tls != tls))
|| conflict->lookupval != value[0]
|| conflict->conflictval != value[0])
{
@@ -418,13 +431,22 @@ 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;
+ if (reloc_class != RTYPE_CLASS_TLS)
+ {
+ conflict->lookup.ent = ent;
+ conflict->conflict.ent = ent;
+ }
+ else
+ {
+ conflict->lookup.tls = tls;
+ conflict->conflict.tls = tls;
+ }
conflict->lookupval = value[0];
conflict->conflictval = value[0];
conflict->symoff = symoff;
conflict->reloc_class = reloc_class;
conflict->used = 0;
+ conflict->ifunc = ifunc;
if (++info->conflicts[symowner].count == 16)
conflict_hash_init (&info->conflicts[symowner]);
}
@@ -458,7 +480,13 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
reloc_class = dso->arch->reloc_class (reloc_class);
else
{
- if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
+ if (reloc_class & 8)
+ {
+ reloc_class = ((reloc_class & ~8)
+ | dso->arch->rtype_class_valid);
+ ifunc = 1;
+ }
+ else if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
reloc_class |= RTYPE_CLASS_VALID;
else
reloc_class |= dso->arch->rtype_class_valid;
@@ -571,6 +599,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
conflict->symoff = symoff;
conflict->reloc_class = reloc_class;
conflict->used = 0;
+ conflict->ifunc = ifunc;
if (++info->conflicts[symowner].count == 16)
conflict_hash_init (&info->conflicts[symowner]);
}