This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
ppc apuinfo processing
- From: Nathan Sidwell <nathan at codesourcery dot com>
- To: binutils <binutils at sources dot redhat dot com>
- Date: Fri, 05 Feb 2010 11:45:13 +0000
- Subject: ppc apuinfo processing
Hi,
I met a toolchain that emitted empty apuinfo sections (all header, no data), and
these are currently rejected by bfd. I couldn't see anything in the apuinfo ABI
documentation indicating this is an error, so it seems best to allow it.
While working on that, I noticed the apuinfo processing being done is rather
baroque. We scan the input apusections and then allocate one big buffer to
concatenate them into. We then read them one at a time, appending to this
buffer and processing each as we go. Then we throw the buffer away. That seems
less than optimal :)
So this patch scans the input sections only once, reusing a temporary buffer for
each input section -- in addition to allowing empty apuinfo sections.
I added a dummy apuinfo case to the testsuite, to make sure it is correctly ignored.
built and tested for powerpc-eabi, ok?
nathan
--
Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery
2010-02-05 Nathan Sidwell <nathan@codesourcery.com>
bfd/
* elf32-ppc.c (ppc_elf_begin_write_processing): Allow empty
apuinfo sections, only scan input sections once and reuse the
buffer.
ld/testsuite/
* ld-powerpc/apuinfo-nul.s: New.
* ld-powerpc/apuinfo.rd: Add it.
* ld-powerpc/powerpc.exp: Likewise.
Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.275
diff -c -3 -p -r1.275 elf32-ppc.c
*** bfd/elf32-ppc.c 4 Feb 2010 09:16:39 -0000 1.275
--- bfd/elf32-ppc.c 5 Feb 2010 11:38:20 -0000
*************** ppc_elf_begin_write_processing (bfd *abf
*** 2159,2281 ****
{
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;
if (link_info == NULL)
return;
- /* 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->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->size;
! if (length < 24)
{
! error_message = _("corrupt or empty %s section in %B");
! 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 %B");
goto fail;
}
- /* Process the contents of the section. */
- ptr = buffer + offset;
- error_message = _("corrupt %s section in %B");
-
/* 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 bytes used for apuinfo entries. */
! datum = bfd_get_32 (ibfd, ptr + 4);
if (datum + 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 += 4)
! apuinfo_list_add (bfd_get_32 (ibfd, ptr + 20 + i));
!
! /* 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 %B");
fail:
! free (buffer);
if (error_message)
(*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
--- 2159,2250 ----
{
bfd *ibfd;
asection *asec;
! char *buffer = NULL;
! bfd_size_type largest_input_size = 0;
unsigned i;
unsigned num_entries;
unsigned long length;
const char *error_message = NULL;
if (link_info == NULL)
return;
apuinfo_list_init ();
/* Read in the input sections contents. */
for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
{
unsigned long datum;
asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME);
if (asec == NULL)
continue;
+ error_message = _("corrupt %s section in %B");
length = asec->size;
! if (length < 20)
! goto fail;
!
! if (largest_input_size < asec->size)
{
! if (buffer)
! free (buffer);
! largest_input_size = asec->size;
! buffer = bfd_malloc (largest_input_size);
! if (!buffer)
! return;
}
!
if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0
! || (bfd_bread (buffer, length, ibfd) != length))
{
error_message = _("unable to read in %s section from %B");
goto fail;
}
/* 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, buffer);
if (datum != sizeof APUINFO_LABEL)
goto fail;
! datum = bfd_get_32 (ibfd, buffer + 8);
if (datum != 0x2)
goto fail;
! if (strcmp (buffer + 12, APUINFO_LABEL) != 0)
goto fail;
/* Get the number of bytes used for apuinfo entries. */
! datum = bfd_get_32 (ibfd, buffer + 4);
if (datum + 20 != length)
goto fail;
/* Scan the apuinfo section, building a list of apuinfo numbers. */
for (i = 0; i < datum; i += 4)
! apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i));
}
error_message = NULL;
/* Compute the size of the output section. */
num_entries = apuinfo_list_length ();
! if (num_entries)
! {
! /* Set the output section size, if it exists. */
! asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
! if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4))
! {
! ibfd = abfd;
! error_message = _("warning: unable to set size of %s section in %B");
! }
! }
fail:
! if (buffer)
! free (buffer);
if (error_message)
(*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
Index: ld/testsuite/ld-powerpc/apuinfo-nul.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/apuinfo-nul.s
diff -N ld/testsuite/ld-powerpc/apuinfo-nul.s
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-powerpc/apuinfo-nul.s 5 Feb 2010 11:38:20 -0000
***************
*** 0 ****
--- 1,10 ----
+ .text
+ nop
+
+ # dummy empty apuinfo
+ # some other tools emit these
+ .section ".PPC.EMB.apuinfo"
+ .long 8
+ .long 0
+ .long 2
+ .asciz "APUinfo"
Index: ld/testsuite/ld-powerpc/apuinfo.rd
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/apuinfo.rd,v
retrieving revision 1.3
diff -c -3 -p -r1.3 apuinfo.rd
*** ld/testsuite/ld-powerpc/apuinfo.rd 16 Mar 2005 21:52:47 -0000 1.3
--- ld/testsuite/ld-powerpc/apuinfo.rd 5 Feb 2010 11:38:20 -0000
***************
*** 1,5 ****
--- 1,6 ----
#source: apuinfo1.s
#source: apuinfo2.s
+ #source: apuinfo-nul.s
#as: -me500
#readelf: -x2
#target: powerpc-eabi*
Index: ld/testsuite/ld-powerpc/powerpc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/powerpc.exp,v
retrieving revision 1.29
diff -c -3 -p -r1.29 powerpc.exp
*** ld/testsuite/ld-powerpc/powerpc.exp 21 Sep 2009 11:51:02 -0000 1.29
--- ld/testsuite/ld-powerpc/powerpc.exp 5 Feb 2010 11:38:20 -0000
*************** set ppcelftests {
*** 101,107 ****
{"Reloc section order" "-melf32ppc -shared -z nocombreloc" "-a32" {reloc.s}
{{objdump -hw reloc.d}} "reloc.so"}
{"APUinfo section processing" "-melf32ppc"
! "-a32 -me500" {apuinfo1.s apuinfo2.s}
{{readelf -x2 apuinfo.rd}} "apuinfo"}
{"TLS32 static exec" "-melf32ppc" "-a32" {tls32.s tlslib32.s}
{{objdump -dr tls32.d} {objdump -sj.got tls32.g}
--- 101,107 ----
{"Reloc section order" "-melf32ppc -shared -z nocombreloc" "-a32" {reloc.s}
{{objdump -hw reloc.d}} "reloc.so"}
{"APUinfo section processing" "-melf32ppc"
! "-a32 -me500" {apuinfo1.s apuinfo-nul.s apuinfo2.s}
{{readelf -x2 apuinfo.rd}} "apuinfo"}
{"TLS32 static exec" "-melf32ppc" "-a32" {tls32.s tlslib32.s}
{{objdump -dr tls32.d} {objdump -sj.got tls32.g}