if (skip)
goto nondefault;
- if (hi->def_regular)
+ if (hi->def_regular || ELF_COMMON_DEF_P (hi))
{
/* If the undecorated symbol will have a version added by a
script different to H, then don't indirect to/from the
/* We only need version numbers for symbols defined in regular
objects. */
- if (!h->def_regular)
+ if (!h->def_regular && !ELF_COMMON_DEF_P (h))
{
/* Hide symbols defined in discarded input sections. */
if ((h->root.type == bfd_link_hash_defined
return FALSE;
}
-/* Sort symbol by value, section, and size. */
+/* Sort symbol by value, section, size, and type. */
static int
elf_sort_symbol (const void *arg1, const void *arg2)
{
const struct elf_link_hash_entry *h1;
const struct elf_link_hash_entry *h2;
bfd_signed_vma vdiff;
+ int sdiff;
+ const char *n1;
+ const char *n2;
h1 = *(const struct elf_link_hash_entry **) arg1;
h2 = *(const struct elf_link_hash_entry **) arg2;
vdiff = h1->root.u.def.value - h2->root.u.def.value;
if (vdiff != 0)
return vdiff > 0 ? 1 : -1;
- else
- {
- int sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id;
- if (sdiff != 0)
- return sdiff > 0 ? 1 : -1;
- }
+
+ sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id;
+ if (sdiff != 0)
+ return sdiff;
+
+ /* Sort so that sized symbols are selected over zero size symbols. */
vdiff = h1->size - h2->size;
- return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1;
+ if (vdiff != 0)
+ return vdiff > 0 ? 1 : -1;
+
+ /* Sort so that STT_OBJECT is selected over STT_NOTYPE. */
+ if (h1->type != h2->type)
+ return h1->type - h2->type;
+
+ /* If symbols are properly sized and typed, and multiple strong
+ aliases are not defined in a shared library by the user we
+ shouldn't get here. Unfortunately linker script symbols like
+ __bss_start sometimes match a user symbol defined at the start of
+ .bss without proper size and type. We'd like to preference the
+ user symbol over reserved system symbols. Sort on leading
+ underscores. */
+ n1 = h1->root.root.string;
+ n2 = h2->root.root.string;
+ while (*n1 == *n2)
+ {
+ if (*n1 == 0)
+ break;
+ ++n1;
+ ++n2;
+ }
+ if (*n1 == '_')
+ return -1;
+ if (*n2 == '_')
+ return 1;
+
+ /* Final sort on name selects user symbols like '_u' over reserved
+ system symbols like '_Z' and also will avoid qsort instability. */
+ return *n1 - *n2;
}
/* This function is used to adjust offsets into .dynstr for
defined symbol, search time for N weak defined symbols will be
O(N^2). Binary search will cut it down to O(NlogN). */
amt = extsymcount;
- amt *= sizeof (struct elf_link_hash_entry *);
- sorted_sym_hash = (struct elf_link_hash_entry **) bfd_malloc (amt);
+ amt *= sizeof (*sorted_sym_hash);
+ sorted_sym_hash = bfd_malloc (amt);
if (sorted_sym_hash == NULL)
goto error_return;
sym_hash = sorted_sym_hash;
}
}
- qsort (sorted_sym_hash, sym_count,
- sizeof (struct elf_link_hash_entry *),
+ qsort (sorted_sym_hash, sym_count, sizeof (*sorted_sym_hash),
elf_sort_symbol);
while (weaks != NULL)
{
Elf_Internal_Sym *isym;
struct elf_symbuf_symbol *ssym;
+ void *p;
} u;
const char *name;
};
const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
- return s1->st_shndx - s2->st_shndx;
+ if (s1->st_shndx != s2->st_shndx)
+ return s1->st_shndx > s2->st_shndx ? 1 : -1;
+ /* Final sort by the address of the sym in the symbuf ensures
+ a stable sort. */
+ if (s1 != s2)
+ return s1 > s2 ? 1 : -1;
+ return 0;
}
static int
{
const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
- return strcmp (s1->name, s2->name);
+ int ret = strcmp (s1->name, s2->name);
+ if (ret != 0)
+ return ret;
+ if (s1->u.p != s2->u.p)
+ return s1->u.p > s2->u.p ? 1 : -1;
+ return 0;
}
static struct elf_symbuf_head *
goto done;
if (!info->reduce_memory_overheads)
- elf_tdata (bfd1)->symbuf = ssymbuf1
- = elf_create_symbuf (symcount1, isymbuf1);
+ {
+ ssymbuf1 = elf_create_symbuf (symcount1, isymbuf1);
+ elf_tdata (bfd1)->symbuf = ssymbuf1;
+ }
}
if (ssymbuf1 == NULL || ssymbuf2 == NULL)
goto done;
if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
- elf_tdata (bfd2)->symbuf = ssymbuf2
- = elf_create_symbuf (symcount2, isymbuf2);
+ {
+ ssymbuf2 = elf_create_symbuf (symcount2, isymbuf2);
+ elf_tdata (bfd2)->symbuf = ssymbuf2;
+ }
}
if (ssymbuf1 != NULL && ssymbuf2 != NULL)
{
if (strncmp (".end", name + len, 4) == 0)
{
- *result = curr->vma + curr->size / bfd_octets_per_byte (abfd);
+ *result = (curr->vma
+ + curr->size / bfd_octets_per_byte (abfd, curr));
return TRUE;
}
bfd_reloc_status_type
bfd_elf_perform_complex_relocation (bfd *input_bfd,
- asection *input_section ATTRIBUTE_UNUSED,
+ asection *input_section,
bfd_byte *contents,
Elf_Internal_Rela *rel,
bfd_vma relocation)
bfd_vma shift, x, mask;
unsigned long start, oplen, len, wordsz, chunksz, lsb0_p, signed_p, trunc_p;
bfd_reloc_status_type r;
+ bfd_size_type octets;
/* Perform this reloc, since it is complex.
(this is not to say that it necessarily refers to a complex
else
shift = (8 * wordsz) - (start + len);
- x = get_value (wordsz, chunksz, input_bfd,
- contents + rel->r_offset * bfd_octets_per_byte (input_bfd));
+ octets = rel->r_offset * bfd_octets_per_byte (input_bfd, input_section);
+ x = get_value (wordsz, chunksz, input_bfd, contents + octets);
#ifdef DEBUG
printf ("Doing complex reloc: "
(unsigned long) relocation, (unsigned long) (mask << shift),
(unsigned long) ((relocation & mask) << shift), (unsigned long) x);
#endif
- put_value (wordsz, chunksz, input_bfd, x,
- contents + rel->r_offset * bfd_octets_per_byte (input_bfd));
+ put_value (wordsz, chunksz, input_bfd, x, contents + octets);
return r;
}
Elf_Internal_Rela rela[1];
};
+/* qsort stability here and for cmp2 is only an issue if multiple
+ dynamic relocations are emitted at the same address. But targets
+ that apply a series of dynamic relocations each operating on the
+ result of the prior relocation can't use -z combreloc as
+ implemented anyway. Such schemes tend to be broken by sorting on
+ symbol index. That leaves dynamic NONE relocs as the only other
+ case where ld might emit multiple relocs at the same address, and
+ those are only emitted due to target bugs. */
+
static int
elf_link_sort_cmp1 (const void *A, const void *B)
{
struct elf_link_sort_rela *sq;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
int i2e = bed->s->int_rels_per_ext_rel;
- unsigned int opb = bfd_octets_per_byte (abfd);
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *);
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
struct bfd_link_order *lo;
Elf_Internal_Versym iversym;
Elf_External_Versym *eversym;
- if (!h->def_regular)
+ if (!h->def_regular && !ELF_COMMON_DEF_P (h))
{
if (h->verinfo.verdef == NULL
|| (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd)
file_ptr offset = (file_ptr) o->output_offset;
bfd_size_type todo = o->size;
- offset *= bfd_octets_per_byte (output_bfd);
+ offset *= bfd_octets_per_byte (output_bfd, o);
if ((o->flags & SEC_ELF_REVERSE_COPY))
{
bfd_byte *buf;
bfd_boolean ok;
const char *sym_name;
+ bfd_size_type octets;
size = (bfd_size_type) bfd_get_reloc_size (howto);
buf = (bfd_byte *) bfd_zmalloc (size);
break;
}
+ octets = link_order->offset * bfd_octets_per_byte (output_bfd,
+ output_section);
ok = bfd_set_section_contents (output_bfd, output_section, buf,
- link_order->offset
- * bfd_octets_per_byte (output_bfd),
- size);
+ octets, size);
free (buf);
if (! ok)
return FALSE;
}
-/* Get the output vma of the section pointed to by the sh_link field. */
-
-static bfd_vma
-elf_get_linked_section_vma (struct bfd_link_order *p)
-{
- Elf_Internal_Shdr **elf_shdrp;
- asection *s;
- int elfsec;
-
- s = p->u.indirect.section;
- elf_shdrp = elf_elfsections (s->owner);
- elfsec = _bfd_elf_section_from_bfd_section (s->owner, s);
- elfsec = elf_shdrp[elfsec]->sh_link;
- /* PR 290:
- The Intel C compiler generates SHT_IA_64_UNWIND with
- SHF_LINK_ORDER. But it doesn't set the sh_link or
- sh_info fields. Hence we could get the situation
- where elfsec is 0. */
- if (elfsec == 0)
- {
- const struct elf_backend_data *bed
- = get_elf_backend_data (s->owner);
- if (bed->link_order_error_handler)
- bed->link_order_error_handler
- /* xgettext:c-format */
- (_("%pB: warning: sh_link not set for section `%pA'"), s->owner, s);
- return 0;
- }
- else
- {
- s = elf_shdrp[elfsec]->bfd_section;
- return s->output_section->vma + s->output_offset;
- }
-}
-
-
/* Compare two sections based on the locations of the sections they are
linked to. Used by elf_fixup_link_order. */
static int
-compare_link_order (const void * a, const void * b)
+compare_link_order (const void *a, const void *b)
{
- bfd_vma apos;
- bfd_vma bpos;
+ const struct bfd_link_order *alo = *(const struct bfd_link_order **) a;
+ const struct bfd_link_order *blo = *(const struct bfd_link_order **) b;
+ asection *asec = elf_linked_to_section (alo->u.indirect.section);
+ asection *bsec = elf_linked_to_section (blo->u.indirect.section);
+ bfd_vma apos = asec->output_section->lma + asec->output_offset;
+ bfd_vma bpos = bsec->output_section->lma + bsec->output_offset;
+
+ if (apos < bpos)
+ return -1;
+ if (apos > bpos)
+ return 1;
+
+ /* The only way we should get matching LMAs is when the first of two
+ sections has zero size. */
+ if (asec->size < bsec->size)
+ return -1;
+ if (asec->size > bsec->size)
+ return 1;
- apos = elf_get_linked_section_vma (*(struct bfd_link_order **)a);
- bpos = elf_get_linked_section_vma (*(struct bfd_link_order **)b);
+ /* If they are both zero size then they almost certainly have the same
+ VMA and thus are not ordered with respect to each other. Test VMA
+ anyway, and fall back to id to make the result reproducible across
+ qsort implementations. */
+ apos = asec->output_section->vma + asec->output_offset;
+ bpos = bsec->output_section->vma + bsec->output_offset;
if (apos < bpos)
return -1;
- return apos > bpos;
+ if (apos > bpos)
+ return 1;
+
+ return asec->id - bsec->id;
}
static bfd_boolean
elf_fixup_link_order (bfd *abfd, asection *o)
{
- int seen_linkorder;
- int seen_other;
- int n;
+ size_t seen_linkorder;
+ size_t seen_other;
+ size_t n;
struct bfd_link_order *p;
bfd *sub;
- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- unsigned elfsec;
struct bfd_link_order **sections;
asection *s, *other_sec, *linkorder_sec;
bfd_vma offset;
sub = s->owner;
if ((s->flags & SEC_LINKER_CREATED) == 0
&& bfd_get_flavour (sub) == bfd_target_elf_flavour
- && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass
- && (elfsec = _bfd_elf_section_from_bfd_section (sub, s))
- && elfsec < elf_numsections (sub)
- && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER
- && elf_elfsections (sub)[elfsec]->sh_link < elf_numsections (sub))
+ && elf_section_data (s) != NULL
+ && elf_linked_to_section (s) != NULL)
{
seen_linkorder++;
linkorder_sec = s;
if (!seen_linkorder)
return TRUE;
- sections = (struct bfd_link_order **)
- bfd_malloc (seen_linkorder * sizeof (struct bfd_link_order *));
+ sections = bfd_malloc (seen_linkorder * sizeof (*sections));
if (sections == NULL)
return FALSE;
- seen_linkorder = 0;
+ seen_linkorder = 0;
for (p = o->map_head.link_order; p != NULL; p = p->next)
- {
- sections[seen_linkorder++] = p;
- }
+ sections[seen_linkorder++] = p;
+
/* Sort the input sections in the order of their linked section. */
- qsort (sections, seen_linkorder, sizeof (struct bfd_link_order *),
- compare_link_order);
+ qsort (sections, seen_linkorder, sizeof (*sections), compare_link_order);
/* Change the offsets of the sections. */
offset = 0;
for (n = 0; n < seen_linkorder; n++)
{
+ bfd_vma mask;
s = sections[n]->u.indirect.section;
- offset &= ~(bfd_vma) 0 << s->alignment_power;
- s->output_offset = offset / bfd_octets_per_byte (abfd);
+ mask = ~(bfd_vma) 0 << s->alignment_power;
+ offset = (offset + ~mask) & mask;
+ s->output_offset = offset / bfd_octets_per_byte (abfd, s);
sections[n]->offset = offset;
offset += sections[n]->size;
}
goto error_return;
}
+ /* _bfd_elf_compute_section_file_positions makes temporary use
+ of target_index. Reset it. */
+ o->target_index = 0;
+
/* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
to count upwards while actually outputting the relocations. */
esdo->rel.count = 0;
continue;
if (strcmp (o->name, ".dynstr") != 0)
{
- if (! bfd_set_section_contents (abfd, o->output_section,
- o->contents,
- (file_ptr) o->output_offset
- * bfd_octets_per_byte (abfd),
- o->size))
+ bfd_size_type octets = ((file_ptr) o->output_offset
+ * bfd_octets_per_byte (abfd, o));
+ if (!bfd_set_section_contents (abfd, o->output_section,
+ o->contents, octets, o->size))
goto error_return;
}
else