From e1a9cb8e15a2f05592910ee3e27dacf7fbee68b0 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 3 Dec 2002 18:24:33 +0000 Subject: Fix the merging of .PPC.EMB.apuinfo sections. Add a test to make sure that the fix continues to work. --- bfd/ChangeLog | 20 +++ bfd/elf32-ppc.c | 300 ++++++++++++++++++++++++++++++++++++ gas/ChangeLog | 5 + gas/config/tc-ppc.c | 2 +- ld/testsuite/ChangeLog | 8 + ld/testsuite/ld-powerpc/apuinfo.rd | 10 ++ ld/testsuite/ld-powerpc/apuinfo1.s | 9 ++ ld/testsuite/ld-powerpc/apuinfo2.s | 8 + ld/testsuite/ld-powerpc/powerpc.exp | 2 + ld/testsuite/ld-srec/srec.exp | 2 +- 10 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 ld/testsuite/ld-powerpc/apuinfo.rd create mode 100644 ld/testsuite/ld-powerpc/apuinfo1.s create mode 100644 ld/testsuite/ld-powerpc/apuinfo2.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 57d7ee9..c16c741 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,23 @@ +2002-12-03 Nick Clifton + + * 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 * cpu-ia64-opc.c (elf64_ia64_operands): Add ldxmov entry. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 0c33a90..c117f54 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -3783,6 +3783,303 @@ ppc_elf_grok_psinfo (abfd, note) 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 @@ -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" diff --git a/gas/ChangeLog b/gas/ChangeLog index d891166..5c59ad5 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2002-12-03 Nick Clifton + + * config/tc-ppc.c (ppc_cleanup): Do not set SEC_MERGE flag on + .PPC.EMB>apuinfo sections. + 2002-12-03 Richard Henderson * config/tc-ia64.c (operand_match): Add IA64_OPND_LDXMOV case. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 04fae38..ba058f6 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -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); diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 2f8179b..4226307 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2002-12-03 Nick Clifton + + * 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 Fix PR savannah/1417: diff --git a/ld/testsuite/ld-powerpc/apuinfo.rd b/ld/testsuite/ld-powerpc/apuinfo.rd new file mode 100644 index 0000000..421ae7d --- /dev/null +++ b/ld/testsuite/ld-powerpc/apuinfo.rd @@ -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 index 0000000..fd42eac --- /dev/null +++ b/ld/testsuite/ld-powerpc/apuinfo1.s @@ -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 index 0000000..7f4e7bb --- /dev/null +++ b/ld/testsuite/ld-powerpc/apuinfo2.s @@ -0,0 +1,8 @@ + .text + .global apuinfo2 +apuinfo2: + evstdd 29,8(1) + mfbbear 29 + mfpmr 29, 27 + dcbtstls 1, 29, 28 + rfmci diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index f52278d..a853df9 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -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 diff --git a/ld/testsuite/ld-srec/srec.exp b/ld/testsuite/ld-srec/srec.exp index d3fa764..af1ceed 100644 --- a/ld/testsuite/ld-srec/srec.exp +++ b/ld/testsuite/ld-srec/srec.exp @@ -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" -- cgit v1.1