This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
record Xtensa configuration info in ELF files
- From: Bob Wilson <bwilson at tensilica dot com>
- To: binutils at sources dot redhat dot com
- Date: Mon, 27 Nov 2006 12:15:00 -0800
- Subject: record Xtensa configuration info in ELF files
Add a new .xtensa.info note section to ELF files generated by GAS and LD to
record some Xtensa configuration information, currently the ABI and the Extended
L32R option. The linker uses this information to check for incompatible files
being linked together. I had to add a new expected output file for the
gas/elf/section2 test, but with that change, all the tests pass. Committed on
the mainline.
bfd/
* elf32-xtensa.c (elf_xtensa_special_sections): Add .xtensa.info.
gas/
* config/tc-xtensa.c (XSHAL_ABI): Add default definition.
(directive_state): Disable scheduling by default.
(xtensa_add_config_info): New.
(xtensa_end): Call xtensa_add_config_info.
gas/testsuite/
* gas/elf/section2.e-xtensa: New file.
* gas/elf/elf.exp: Use it.
include/
* xtensa-config.h (XSHAL_ABI): New.
(XTHAL_ABI_WINDOWED, XTHAL_ABI_CALL0): New.
ld/
* emultempl/xtensaelf.em (XSHAL_ABI): Add default definition.
(replace_insn_sec_with_prop_sec): Use bfd_make_section_with_flags.
Delete redundant code to set sections flags and alignment.
(xt_config_info_unpack_and_check, check_xtensa_info): New.
(elf_xtensa_after_open): Iterate over input statements instead of
link_info.input_bfds.
(elf_xtensa_before_allocation): Likewise. Call check_xtensa_info for
each input, and write a new .xtensa.info section in the output.
Index: bfd/elf32-xtensa.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-xtensa.c,v
retrieving revision 1.75
diff -u -p -r1.75 elf32-xtensa.c
--- bfd/elf32-xtensa.c 3 Nov 2006 00:58:09 -0000 1.75
+++ bfd/elf32-xtensa.c 27 Nov 2006 19:31:32 -0000
@@ -9801,6 +9801,7 @@ static const struct bfd_elf_special_sect
{ STRING_COMMA_LEN (".fini.literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
{ STRING_COMMA_LEN (".init.literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
{ STRING_COMMA_LEN (".literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".xtensa.info"), 0, SHT_NOTE, 0 },
{ NULL, 0, 0, 0, 0 }
};
Index: gas/config/tc-xtensa.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.c,v
retrieving revision 1.70
diff -u -p -r1.70 tc-xtensa.c
--- gas/config/tc-xtensa.c 25 Aug 2006 19:59:31 -0000 1.70
+++ gas/config/tc-xtensa.c 27 Nov 2006 19:31:35 -0000
@@ -30,6 +30,11 @@
#include "struc-symbol.h"
#include "xtensa-config.h"
+/* Provide default values for new configuration settings. */
+#ifndef XSHAL_ABI
+#define XSHAL_ABI 0
+#endif
+
#ifndef uint32
#define uint32 unsigned int
#endif
@@ -396,7 +401,7 @@ bfd_boolean directive_state[] =
FALSE, /* freeregs */
FALSE, /* longcalls */
FALSE, /* literal_prefix */
- TRUE, /* schedule */
+ FALSE, /* schedule */
#if XSHAL_USE_ABSOLUTE_LITERALS
TRUE /* absolute_literals */
#else
@@ -6859,6 +6864,7 @@ static void xtensa_fix_b_j_loop_end_frag
static void xtensa_fix_close_loop_end_frags (void);
static void xtensa_fix_short_loop_frags (void);
static void xtensa_sanity_check (void);
+static void xtensa_add_config_info (void);
void
xtensa_end (void)
@@ -6889,6 +6895,8 @@ xtensa_end (void)
xtensa_mark_zcl_first_insns ();
xtensa_sanity_check ();
+
+ xtensa_add_config_info ();
}
@@ -7797,6 +7805,55 @@ is_local_forward_loop (const TInsn *insn
return FALSE;
}
+
+#define XTINFO_NAME "Xtensa_Info"
+#define XTINFO_NAMESZ 12
+#define XTINFO_TYPE 1
+
+static void
+xtensa_add_config_info (void)
+{
+ asection *info_sec;
+ char *data, *p;
+ int sz;
+
+ info_sec = subseg_new (".xtensa.info", 0);
+ bfd_set_section_flags (stdoutput, info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
+
+ data = xmalloc (100);
+ sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
+ XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
+ sz = strlen (data) + 1;
+
+ /* Add enough null terminators to pad to a word boundary. */
+ do
+ data[sz++] = 0;
+ while ((sz & 3) != 0);
+
+ /* Follow the standard note section layout:
+ First write the length of the name string. */
+ p = frag_more (4);
+ md_number_to_chars (p, (valueT) XTINFO_NAMESZ, 4);
+
+ /* Next comes the length of the "descriptor", i.e., the actual data. */
+ p = frag_more (4);
+ md_number_to_chars (p, (valueT) sz, 4);
+
+ /* Write the note type. */
+ p = frag_more (4);
+ md_number_to_chars (p, (valueT) XTINFO_TYPE, 4);
+
+ /* Write the name field. */
+ p = frag_more (XTINFO_NAMESZ);
+ memcpy (p, XTINFO_NAME, XTINFO_NAMESZ);
+
+ /* Finally, write the descriptor. */
+ p = frag_more (sz);
+ memcpy (p, data, sz);
+
+ free (data);
+}
+
/* Alignment Functions. */
Index: gas/testsuite/gas/elf/elf.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/elf/elf.exp,v
retrieving revision 1.34
diff -u -p -r1.34 elf.exp
--- gas/testsuite/gas/elf/elf.exp 22 Nov 2006 17:45:56 -0000 1.34
+++ gas/testsuite/gas/elf/elf.exp 27 Nov 2006 19:31:35 -0000
@@ -53,6 +53,9 @@ if { ([istarget "*-*-*elf*"]
if {[istarget "score-*-*"]} then {
set target_machine -score
}
+ if {[istarget "xtensa-*-*"]} then {
+ set target_machine -xtensa
+ }
if { ([istarget "*arm*-*-*"]
|| [istarget "xscale*-*-*"]) } {
--- /dev/null 2006-05-30 18:33:22.000000000 -0700
+++ gas/testsuite/gas/elf/section2.e-xtensa 2006-11-22 14:59:55.000000000 -0800
@@ -0,0 +1,9 @@
+
+Symbol table '.symtab' contains 6 entries:
+ Num: Value[ ]* Size Type Bind Vis Ndx Name
+ 0: 0+0 0 NOTYPE LOCAL DEFAULT UND
+ 1: 0+0 0 SECTION LOCAL DEFAULT 1
+ 2: 0+0 0 SECTION LOCAL DEFAULT 2
+ 3: 0+0 0 SECTION LOCAL DEFAULT 3
+ 4: 0+0 0 SECTION LOCAL DEFAULT 4
+ 5: 0+0 0 SECTION LOCAL DEFAULT 5
Index: include/xtensa-config.h
===================================================================
RCS file: /cvs/src/src/include/xtensa-config.h,v
retrieving revision 1.8
diff -u -p -r1.8 xtensa-config.h
--- include/xtensa-config.h 9 Jan 2006 23:47:37 -0000 1.8
+++ include/xtensa-config.h 27 Nov 2006 19:31:35 -0000
@@ -1,5 +1,6 @@
/* Xtensa configuration settings.
- Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This program is free software; you can redistribute it and/or modify
@@ -145,4 +146,12 @@
#undef XCHAL_INST_FETCH_WIDTH
#define XCHAL_INST_FETCH_WIDTH 4
+
+#undef XSHAL_ABI
+#undef XTHAL_ABI_WINDOWED
+#undef XTHAL_ABI_CALL0
+#define XSHAL_ABI XTHAL_ABI_WINDOWED
+#define XTHAL_ABI_WINDOWED 0
+#define XTHAL_ABI_CALL0 1
+
#endif /* !XTENSA_CONFIG_H */
Index: ld/emultempl/xtensaelf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/xtensaelf.em,v
retrieving revision 1.16
diff -u -p -r1.16 xtensaelf.em
--- ld/emultempl/xtensaelf.em 12 Oct 2006 21:56:19 -0000 1.16
+++ ld/emultempl/xtensaelf.em 27 Nov 2006 19:31:36 -0000
@@ -16,7 +16,8 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301 USA.
#
# This file is sourced from elf32.em, and defines extra xtensa-elf
@@ -30,6 +31,11 @@ cat >>e${EMULATION_NAME}.c <<EOF
#include "elf/xtensa.h"
#include "bfd.h"
+/* Provide default values for new configuration settings. */
+#ifndef XSHAL_ABI
+#define XSHAL_ABI 0
+#endif
+
static void xtensa_wild_group_interleave (lang_statement_union_type *);
static void xtensa_colocate_output_literals (lang_statement_union_type *);
static void xtensa_strip_inconsistent_linkonce_sections
@@ -128,25 +134,17 @@ replace_insn_sec_with_prop_sec (bfd *abf
}
}
- /* Create a Property table section and relocation section for it. */
+ /* Create a property table section for it. */
prop_sec_name = strdup (prop_sec_name);
- prop_sec = bfd_make_section (abfd, prop_sec_name);
+ prop_sec = bfd_make_section_with_flags
+ (abfd, prop_sec_name, bfd_get_section_flags (abfd, insn_sec));
if (prop_sec == NULL
- || ! bfd_set_section_flags (abfd, prop_sec,
- bfd_get_section_flags (abfd, insn_sec))
|| ! bfd_set_section_alignment (abfd, prop_sec, 2))
{
*error_message = _("could not create new section");
goto cleanup;
}
- if (! bfd_set_section_flags (abfd, prop_sec,
- bfd_get_section_flags (abfd, insn_sec))
- || ! bfd_set_section_alignment (abfd, prop_sec, 2))
- {
- *error_message = _("could not set new section properties");
- goto cleanup;
- }
prop_sec->size = entry_count * 12;
prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size);
elf_section_data (prop_sec)->this_hdr.contents = prop_contents;
@@ -297,17 +295,13 @@ replace_instruction_table_sections (bfd
static void
elf_xtensa_after_open (void)
{
- bfd *abfd;
-
/* First call the ELF version. */
gld${EMULATION_NAME}_after_open ();
/* Now search the input files looking for instruction table sections. */
- for (abfd = link_info.input_bfds;
- abfd != NULL;
- abfd = abfd->link_next)
+ LANG_FOR_EACH_INPUT_STATEMENT (f)
{
- asection *sec = abfd->sections;
+ asection *sec = f->the_bfd->sections;
asection *next_sec;
/* Do not use bfd_map_over_sections here since we are removing
@@ -315,20 +309,122 @@ elf_xtensa_after_open (void)
while (sec != NULL)
{
next_sec = sec->next;
- replace_instruction_table_sections (abfd, sec);
+ replace_instruction_table_sections (f->the_bfd, sec);
sec = next_sec;
}
}
}
+static bfd_boolean
+xt_config_info_unpack_and_check (char *data,
+ bfd_boolean *pmismatch,
+ char **pmsg)
+{
+ char *d, *key;
+ unsigned num;
+
+ *pmismatch = FALSE;
+
+ d = data;
+ while (*d)
+ {
+ key = d;
+ d = strchr (d, '=');
+ if (! d)
+ goto error;
+
+ /* Overwrite the equal sign. */
+ *d++ = 0;
+
+ /* Check if this is a quoted string or a number. */
+ if (*d == '"')
+ {
+ /* No string values are currently checked by LD;
+ just skip over the quotes. */
+ d++;
+ d = strchr (d, '"');
+ if (! d)
+ goto error;
+ /* Overwrite the trailing quote. */
+ *d++ = 0;
+ }
+ else
+ {
+ if (*d == 0)
+ goto error;
+ num = strtoul (d, &d, 0);
+
+ if (! strcmp (key, "ABI"))
+ {
+ if (num != XSHAL_ABI)
+ {
+ *pmismatch = TRUE;
+ *pmsg = "ABI does not match";
+ }
+ }
+ else if (! strcmp (key, "USE_ABSOLUTE_LITERALS"))
+ {
+ if (num != XSHAL_USE_ABSOLUTE_LITERALS)
+ {
+ *pmismatch = TRUE;
+ *pmsg = "incompatible use of the Extended L32R option";
+ }
+ }
+ }
+
+ if (*d++ != '\n')
+ goto error;
+ }
+
+ return TRUE;
+
+ error:
+ return FALSE;
+}
+
+
+#define XTINFO_NAME "Xtensa_Info"
+#define XTINFO_NAMESZ 12
+#define XTINFO_TYPE 1
+
+static void
+check_xtensa_info (bfd *abfd, asection *info_sec)
+{
+ char *data, *errmsg = "";
+ bfd_boolean mismatch;
+
+ data = xmalloc (info_sec->size);
+ if (! bfd_get_section_contents (abfd, info_sec, data, 0, info_sec->size))
+ einfo (_("%F%P:%B: cannot read contents of section %A\n"), abfd, info_sec);
+
+ if (info_sec->size > 24
+ && info_sec->size >= 24 + bfd_get_32 (abfd, data + 4)
+ && bfd_get_32 (abfd, data + 0) == XTINFO_NAMESZ
+ && bfd_get_32 (abfd, data + 8) == XTINFO_TYPE
+ && strcmp (data + 12, XTINFO_NAME) == 0
+ && xt_config_info_unpack_and_check (data + 12 + XTINFO_NAMESZ,
+ &mismatch, &errmsg))
+ {
+ if (mismatch)
+ einfo (_("%P:%B: warning: incompatible Xtensa configuration (%s)\n"),
+ abfd, errmsg);
+ }
+ else
+ einfo (_("%P:%B: warning: cannot parse .xtensa.info section\n"), abfd);
+
+ free (data);
+}
+
+
/* This is called after the sections have been attached to output
sections, but before any sizes or addresses have been set. */
static void
elf_xtensa_before_allocation (void)
{
- bfd *in_bfd;
+ asection *info_sec, *first_info_sec;
+ bfd *first_bfd;
bfd_boolean is_big_endian = XCHAL_HAVE_BE;
/* Check that the output endianness matches the Xtensa
@@ -349,18 +445,80 @@ elf_xtensa_before_allocation (void)
"Xtensa configuration\n"));
}
- /* Check that the endianness for each input file matches the output.
- The merge_private_bfd_data hook has already reported any mismatches
- as errors, but those errors are not fatal. At this point, we
- cannot go any further if there are any mismatches. */
-
- for (in_bfd = link_info.input_bfds;
- in_bfd != NULL;
- in_bfd = in_bfd->link_next)
- {
- if ((is_big_endian && in_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
- || (!is_big_endian && in_bfd->xvec->byteorder == BFD_ENDIAN_BIG))
- einfo (_("%F%P: cross-endian linking not supported\n"));
+ /* Keep track of the first input .xtensa.info section, and as a fallback,
+ the first input bfd where a .xtensa.info section could be created.
+ After the input .xtensa.info has been checked, the contents of the
+ first one will be replaced with the output .xtensa.info table. */
+ first_info_sec = 0;
+ first_bfd = 0;
+
+ LANG_FOR_EACH_INPUT_STATEMENT (f)
+ {
+ /* Check that the endianness for each input file matches the output.
+ The merge_private_bfd_data hook has already reported any mismatches
+ as errors, but those errors are not fatal. At this point, we
+ cannot go any further if there are any mismatches. */
+ if ((is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
+ || (!is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_BIG))
+ einfo (_("%F%P: cross-endian linking for %B not supported\n"),
+ f->the_bfd);
+
+ if (! first_bfd)
+ first_bfd = f->the_bfd;
+
+ info_sec = bfd_get_section_by_name (f->the_bfd, ".xtensa.info");
+ if (! info_sec)
+ continue;
+
+ if (! first_info_sec)
+ first_info_sec = info_sec;
+
+ /* Unpack the .xtensa.info section and check it against the current
+ Xtensa configuration. */
+ check_xtensa_info (f->the_bfd, info_sec);
+
+ /* Do not include this copy of .xtensa.info in the output. */
+ info_sec->size = 0;
+ info_sec->flags |= SEC_EXCLUDE;
+ }
+
+ /* Reuse the first .xtensa.info input section to hold the output
+ .xtensa.info; or, if none were found, create a new section in the
+ first input bfd (assuming there is one). */
+ info_sec = first_info_sec;
+ if (! info_sec && first_bfd)
+ {
+ info_sec = bfd_make_section_with_flags (first_bfd, ".xtensa.info",
+ SEC_HAS_CONTENTS | SEC_READONLY);
+ if (! info_sec)
+ einfo (_("%F%P: failed to create .xtensa.info section\n"));
+ }
+ if (info_sec)
+ {
+ int xtensa_info_size;
+ char *data;
+
+ info_sec->flags &= ~SEC_EXCLUDE;
+ info_sec->flags |= SEC_IN_MEMORY;
+
+ data = xmalloc (100);
+ sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
+ XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
+ xtensa_info_size = strlen (data) + 1;
+
+ /* Add enough null terminators to pad to a word boundary. */
+ do
+ data[xtensa_info_size++] = 0;
+ while ((xtensa_info_size & 3) != 0);
+
+ info_sec->size = 12 + XTINFO_NAMESZ + xtensa_info_size;
+ info_sec->contents = xmalloc (info_sec->size);
+ bfd_put_32 (info_sec->owner, XTINFO_NAMESZ, info_sec->contents + 0);
+ bfd_put_32 (info_sec->owner, xtensa_info_size, info_sec->contents + 4);
+ bfd_put_32 (info_sec->owner, XTINFO_TYPE, info_sec->contents + 8);
+ memcpy (info_sec->contents + 12, XTINFO_NAME, XTINFO_NAMESZ);
+ memcpy (info_sec->contents + 12 + XTINFO_NAMESZ, data, xtensa_info_size);
+ free (data);
}
/* Enable relaxation by default if the "--no-relax" option was not