From 22216541c1796e9e1331d6f4e16b03a6f02e7381 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 16 Oct 2019 21:23:29 +1030 Subject: [PATCH] PR13616, linker should pad executable sections with nops, not zeros This implements padding of orphan executable sections for PowerPC. Of course, the simple implementation of bfd_arch_ppc_nop_fill and removing the NOP definition didn't work, with powerpc64 hitting a testsuite failure linking to S-records. That's because the srec target is BFD_ENDIAN_UNKNOWN so the test of bfd_big_endian (abfd) in default_data_link_order therefore returned false, resulting in a little-endian nop pattern. The rest of the patch fixes that problem by adding a new field to bfd_link_info that can be used to determine actual endianness on targets like srec. PR 13616 include/ * bfdlink.h (struct bfd_link_info ): New field. bfd/ * cpu-powerpc.c (bfd_arch_ppc_nop_fill): New function, use it for all ppc arch info. * linker.c (default_data_link_order): Pass info->big_endian to arch_info->fill function. ld/ * emulparams/elf64lppc.sh (NOP): Don't define. * emulparams/elf64ppc.sh (NOP): Don't define. * ldwrite.c (build_link_order): Use link_info.big_endian. Move code determining endian to use for data_statement to.. * ldemul.c (after_open_default): ..here. Set link_info.big_endian. --- bfd/ChangeLog | 8 ++++ bfd/cpu-powerpc.c | 39 +++++++++++++++- bfd/linker.c | 4 +- include/ChangeLog | 5 +++ include/bfdlink.h | 4 ++ ld/ChangeLog | 9 ++++ ld/emulparams/elf64lppc.sh | 1 - ld/emulparams/elf64ppc.sh | 1 - ld/ldemul.c | 23 ++++++++++ ld/ldwrite.c | 91 +++++++++++--------------------------- 10 files changed, 116 insertions(+), 69 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5a9bfd7270a..74cdda4ffaa 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2019-10-16 Alan Modra + + PR 13616 + * cpu-powerpc.c (bfd_arch_ppc_nop_fill): New function, use it + for all ppc arch info. + * linker.c (default_data_link_order): Pass info->big_endian to + arch_info->fill function. + 2019-10-15 Alan Modra * elf32-m68hc1x.c (reloc_warning): Add printf attribute. diff --git a/bfd/cpu-powerpc.c b/bfd/cpu-powerpc.c index 49594678d3a..6c54388a82b 100644 --- a/bfd/cpu-powerpc.c +++ b/bfd/cpu-powerpc.c @@ -48,6 +48,43 @@ powerpc_compatible (const bfd_arch_info_type *a, /*NOTREACHED*/ } +/* Return a COUNT sized buffer filled with nops (if CODE is TRUE) or + zeros (if CODE is FALSE). This is the fill used between input + sections for alignment. It won't normally be executed. */ + +static void * +bfd_arch_ppc_nop_fill (bfd_size_type count, + bfd_boolean is_bigendian, + bfd_boolean code) +{ + bfd_byte *fill; + + if (count == 0) + return NULL; + fill = bfd_malloc (count); + if (fill == NULL) + return fill; + + if (code && (count & 3) == 0) + { + static const char nop_be[4] = {0x60, 0, 0, 0}; + static const char nop_le[4] = {0, 0, 0, 0x60}; + const char *nop = is_bigendian ? nop_be : nop_le; + bfd_byte *p = fill; + + while (count != 0) + { + memcpy (p, nop, 4); + p += 4; + count -= 4; + } + } + else + memset (fill, 0, count); + + return fill; +} + #define N(BITS, NUMBER, PRINT, DEFAULT, NEXT) \ { \ BITS, /* Bits in a word. */ \ @@ -61,7 +98,7 @@ powerpc_compatible (const bfd_arch_info_type *a, DEFAULT, \ powerpc_compatible, \ bfd_default_scan, \ - bfd_arch_default_fill, \ + bfd_arch_ppc_nop_fill, \ NEXT, \ 0 /* Maximum offset of a reloc from the start of an insn. */ \ } diff --git a/bfd/linker.c b/bfd/linker.c index 143b8eb950e..382b69d8c3d 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -2469,7 +2469,7 @@ _bfd_default_link_order (bfd *abfd, static bfd_boolean default_data_link_order (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct bfd_link_info *info, asection *sec, struct bfd_link_order *link_order) { @@ -2489,7 +2489,7 @@ default_data_link_order (bfd *abfd, fill_size = link_order->u.data.size; if (fill_size == 0) { - fill = abfd->arch_info->fill (size, bfd_big_endian (abfd), + fill = abfd->arch_info->fill (size, info->big_endian, (sec->flags & SEC_CODE) != 0); if (fill == NULL) return FALSE; diff --git a/include/ChangeLog b/include/ChangeLog index 13b15f00a71..412d71459e0 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2019-10-16 Alan Modra + + PR 13616 + * bfdlink.h (struct bfd_link_info ): New field. + 2019-10-07 Jozef Lawrynowicz * elf/msp430.h: Add enums for MSPABI and GNU object attribute tag diff --git a/include/bfdlink.h b/include/bfdlink.h index 76355a3b953..32d15129ab5 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -359,6 +359,10 @@ struct bfd_link_info /* TRUE if section groups should be resolved. */ unsigned int resolve_section_groups: 1; + /* Set if output file is big-endian, or if that is unknown, from + the command line or first input file endianness. */ + unsigned int big_endian : 1; + /* Which symbols to strip. */ ENUM_BITFIELD (bfd_link_strip) strip : 2; diff --git a/ld/ChangeLog b/ld/ChangeLog index 5553095352d..f51e6466e68 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2019-10-16 Alan Modra + + PR 13616 + * emulparams/elf64lppc.sh (NOP): Don't define. + * emulparams/elf64ppc.sh (NOP): Don't define. + * ldwrite.c (build_link_order): Use link_info.big_endian. Move + code determining endian to use for data_statement to.. + * ldemul.c (after_open_default): ..here. Set link_info.big_endian. + 2019-10-16 Alan Modra * genscripts.sh: Correct comments. Remove outdated comment block diff --git a/ld/emulparams/elf64lppc.sh b/ld/emulparams/elf64lppc.sh index 71ef0d3efd1..341629184bc 100644 --- a/ld/emulparams/elf64lppc.sh +++ b/ld/emulparams/elf64lppc.sh @@ -1,3 +1,2 @@ source_sh ${srcdir}/emulparams/elf64ppc.sh OUTPUT_FORMAT="elf64-powerpcle" -NOP=0x00000060 diff --git a/ld/emulparams/elf64ppc.sh b/ld/emulparams/elf64ppc.sh index 0dd42cf4323..15221b82220 100644 --- a/ld/emulparams/elf64ppc.sh +++ b/ld/emulparams/elf64ppc.sh @@ -6,7 +6,6 @@ OUTPUT_FORMAT="elf64-powerpc" TEXT_START_ADDR=0x10000000 #SEGMENT_SIZE=0x10000000 ARCH=powerpc:common64 -NOP=0x60000000 unset EXECUTABLE_SYMBOLS unset SDATA_START_SYMBOLS unset SDATA2_START_SYMBOLS diff --git a/ld/ldemul.c b/ld/ldemul.c index ab23dee41b6..090f1ebfa75 100644 --- a/ld/ldemul.c +++ b/ld/ldemul.c @@ -236,6 +236,29 @@ after_parse_default (void) void after_open_default (void) { + link_info.big_endian = TRUE; + + if (bfd_big_endian (link_info.output_bfd)) + ; + else if (bfd_little_endian (link_info.output_bfd)) + link_info.big_endian = FALSE; + else + { + if (command_line.endian == ENDIAN_BIG) + ; + else if (command_line.endian == ENDIAN_LITTLE) + link_info.big_endian = FALSE; + else if (command_line.endian == ENDIAN_UNSET) + { + LANG_FOR_EACH_INPUT_STATEMENT (s) + if (s->the_bfd != NULL) + { + if (bfd_little_endian (s->the_bfd)) + link_info.big_endian = FALSE; + break; + } + } + } } void diff --git a/ld/ldwrite.c b/ld/ldwrite.c index f2d695063ca..491a4e9d7f6 100644 --- a/ld/ldwrite.c +++ b/ld/ldwrite.c @@ -46,7 +46,6 @@ build_link_order (lang_statement_union_type *statement) asection *output_section; struct bfd_link_order *link_order; bfd_vma value; - bfd_boolean big_endian = FALSE; output_section = statement->data_statement.output_section; ASSERT (output_section->owner == link_info.output_bfd); @@ -66,74 +65,38 @@ build_link_order (lang_statement_union_type *statement) value = statement->data_statement.value; - /* If the endianness of the output BFD is not known, then we - base the endianness of the data on the first input file. - By convention, the bfd_put routines for an unknown + /* By convention, the bfd_put routines for an unknown endianness are big endian, so we must swap here if the - input file is little endian. */ - if (bfd_big_endian (link_info.output_bfd)) - big_endian = TRUE; - else if (bfd_little_endian (link_info.output_bfd)) - big_endian = FALSE; - else + input is little endian. */ + if (!bfd_big_endian (link_info.output_bfd) + && !bfd_little_endian (link_info.output_bfd) + && !link_info.big_endian) { - bfd_boolean swap; + bfd_byte buffer[8]; - swap = FALSE; - if (command_line.endian == ENDIAN_BIG) - big_endian = TRUE; - else if (command_line.endian == ENDIAN_LITTLE) - { - big_endian = FALSE; - swap = TRUE; - } - else if (command_line.endian == ENDIAN_UNSET) + switch (statement->data_statement.type) { - big_endian = TRUE; - { - LANG_FOR_EACH_INPUT_STATEMENT (s) + case QUAD: + case SQUAD: + if (sizeof (bfd_vma) >= QUAD_SIZE) { - if (s->the_bfd != NULL) - { - if (bfd_little_endian (s->the_bfd)) - { - big_endian = FALSE; - swap = TRUE; - } - break; - } - } - } - } - - if (swap) - { - bfd_byte buffer[8]; - - switch (statement->data_statement.type) - { - case QUAD: - case SQUAD: - if (sizeof (bfd_vma) >= QUAD_SIZE) - { - bfd_putl64 (value, buffer); - value = bfd_getb64 (buffer); - break; - } - /* Fall through. */ - case LONG: - bfd_putl32 (value, buffer); - value = bfd_getb32 (buffer); - break; - case SHORT: - bfd_putl16 (value, buffer); - value = bfd_getb16 (buffer); - break; - case BYTE: + bfd_putl64 (value, buffer); + value = bfd_getb64 (buffer); break; - default: - abort (); } + /* Fall through. */ + case LONG: + bfd_putl32 (value, buffer); + value = bfd_getb32 (buffer); + break; + case SHORT: + bfd_putl16 (value, buffer); + value = bfd_getb16 (buffer); + break; + case BYTE: + break; + default: + abort (); } } @@ -157,10 +120,10 @@ build_link_order (lang_statement_union_type *statement) high = (bfd_vma) -1; bfd_put_32 (link_info.output_bfd, high, (link_order->u.data.contents - + (big_endian ? 0 : 4))); + + (link_info.big_endian ? 0 : 4))); bfd_put_32 (link_info.output_bfd, value, (link_order->u.data.contents - + (big_endian ? 4 : 0))); + + (link_info.big_endian ? 4 : 0))); } link_order->size = QUAD_SIZE; break; -- 2.30.2