diff options
-rw-r--r-- | bfd/ChangeLog | 10 | ||||
-rw-r--r-- | bfd/elflink.h | 89 | ||||
-rw-r--r-- | bfd/elfxx-mips.c | 4 |
3 files changed, 69 insertions, 34 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9dfac9c..f00325e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2002-10-22 Alexandre Oliva <aoliva@redhat.com> + + * elflink.h (struct elf_link_sort_rela): Turn rel and rela + into arrays. + (elf_link_sort_cmp1, elf_link_sort_cmp2): Adjust. + (elf_link_sort_relocs): Likewise. Take int_rels_per_ext_rel + into account. + * elfxx-mips.c (mips_elf_create_dynamic_relocation): Compose + R_MIPS_REL32 with R_MIPS64 if ABI_64_P. + 2002-10-21 Graeme Peterson <gp@qnx.com> * targets.c (_bfd_target_vector): Add missing qnx vectors. diff --git a/bfd/elflink.h b/bfd/elflink.h index 079917e..03be87a 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -4669,8 +4669,9 @@ struct elf_link_sort_rela 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; }; @@ -4690,13 +4691,13 @@ elf_link_sort_cmp1 (A, B) 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; } @@ -4720,9 +4721,9 @@ elf_link_sort_cmp2 (A, B) 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; } @@ -4740,6 +4741,7 @@ elf_link_sort_relocs (abfd, info, psec) 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) @@ -4763,7 +4765,23 @@ elf_link_sort_relocs (abfd, info, psec) 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) @@ -4784,15 +4802,16 @@ elf_link_sort_relocs (abfd, info, psec) 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 @@ -4802,30 +4821,34 @@ elf_link_sort_relocs (abfd, info, psec) 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)) @@ -4839,14 +4862,14 @@ elf_link_sort_relocs (abfd, info, psec) 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 @@ -4856,14 +4879,14 @@ elf_link_sort_relocs (abfd, info, psec) 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); } } } diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index a179057..ec0b54b 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -2954,7 +2954,9 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx, R_MIPS_REL32); outrel[1].r_info = ELF_R_INFO (output_bfd, (unsigned long) 0, - R_MIPS_NONE); + ABI_64_P (output_bfd) + ? R_MIPS_64 + : R_MIPS_NONE); outrel[2].r_info = ELF_R_INFO (output_bfd, (unsigned long) 0, R_MIPS_NONE); |