enum elf_reloc_type_class type;
union
{
- Elf_Internal_Rel rel;
- Elf_Internal_Rela rela;
+ /* We use these as arrays of size int_rels_per_ext_rel. */
+ Elf_Internal_Rel rel[1];
+ Elf_Internal_Rela rela[1];
} u;
};
return 1;
if (relativea > relativeb)
return -1;
- if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+ if (ELF_R_SYM (a->u.rel->r_info) < ELF_R_SYM (b->u.rel->r_info))
return -1;
- if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+ if (ELF_R_SYM (a->u.rel->r_info) > ELF_R_SYM (b->u.rel->r_info))
return 1;
- if (a->u.rel.r_offset < b->u.rel.r_offset)
+ if (a->u.rel->r_offset < b->u.rel->r_offset)
return -1;
- if (a->u.rel.r_offset > b->u.rel.r_offset)
+ if (a->u.rel->r_offset > b->u.rel->r_offset)
return 1;
return 0;
}
return -1;
if (copya > copyb)
return 1;
- if (a->u.rel.r_offset < b->u.rel.r_offset)
+ if (a->u.rel->r_offset < b->u.rel->r_offset)
return -1;
- if (a->u.rel.r_offset > b->u.rel.r_offset)
+ if (a->u.rel->r_offset > b->u.rel->r_offset)
return 1;
return 0;
}
size_t i, j, ret;
struct elf_link_sort_rela *rela;
struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ int i2e = bed->s->int_rels_per_ext_rel;
reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
if (reldyn == NULL || reldyn->_raw_size == 0)
if (size != reldyn->_raw_size)
return 0;
- rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count);
+ /* We waste some memory here when N = i2e is greater than 1, since
+ we allocate space for N * sizeof (*rela) where sizeof (*rela) +
+ (N - 1) * sizeof (Elf_Internal_Rel/Rela) would do. Also, we use
+ rela[k] only when k is a multiple of N, and then we index the
+ array within the union, such that rela[k].u.rel[i], i < N, is the
+ (i+1)th internal relocation corresponding to the (k/N)th external
+ relocation. This is done such that the relocation swap-in and
+ swap-out functions can gen pointers to arrays of internal
+ relocations that form a single external relocation.
+
+ If C permitted arrays of structures with dynamic sizes, we could
+ do better, but trying to avoid wasting space at the end of the
+ chunk from rela[k] to rela[k+N-1] would require us to allocate a
+ separate array of pointers and since most ports have N == 1, this
+ would be more wasteful. */
+ rela = (struct elf_link_sort_rela *) bfd_zmalloc
+ (sizeof (*rela) * count * i2e);
if (rela == NULL)
{
(*info->callbacks->warning)
erel = (Elf_External_Rel *) o->contents;
erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
- s = rela + o->output_offset / sizeof (Elf_External_Rel);
- for (; erel < erelend; erel++, s++)
+ s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+ for (; erel < erelend; erel++, s += i2e)
{
if (bed->s->swap_reloc_in)
- (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+ (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel,
+ s->u.rel);
else
- elf_swap_reloc_in (abfd, erel, &s->u.rel);
+ elf_swap_reloc_in (abfd, erel, s->u.rel);
- s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+ s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
}
}
else
erela = (Elf_External_Rela *) o->contents;
erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
- s = rela + o->output_offset / sizeof (Elf_External_Rela);
- for (; erela < erelaend; erela++, s++)
+ s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+ for (; erela < erelaend; erela++, s += i2e)
{
if (bed->s->swap_reloca_in)
(*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela,
- &s->u.rela);
+ s->u.rela);
else
- elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+ elf_swap_reloca_in (dynobj, erela, s->u.rela);
- s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+ s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
}
}
}
- qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1);
- for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++)
+ qsort (rela, (size_t) count, sizeof (*rela) * i2e, elf_link_sort_cmp1);
+ for (ret = 0; ret < count * i2e && rela[ret].type == reloc_class_relative;
+ ret += i2e)
;
- for (i = ret, j = ret; i < count; i++)
+ for (i = ret, j = ret; i < count * i2e; i += i2e)
{
- if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+ if (ELF_R_SYM (rela[i].u.rel->r_info)
+ != ELF_R_SYM (rela[j].u.rel->r_info))
j = i;
- rela[i].offset = rela[j].u.rel.r_offset;
+ rela[i].offset = rela[j].u.rel->r_offset;
}
- qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2);
+ ret /= i2e;
+ qsort (rela + ret, (size_t) count - ret,
+ sizeof (*rela) * i2e, elf_link_sort_cmp2);
for (o = dynobj->sections; o != NULL; o = o->next)
if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
erel = (Elf_External_Rel *) o->contents;
erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
- s = rela + o->output_offset / sizeof (Elf_External_Rel);
- for (; erel < erelend; erel++, s++)
+ s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+ for (; erel < erelend; erel++, s += i2e)
{
if (bed->s->swap_reloc_out)
- (*bed->s->swap_reloc_out) (abfd, &s->u.rel,
+ (*bed->s->swap_reloc_out) (abfd, s->u.rel,
(bfd_byte *) erel);
else
- elf_swap_reloc_out (abfd, &s->u.rel, erel);
+ elf_swap_reloc_out (abfd, s->u.rel, erel);
}
}
else
erela = (Elf_External_Rela *) o->contents;
erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
- s = rela + o->output_offset / sizeof (Elf_External_Rela);
- for (; erela < erelaend; erela++, s++)
+ s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+ for (; erela < erelaend; erela++, s += i2e)
{
if (bed->s->swap_reloca_out)
- (*bed->s->swap_reloca_out) (dynobj, &s->u.rela,
+ (*bed->s->swap_reloca_out) (dynobj, s->u.rela,
(bfd_byte *) erela);
else
- elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+ elf_swap_reloca_out (dynobj, s->u.rela, erela);
}
}
}