From 3410fea824b6da85a6abdcb5c4916976afc745ce Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 4 May 2007 14:17:07 +0000 Subject: [PATCH] * elflink.c (elf_link_sort_relocs): If both .rela.dyn and .rel.dyn sections are present examine the indirect sections in an attempt to compute the correct relocation size. If there is any ambiguity, produce an error and refuse to sort. --- bfd/ChangeLog | 7 +++ bfd/elflink.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 159 insertions(+), 19 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 4726c96..f4eec5c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2007-05-04 Nick Clifton + + * elflink.c (elf_link_sort_relocs): If both .rela.dyn and .rel.dyn + sections are present examine the indirect sections in an attempt + to compute the correct relocation size. If there is any + ambiguity, produce an error and refuse to sort. + 2007-05-03 Sandra Loosemore * elf32-arm.c (allocate_dynrelocs): Fix typo in comment. diff --git a/bfd/elflink.c b/bfd/elflink.c index cc035fb..0e1dc6e 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -7220,7 +7220,9 @@ elf_link_sort_cmp2 (const void *A, const void *B) static size_t elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) { - asection *reldyn; + asection *dynamic_relocs; + asection * rela_dyn; + asection * rel_dyn; bfd_size_type count, size; size_t i, ret, sort_elt, ext_size; bfd_byte *sort, *s_non_relative, *p; @@ -7231,39 +7233,168 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); struct bfd_link_order *lo; bfd_vma r_sym_mask; + bfd_boolean use_rela; - reldyn = bfd_get_section_by_name (abfd, ".rela.dyn"); - if (reldyn == NULL || reldyn->size == 0) + /* Find a dynamic reloc section. */ + rela_dyn = bfd_get_section_by_name (abfd, ".rela.dyn"); + rel_dyn = bfd_get_section_by_name (abfd, ".rel.dyn"); + if (rela_dyn != NULL && rela_dyn->size > 0 + && rel_dyn != NULL && rel_dyn->size > 0) { - reldyn = bfd_get_section_by_name (abfd, ".rel.dyn"); - if (reldyn == NULL || reldyn->size == 0) - return 0; - ext_size = bed->s->sizeof_rel; - swap_in = bed->s->swap_reloc_in; - swap_out = bed->s->swap_reloc_out; + bfd_boolean use_rela_initialised = FALSE; + + /* This is just here to stop gcc from complaining. + It's initialization checking code is not perfect. */ + use_rela = TRUE; + + /* Both sections are present. Examine the sizes + of the indirect sections to help us choose. */ + for (lo = rela_dyn->map_head.link_order; lo != NULL; lo = lo->next) + if (lo->type == bfd_indirect_link_order) + { + asection *o = lo->u.indirect.section; + + if ((o->size % bed->s->sizeof_rela) == 0) + { + if ((o->size % bed->s->sizeof_rel) == 0) + /* Section size is divisible by both rel and rela sizes. + It is of no help to us. */ + ; + else + { + /* Section size is only divisible by rela. */ + if (use_rela_initialised && (use_rela == FALSE)) + { + _bfd_error_handler + (_("%B: Unable to sort relocs - they are in more than one size"), abfd); + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + else + { + use_rela = TRUE; + use_rela_initialised = TRUE; + } + } + } + else if ((o->size % bed->s->sizeof_rel) == 0) + { + /* Section size is only divisible by rel. */ + if (use_rela_initialised && (use_rela == TRUE)) + { + _bfd_error_handler + (_("%B: Unable to sort relocs - they are in more than one size"), abfd); + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + else + { + use_rela = FALSE; + use_rela_initialised = TRUE; + } + } + else + { + /* The section size is not divisible by either - something is wrong. */ + _bfd_error_handler + (_("%B: Unable to sort relocs - they are of an unknown size"), abfd); + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + } + + for (lo = rel_dyn->map_head.link_order; lo != NULL; lo = lo->next) + if (lo->type == bfd_indirect_link_order) + { + asection *o = lo->u.indirect.section; + + if ((o->size % bed->s->sizeof_rela) == 0) + { + if ((o->size % bed->s->sizeof_rel) == 0) + /* Section size is divisible by both rel and rela sizes. + It is of no help to us. */ + ; + else + { + /* Section size is only divisible by rela. */ + if (use_rela_initialised && (use_rela == FALSE)) + { + _bfd_error_handler + (_("%B: Unable to sort relocs - they are in more than one size"), abfd); + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + else + { + use_rela = TRUE; + use_rela_initialised = TRUE; + } + } + } + else if ((o->size % bed->s->sizeof_rel) == 0) + { + /* Section size is only divisible by rel. */ + if (use_rela_initialised && (use_rela == TRUE)) + { + _bfd_error_handler + (_("%B: Unable to sort relocs - they are in more than one size"), abfd); + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + else + { + use_rela = FALSE; + use_rela_initialised = TRUE; + } + } + else + { + /* The section size is not divisible by either - something is wrong. */ + _bfd_error_handler + (_("%B: Unable to sort relocs - they are of an unknown size"), abfd); + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + } + + if (! use_rela_initialised) + /* Make a guess. */ + use_rela = TRUE; } + else if (rela_dyn == NULL || rela_dyn->size == 0) + use_rela = FALSE; else + use_rela = TRUE; + + if (use_rela) { + dynamic_relocs = rela_dyn; ext_size = bed->s->sizeof_rela; swap_in = bed->s->swap_reloca_in; swap_out = bed->s->swap_reloca_out; } - count = reldyn->size / ext_size; + else + { + dynamic_relocs = rel_dyn; + ext_size = bed->s->sizeof_rel; + swap_in = bed->s->swap_reloc_in; + swap_out = bed->s->swap_reloc_out; + } size = 0; - for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next) + for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next) if (lo->type == bfd_indirect_link_order) - { - asection *o = lo->u.indirect.section; - size += o->size; - } + size += lo->u.indirect.section->size; - if (size != reldyn->size) + if (size != dynamic_relocs->size) return 0; sort_elt = (sizeof (struct elf_link_sort_rela) + (i2e - 1) * sizeof (Elf_Internal_Rela)); + + count = dynamic_relocs->size / ext_size; sort = bfd_zmalloc (sort_elt * count); + if (sort == NULL) { (*info->callbacks->warning) @@ -7276,7 +7407,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) else r_sym_mask = ~(bfd_vma) 0xffffffff; - for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next) + for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next) if (lo->type == bfd_indirect_link_order) { bfd_byte *erel, *erelend; @@ -7293,9 +7424,11 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) erel = o->contents; erelend = o->contents + o->size; p = sort + o->output_offset / ext_size * sort_elt; + while (erel < erelend) { struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; + (*swap_in) (abfd, erel, s->rela); s->type = (*bed->elf_backend_reloc_type_class) (s->rela); s->u.sym_mask = r_sym_mask; @@ -7326,7 +7459,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2); - for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next) + for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next) if (lo->type == bfd_indirect_link_order) { bfd_byte *erel, *erelend; @@ -7345,7 +7478,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) } free (sort); - *psec = reldyn; + *psec = dynamic_relocs; return ret; } -- 2.7.4