diff options
author | Alan Modra <amodra@gmail.com> | 2014-12-03 22:00:18 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2014-12-04 17:37:58 +1030 |
commit | 53df40a43c968f4d97754226d62775d1fe665459 (patch) | |
tree | 1f22712409b2b44439fad7bba496e430637111a2 /bfd | |
parent | 621661e3faf809d4f28bb84e94e30c1c8a8cc933 (diff) | |
download | gdb-53df40a43c968f4d97754226d62775d1fe665459.zip gdb-53df40a43c968f4d97754226d62775d1fe665459.tar.gz gdb-53df40a43c968f4d97754226d62775d1fe665459.tar.bz2 |
Sort relocs output by ld -r
bfd/
PR 17666
* elflink.c: Include bfd_stdint.h.
(cmp_ext32l_r_offset, cmp_ext32b_r_offset,
cmp_ext64l_r_offset, cmp_ext64b_r_offset): New functions.
(elf_link_adjust_relocs): Sort relocs. Free reloc hashes after
sorting invalidates.
ld/testsuite/
* ld-powerpc/vxworks-relax.rd: Update for reloc sorting.
* ld-powerpc/vxworks-relax-2.rd: Likewise.
* ld-sh/sh64/reldl32.rd: Likewise.
* ld-sh/sh64/reldl64.rd: Likewise.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 9 | ||||
-rw-r--r-- | bfd/elflink.c | 158 |
2 files changed, 167 insertions, 0 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 65c7243..5144eb6 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2014-12-04 Alan Modra <amodra@gmail.com> + + PR 17666 + * elflink.c: Include bfd_stdint.h. + (cmp_ext32l_r_offset, cmp_ext32b_r_offset, + cmp_ext64l_r_offset, cmp_ext64b_r_offset): New functions. + (elf_link_adjust_relocs): Sort relocs. Free rel hashes after + sorting invalidates. + 2014-12-03 Nick Clifton <nickc@redhat.com> PR binutils/17512 diff --git a/bfd/elflink.c b/bfd/elflink.c index c964a98..e768634 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -20,6 +20,7 @@ #include "sysdep.h" #include "bfd.h" +#include "bfd_stdint.h" #include "bfdlink.h" #include "libbfd.h" #define ARCH_SIZE 0 @@ -7957,6 +7958,138 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd, return r; } +/* qsort comparison functions sorting external relocs by r_offset. */ + +static int +cmp_ext32l_r_offset (const void *p, const void *q) +{ + union aligned32 + { + uint32_t v; + unsigned char c[4]; + }; + const union aligned32 *a + = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset; + const union aligned32 *b + = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset; + + uint32_t aval = ( (uint32_t) a->c[0] + | (uint32_t) a->c[1] << 8 + | (uint32_t) a->c[2] << 16 + | (uint32_t) a->c[3] << 24); + uint32_t bval = ( (uint32_t) b->c[0] + | (uint32_t) b->c[1] << 8 + | (uint32_t) b->c[2] << 16 + | (uint32_t) b->c[3] << 24); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +static int +cmp_ext32b_r_offset (const void *p, const void *q) +{ + union aligned32 + { + uint32_t v; + unsigned char c[4]; + }; + const union aligned32 *a + = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset; + const union aligned32 *b + = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset; + + uint32_t aval = ( (uint32_t) a->c[0] << 24 + | (uint32_t) a->c[1] << 16 + | (uint32_t) a->c[2] << 8 + | (uint32_t) a->c[3]); + uint32_t bval = ( (uint32_t) b->c[0] << 24 + | (uint32_t) b->c[1] << 16 + | (uint32_t) b->c[2] << 8 + | (uint32_t) b->c[3]); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +#ifdef BFD_HOST_64_BIT +static int +cmp_ext64l_r_offset (const void *p, const void *q) +{ + union aligned64 + { + uint64_t v; + unsigned char c[8]; + }; + const union aligned64 *a + = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset; + const union aligned64 *b + = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset; + + uint64_t aval = ( (uint64_t) a->c[0] + | (uint64_t) a->c[1] << 8 + | (uint64_t) a->c[2] << 16 + | (uint64_t) a->c[3] << 24 + | (uint64_t) a->c[4] << 32 + | (uint64_t) a->c[5] << 40 + | (uint64_t) a->c[6] << 48 + | (uint64_t) a->c[7] << 56); + uint64_t bval = ( (uint64_t) b->c[0] + | (uint64_t) b->c[1] << 8 + | (uint64_t) b->c[2] << 16 + | (uint64_t) b->c[3] << 24 + | (uint64_t) b->c[4] << 32 + | (uint64_t) b->c[5] << 40 + | (uint64_t) b->c[6] << 48 + | (uint64_t) b->c[7] << 56); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +static int +cmp_ext64b_r_offset (const void *p, const void *q) +{ + union aligned64 + { + uint64_t v; + unsigned char c[8]; + }; + const union aligned64 *a + = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset; + const union aligned64 *b + = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset; + + uint64_t aval = ( (uint64_t) a->c[0] << 56 + | (uint64_t) a->c[1] << 48 + | (uint64_t) a->c[2] << 40 + | (uint64_t) a->c[3] << 32 + | (uint64_t) a->c[4] << 24 + | (uint64_t) a->c[5] << 16 + | (uint64_t) a->c[6] << 8 + | (uint64_t) a->c[7]); + uint64_t bval = ( (uint64_t) b->c[0] << 56 + | (uint64_t) b->c[1] << 48 + | (uint64_t) b->c[2] << 40 + | (uint64_t) b->c[3] << 32 + | (uint64_t) b->c[4] << 24 + | (uint64_t) b->c[5] << 16 + | (uint64_t) b->c[6] << 8 + | (uint64_t) b->c[7]); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} +#endif + /* When performing a relocatable link, the input relocations are preserved. But, if they reference global symbols, the indices referenced must be updated. Update all the relocations found in @@ -7975,6 +8108,7 @@ elf_link_adjust_relocs (bfd *abfd, int r_sym_shift; unsigned int count = reldata->count; struct elf_link_hash_entry **rel_hash = reldata->hashes; + int (*compare) (const void *, const void *); if (reldata->hdr->sh_entsize == bed->s->sizeof_rel) { @@ -8020,6 +8154,30 @@ elf_link_adjust_relocs (bfd *abfd, | (irela[j].r_info & r_type_mask)); (*swap_out) (abfd, irela, erela); } + + if (bed->s->arch_size == 32) + { + if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) + compare = cmp_ext32l_r_offset; + else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) + compare = cmp_ext32b_r_offset; + else + abort (); + } + else + { +#ifdef BFD_HOST_64_BIT + if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) + compare = cmp_ext64l_r_offset; + else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) + compare = cmp_ext64b_r_offset; + else +#endif + abort (); + } + qsort (reldata->hdr->contents, count, reldata->hdr->sh_entsize, compare); + free (reldata->hashes); + reldata->hashes = NULL; } struct elf_link_sort_rela |