PR13616, linker should pad executable sections with nops, not zeros
authorAlan Modra <amodra@gmail.com>
Wed, 16 Oct 2019 10:53:29 +0000 (21:23 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 16 Oct 2019 12:37:27 +0000 (23:07 +1030)
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 <big_endian>): 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
bfd/cpu-powerpc.c
bfd/linker.c
include/ChangeLog
include/bfdlink.h
ld/ChangeLog
ld/emulparams/elf64lppc.sh
ld/emulparams/elf64ppc.sh
ld/ldemul.c
ld/ldwrite.c

index 5a9bfd7270a76ffee15d42587e0d3f70fe367948..74cdda4ffaaba8cf8ff172ac9b2e7860bb1d0fd7 100644 (file)
@@ -1,3 +1,11 @@
+2019-10-16  Alan Modra  <amodra@gmail.com>
+
+       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  <amodra@gmail.com>
 
        * elf32-m68hc1x.c (reloc_warning): Add printf attribute.
index 49594678d3a4319b8923996e0db1ef01e8df7772..6c54388a82be20837a0fb98ca125613212192263 100644 (file)
@@ -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.  */ \
   }
index 143b8eb950e993ae0c5f6fde07023dbb4549ef16..382b69d8c3d62079fbd6ffd8392acf2fbb6064ae 100644 (file)
@@ -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;
index 13b15f00a7165018b0c48622e3944c702624ce06..412d71459e077001a2d21320e7905160c5fa4b7c 100644 (file)
@@ -1,3 +1,8 @@
+2019-10-16  Alan Modra  <amodra@gmail.com>
+
+       PR 13616
+       * bfdlink.h (struct bfd_link_info <big_endian>): New field.
+
 2019-10-07  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
 
        * elf/msp430.h: Add enums for MSPABI and GNU object attribute tag
index 76355a3b9537b398d8dc210102a2c0c2514ca710..32d15129ab5ceeae17bfd1929a39106301bf9739 100644 (file)
@@ -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;
 
index 5553095352dfcfbe96b7bedec724d460e877b03c..f51e6466e68e4604a14a5898da1ed4534d8f9cda 100644 (file)
@@ -1,3 +1,12 @@
+2019-10-16  Alan Modra  <amodra@gmail.com>
+
+       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  <amodra@gmail.com>
 
        * genscripts.sh: Correct comments.  Remove outdated comment block
index 71ef0d3efd1e203eb563fcefc0334110210050b8..341629184bcbabf1446280a8c0a40fffcaac3ad5 100644 (file)
@@ -1,3 +1,2 @@
 source_sh ${srcdir}/emulparams/elf64ppc.sh
 OUTPUT_FORMAT="elf64-powerpcle"
-NOP=0x00000060
index 0dd42cf4323d66cd1e6f8964b48f81eb50bd746a..15221b82220ead59b35fe2d1733971a954744608 100644 (file)
@@ -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
index ab23dee41b67eba9ccca48d4bae6f11d180785c0..090f1ebfa759fc3fd03842206d6aabcfba0a9e39 100644 (file)
@@ -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
index f2d695063ca2e47606f99e16bea1d808663a8d6d..491a4e9d7f692401923791683d8af616293083b5 100644 (file)
@@ -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;