Fix the merging of .PPC.EMB.apuinfo sections. Add a test to make sure that
authorNick Clifton <nickc@redhat.com>
Tue, 3 Dec 2002 18:24:33 +0000 (18:24 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 3 Dec 2002 18:24:33 +0000 (18:24 +0000)
the fix continues to work.

bfd/ChangeLog
bfd/elf32-ppc.c
gas/ChangeLog
gas/config/tc-ppc.c
ld/testsuite/ChangeLog
ld/testsuite/ld-powerpc/apuinfo.rd [new file with mode: 0644]
ld/testsuite/ld-powerpc/apuinfo1.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/apuinfo2.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/powerpc.exp
ld/testsuite/ld-srec/srec.exp

index 57d7ee948a89c8b0638b5f8475ddc10df6fad0c3..c16c741d97a4ea5ca235c1675a0c041ba4735e3a 100644 (file)
@@ -1,3 +1,23 @@
+2002-12-03  Nick Clifton  <nickc@redhat.com>
+
+       * elf32-ppc.c (apuinfo_list_init): New function.
+        (apuinfo_list_add): New function: Add a value to the list.
+        (apuinfo_list_length): New function: Return the number of
+        values on the list.
+        (apuinfo_list_element): New function: Return a value on the
+        list.
+        (apuinfo_list_finish): New function: Free the resources used
+        by the list.
+        (ppc_elf_begin_write_processing): New function.  Scan the
+        input bfds for apuinfo sections.
+        (ppc_elf_write_section): New function: Delay the creation of
+        the contents of an apuinfo section in an output bfd.
+        (ppc_elf_final_write_processing): New function.  Create the
+        contents of an apuinfo section in an output bfd.
+        (elf_backend_begin_write_processing): Define.
+        (elf_backend_final_write_processing): Define.
+        (elf_backend_write_section): Define.
+
 2002-12-03  Richard Henderson  <rth@redhat.com>
 
        * cpu-ia64-opc.c (elf64_ia64_operands): Add ldxmov entry.
index 0c33a905c142fe4cb1496c3d12d2d9f19d295139..c117f54b2009a6ca75431d9d2adc341ffd7c9a57 100644 (file)
@@ -3783,6 +3783,303 @@ ppc_elf_grok_psinfo (abfd, note)
   return TRUE;
 }
 \f
+/* Very simple linked list structure for recording apuinfo values.  */
+typedef struct apuinfo_list
+{
+  struct apuinfo_list *        next;
+  unsigned long         value;
+}
+apuinfo_list;
+
+static apuinfo_list * head;
+
+static void          apuinfo_list_init    PARAMS ((void));
+static void          apuinfo_list_add     PARAMS ((unsigned long));
+static unsigned      apuinfo_list_length  PARAMS ((void));
+static unsigned long apuinfo_list_element PARAMS ((unsigned long));
+static void          apuinfo_list_finish  PARAMS ((void));
+
+extern void          ppc_elf_begin_write_processing
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern void          ppc_elf_final_write_processing
+  PARAMS ((bfd *, bfd_boolean));
+extern bfd_boolean   ppc_elf_write_section
+  PARAMS ((bfd *, asection *, bfd_byte *));
+
+
+
+static void
+apuinfo_list_init PARAMS ((void))
+{
+  head = NULL;
+}
+
+static void
+apuinfo_list_add (value)
+     unsigned long value;
+{
+  apuinfo_list * entry = head;
+
+  while (entry != NULL)
+    {
+      if (entry->value == value)
+       return;
+      entry = entry->next;
+    }
+
+  entry = bfd_malloc (sizeof (* entry));
+  if (entry == NULL)
+    return;
+
+  entry->value = value;
+  entry->next  = head;
+  head = entry;
+}
+
+static unsigned
+apuinfo_list_length PARAMS ((void))
+{
+  apuinfo_list * entry;
+  unsigned long count;
+
+  for (entry = head, count = 0;
+       entry;
+       entry = entry->next)
+    ++ count;
+
+  return count;
+}
+
+static inline unsigned long
+apuinfo_list_element (number)
+     unsigned long number;
+{
+  apuinfo_list * entry;
+
+  for (entry = head;
+       entry && number --;
+       entry = entry->next)
+    ;
+
+  return entry ? entry->value : 0;
+}
+
+static void
+apuinfo_list_finish PARAMS ((void))
+{
+  apuinfo_list * entry;
+
+  for (entry = head; entry;)
+    {
+      apuinfo_list * next = entry->next;
+      free (entry);
+      entry = next;
+    }
+
+  head = NULL;
+}
+
+#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo"
+#define APUINFO_LABEL        "APUinfo"
+
+/* Scan the input BFDs and create a linked list of
+   the APUinfo values that will need to be emitted.  */
+
+void
+ppc_elf_begin_write_processing (abfd, link_info)
+     bfd *abfd;
+     struct bfd_link_info *link_info;
+{
+  bfd *         ibfd;
+  asection *    asec;
+  char *        buffer;
+  unsigned     num_input_sections;
+  bfd_size_type        output_section_size;
+  unsigned      i;
+  unsigned      num_entries;
+  unsigned long        offset;
+  unsigned long length;
+  const char *  error_message = NULL;
+
+  /* Scan the input bfds, looking for apuinfo sections.  */
+  num_input_sections = 0;
+  output_section_size = 0;
+
+  for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
+    {
+      asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME);
+      if (asec)
+       {
+         ++ num_input_sections;
+         output_section_size += asec->_raw_size;
+       }
+    }
+
+  /* We need at least one input sections
+     in order to make merging worthwhile.  */
+  if (num_input_sections < 1)
+    return;
+
+  /* Just make sure that the output section exists as well.  */
+  asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+  if (asec == NULL)
+    return;
+
+  /* Allocate a buffer for the contents of the input sections.  */
+  buffer = bfd_malloc (output_section_size);
+  if (buffer == NULL)
+    return;
+
+  offset = 0;
+  apuinfo_list_init ();
+
+  /* Read in the input sections contents.  */
+  for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
+    {
+      unsigned long    datum;
+      char *           ptr;
+
+      
+      asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME);
+      if (asec == NULL)
+       continue;
+
+      length = asec->_raw_size;
+      if (length < 24)
+       {
+         error_message = _("corrupt or empty %s section in %s");
+         goto fail;
+       }
+      
+      if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0
+         || (bfd_bread (buffer + offset, length, ibfd) != length))
+       {
+         error_message = _("unable to read in %s section from %s");
+         goto fail;
+       }
+
+      /* Process the contents of the section.  */
+      ptr = buffer + offset;
+      error_message = _("corrupt %s section in %s");
+
+      /* Verify the contents of the header.  Note - we have to
+        extract the values this way in order to allow for a
+        host whose endian-ness is different from the target.  */
+      datum = bfd_get_32 (ibfd, ptr);
+      if (datum != sizeof APUINFO_LABEL)
+       goto fail;
+
+      datum = bfd_get_32 (ibfd, ptr + 8);
+      if (datum != 0x2)
+       goto fail;
+
+      if (strcmp (ptr + 12, APUINFO_LABEL) != 0)
+       goto fail;
+
+      /* Get the number of apuinfo entries.  */
+      datum = bfd_get_32 (ibfd, ptr + 4);
+      if ((datum * 4 + 20) != length)
+       goto fail;
+
+      /* Make sure that we do not run off the end of the section.  */
+      if (offset + length > output_section_size)
+       goto fail;
+
+      /* Scan the apuinfo section, building a list of apuinfo numbers.  */
+      for (i = 0; i < datum; i++)
+       apuinfo_list_add (bfd_get_32 (ibfd, ptr + 20 + (i * 4)));
+
+      /* Update the offset.  */
+      offset += length;
+    }
+
+  error_message = NULL;
+
+  /* Compute the size of the output section.  */
+  num_entries = apuinfo_list_length ();
+  output_section_size = 20 + num_entries * 4;
+
+  asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+
+  if (! bfd_set_section_size  (abfd, asec, output_section_size))
+    ibfd = abfd,
+      error_message = _("warning: unable to set size of %s section in %s");
+  
+ fail:
+  free (buffer);
+
+  if (error_message)
+    _bfd_error_handler (error_message, APUINFO_SECTION_NAME,
+                       bfd_archive_filename (ibfd));
+}
+
+
+/* Prevent the output section from accumulating the input sections'
+   contents.  We have already stored this in our linked list structure.  */
+
+bfd_boolean
+ppc_elf_write_section (abfd, asec, contents)
+     bfd * abfd ATTRIBUTE_UNUSED;
+     asection * asec;
+     bfd_byte * contents ATTRIBUTE_UNUSED;
+{
+  return strcmp (asec->name, APUINFO_SECTION_NAME) == 0;
+}
+
+
+/* Finally we can generate the output section.  */
+
+void
+ppc_elf_final_write_processing (abfd, linker)
+     bfd * abfd;
+     bfd_boolean linker ATTRIBUTE_UNUSED;
+{
+  bfd_byte *    buffer;
+  asection *    asec;
+  unsigned      i;
+  unsigned      num_entries;
+  bfd_size_type length;
+
+  asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+  if (asec == NULL)
+    return;
+
+  length = asec->_raw_size;
+  if (length < 20)
+    return;
+
+  buffer = bfd_malloc (length);
+  if (buffer == NULL)
+    {
+      _bfd_error_handler (_("failed to allocate space for new APUinfo section."));
+      return;
+    }
+
+  /* Create the apuinfo header.  */
+  num_entries = apuinfo_list_length ();
+  bfd_put_32 (abfd, sizeof APUINFO_LABEL, buffer);
+  bfd_put_32 (abfd, num_entries, buffer + 4);
+  bfd_put_32 (abfd, 0x2, buffer + 8);
+  strcpy (buffer + 12, APUINFO_LABEL);
+  
+  length = 20;
+  for (i = 0; i < num_entries; i++)
+    {
+      bfd_put_32 (abfd, apuinfo_list_element (i), buffer + length);
+      length += 4;
+    }
+
+  if (length != asec->_raw_size)
+    _bfd_error_handler (_("failed to compute new APUinfo section."));
+  
+  if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length))
+    _bfd_error_handler (_("failed to install new APUinfo section."));
+    
+  free (buffer);
+
+  apuinfo_list_finish ();
+}
+\f
 #define TARGET_LITTLE_SYM      bfd_elf32_powerpcle_vec
 #define TARGET_LITTLE_NAME     "elf32-powerpcle"
 #define TARGET_BIG_SYM         bfd_elf32_powerpc_vec
@@ -3832,5 +4129,8 @@ ppc_elf_grok_psinfo (abfd, note)
 #define elf_backend_grok_prstatus              ppc_elf_grok_prstatus
 #define elf_backend_grok_psinfo                        ppc_elf_grok_psinfo
 #define elf_backend_reloc_type_class           ppc_elf_reloc_type_class
+#define elf_backend_begin_write_processing      ppc_elf_begin_write_processing
+#define elf_backend_final_write_processing      ppc_elf_final_write_processing
+#define elf_backend_write_section               ppc_elf_write_section
 
 #include "elf32-target.h"
index d8911667b347479871f3d2f8d75cfe4f5efcee1f..5c59ad5c21ac8a54bb1261eca0731e735cfad58d 100644 (file)
@@ -1,3 +1,8 @@
+2002-12-03  Nick Clifton  <nickc@redhat.com>
+
+       * config/tc-ppc.c (ppc_cleanup): Do not set SEC_MERGE flag on
+       .PPC.EMB>apuinfo sections.
+
 2002-12-03  Richard Henderson  <rth@redhat.com>
 
        * config/tc-ia64.c (operand_match): Add IA64_OPND_LDXMOV case.
index 04fae3810753f3c891cf02c4db5c625e33c1db85..ba058f667bb2a1565b8dc1abb161160d04b50028 100644 (file)
@@ -1330,7 +1330,7 @@ ppc_cleanup ()
     apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
     bfd_set_section_flags (stdoutput,
                           apuinfo_secp,
-                          SEC_HAS_CONTENTS | SEC_READONLY | SEC_MERGE);
+                          SEC_HAS_CONTENTS | SEC_READONLY);
 
     p = frag_more (4);
     md_number_to_chars (p, (valueT) 8, 4);
index 2f8179bac757702721479140042ebaf806042de3..4226307bba9364b1aa737e27a022745388da1f25 100644 (file)
@@ -1,3 +1,11 @@
+2002-12-03  Nick Clifton  <nickc@redhat.com>
+
+       * ld-powerpc/powerpc.exp (ppcelftests): Add apuinfo merging
+       test.
+       * ld-powerpc/apuinfo1.s: New assembler source file.
+       * ld-powerpc/apuinfo2.s: New assembler source file.
+       * ld-powerpc/apuinfo.rd: New expected output file.
+
 2002-12-01  Stephane Carrez  <stcarrez@nerim.fr>
 
        Fix PR savannah/1417:
diff --git a/ld/testsuite/ld-powerpc/apuinfo.rd b/ld/testsuite/ld-powerpc/apuinfo.rd
new file mode 100644 (file)
index 0000000..421ae7d
--- /dev/null
@@ -0,0 +1,10 @@
+#source: apuinfo1.s
+#source: apuinfo2.s
+#as: -me500
+#readelf: -x5
+#target: powerpc-eabi*
+
+Hex dump of section '.PPC.EMB.apuinfo':
+  0x00000000 00000008 00000007 00000002 41505569 ............APUi
+  0x00000010 6e666f00 00420001 00430001 00410001 nfo..B...C...A..
+  0x00000020 01020001 01010001 00400001 01000001 .........@......
diff --git a/ld/testsuite/ld-powerpc/apuinfo1.s b/ld/testsuite/ld-powerpc/apuinfo1.s
new file mode 100644 (file)
index 0000000..fd42eac
--- /dev/null
@@ -0,0 +1,9 @@
+       .text
+       .global apuinfo1
+apuinfo1:      
+       evstdd 29,8(1)
+       isellt 29, 28, 27
+       efsabs 29, 28
+       .global _start
+_start:
+       nop
diff --git a/ld/testsuite/ld-powerpc/apuinfo2.s b/ld/testsuite/ld-powerpc/apuinfo2.s
new file mode 100644 (file)
index 0000000..7f4e7bb
--- /dev/null
@@ -0,0 +1,8 @@
+       .text
+       .global apuinfo2
+apuinfo2:      
+       evstdd 29,8(1)
+       mfbbear 29
+       mfpmr   29, 27
+       dcbtstls 1, 29, 28
+       rfmci
index f52278d433acd974d22737103761fa433d3c5f68..a853df96a6cf50bd85331f08717bc2be88ff8fca 100644 (file)
@@ -41,6 +41,8 @@ if { [istarget "*-*-macos*"] || [istarget "*-*-netware*"]
 set ppcelftests {
     {"Reloc section order" "-shared -z nocombreloc" "" {reloc.s}
      {{objdump -hw reloc.d}} "reloc.so"}
+    {"APUinfo section processing" "" "-me500" {apuinfo1.s apuinfo2.s}
+   {{readelf -x5 apuinfo.rd}} "apuinfo"}
 }
 
 run_ld_link_tests $ppcelftests
index d3fa76411bc08901633b23c883cea273bbe770de..af1ceed892e6b18c4375be3a56b8ce2b1d83f941 100644 (file)
@@ -370,7 +370,7 @@ setup_xfail "thumb-*-elf*"
 setup_xfail "arm*-*-linux*"
 
 # The S-record linker doesn't build special EABI sections.
-setup_xfail "powerpc*-*-eabi*"
+setup_xfail "powerpc*-*-eabi*"
 
 # The S-record linker doesn't include the .{zda} sections.
 setup_xfail "v850*-*-elf"