This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Incorrect use of SEC_MERGE in tc-ppc.c


Hi Jakub, Hi Elena,

> tc-ppc.c (ppc_cleanup) does:
> 
>     /* Create the .PPC.EMB.apuinfo section.  */
>     apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
>     bfd_set_section_flags (stdoutput,
>                            apuinfo_secp,
>                            SEC_HAS_CONTENTS | SEC_READONLY | SEC_MERGE);
> 
> yet never sets apuinfo_secp->entsize.

Here is a patch to fix this problem.  The patch removes the SEC_MERGE
flag, since the section merging code is not really suited to handling
this section.  Instead it adds code to the PowerPC backend in BFD to
merge the section by hand.

The code is a bit cumbersome.  It has to calculate the length of the
merged section separately from generating its contents, but it does
work.  I have also included a testsuite entry to make sure that it
continues to work.  No new testsuite failures for the powerpc-eabispe
toolchain or the x86 native toolchain were introduced by this patch.

Cheers
        Nick

gas/ChangeLog
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.

bfd/ChangeLog
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.

ld/testsuite/ChangeLog
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.


                      Index: gas/config/tc-ppc.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-ppc.c,v
retrieving revision 1.62
diff -c -3 -p -w -r1.62 tc-ppc.c
*** gas/config/tc-ppc.c	30 Nov 2002 08:39:43 -0000	1.62
--- gas/config/tc-ppc.c	3 Dec 2002 18:10:57 -0000
*************** ppc_cleanup ()
*** 1330,1336 ****
      apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
      bfd_set_section_flags (stdoutput,
  			   apuinfo_secp,
! 			   SEC_HAS_CONTENTS | SEC_READONLY | SEC_MERGE);
  
      p = frag_more (4);
      md_number_to_chars (p, (valueT) 8, 4);
--- 1330,1336 ----
      apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
      bfd_set_section_flags (stdoutput,
  			   apuinfo_secp,
! 			   SEC_HAS_CONTENTS | SEC_READONLY);
  
      p = frag_more (4);
      md_number_to_chars (p, (valueT) 8, 4);

Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.56
diff -c -3 -p -w -r1.56 elf32-ppc.c
*** bfd/elf32-ppc.c	30 Nov 2002 08:39:38 -0000	1.56
--- bfd/elf32-ppc.c	3 Dec 2002 18:10:58 -0000
*************** ppc_elf_grok_psinfo (abfd, note)
*** 3783,3788 ****
--- 3783,4085 ----
    return TRUE;
  }
  
+ /* 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 ();
+ }
+ 
  #define TARGET_LITTLE_SYM	bfd_elf32_powerpcle_vec
  #define TARGET_LITTLE_NAME	"elf32-powerpcle"
  #define TARGET_BIG_SYM		bfd_elf32_powerpc_vec
*************** ppc_elf_grok_psinfo (abfd, note)
*** 3832,3836 ****
--- 4129,4136 ----
  #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: ld/testsuite/ld-powerpc/powerpc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/powerpc.exp,v
retrieving revision 1.3
diff -c -3 -p -w -r1.3 powerpc.exp
*** ld/testsuite/ld-powerpc/powerpc.exp	10 Oct 2002 02:53:17 -0000	1.3
--- ld/testsuite/ld-powerpc/powerpc.exp	3 Dec 2002 18:10:58 -0000
*************** if { [istarget "*-*-macos*"] || [istarge
*** 41,46 ****
--- 41,48 ----
  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: ld/testsuite/ld-powerpc/apuinfo1.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/apuinfo1.s
diff -N ld/testsuite/ld-powerpc/apuinfo1.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-powerpc/apuinfo1.s	3 Dec 2002 18:10:58 -0000
***************
*** 0 ****
--- 1,10 ----
+ 	.text
+ 	.global apuinfo1
+ apuinfo1:	
+ 	evstdd 29,8(1)
+ 	isellt 29, 28, 27
+ 	efsabs 29, 28
+ 	.global _start
+ _start:
+ 	nop
+ 	

Index: ld/testsuite/ld-powerpc/apuinfo2.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/apuinfo2.s
diff -N ld/testsuite/ld-powerpc/apuinfo2.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-powerpc/apuinfo2.s	3 Dec 2002 18:10:58 -0000
***************
*** 0 ****
--- 1,8 ----
+ 	.text
+ 	.global apuinfo2
+ apuinfo2:	
+ 	evstdd 29,8(1)
+ 	mfbbear 29
+ 	mfpmr   29, 27
+ 	dcbtstls 1, 29, 28
+ 	rfmci

Index: ld/testsuite/ld-powerpc/apuinfo.rd
===================================================================
RCS file: ld/testsuite/ld-powerpc/apuinfo.rd
diff -N ld/testsuite/ld-powerpc/apuinfo.rd
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-powerpc/apuinfo.rd	3 Dec 2002 18:10:58 -0000
***************
*** 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 .........@......


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]