This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] gas: xtensa: fix incorrect code generated with auto litpools
- From: Max Filippov <jcmvbkbc at gmail dot com>
- To: binutils at sourceware dot org
- Cc: Sterling Augustine <augustine dot sterling at gmail dot com>, David Weatherford <weath at cadence dot com>, Marc Gauthier <marc at cadence dot com>, linux-xtensa at linux-xtensa dot org, Max Filippov <jcmvbkbc at gmail dot com>
- Date: Wed, 5 Apr 2017 14:20:12 -0700
- Subject: [PATCH] gas: xtensa: fix incorrect code generated with auto litpools
- Authentication-results: sourceware.org; auth=none
Assembling xtensa code w/o implicit (entry instruction) or explicit
(.literal_position directive) literal pool positioning hint with
--auto-litpools option may generate incorrect code when first literal is
emitted before the first automatic literal pool. In that case literal
pool without skipping jump is created right before the literal,
potentially allowing program flow to enter literal pool.
This bug is triggered e.g. by the following xtensa softfloat code from
libgcc built for call0 ABI:
#ifdef L_negdf2
.align 4
.global __negdf2
.type __negdf2, @function
__negdf2:
leaf_entry sp, 16
movi a4, 0x80000000
xor xh, xh, a4
leaf_return
#endif /* L_negdf2 */
It turns into the following binary:
Contents of section .text:
0000 00000080 41ffff40 33300df0 ....A..@30..
Disassembly of section .text:
00000000 <__negdf2>:
0: 000000 ill
3: ff4180 excw
4: R_XTENSA_SLOT0_OP .text
6: ff .byte 0xff
7: 303340 xor a3, a3, a4
a: f00d ret.n
and it manifests itself as an illegal instruction exception happening
in __negdf2.
gas/
2017-03-31 Max Filippov <jcmvbkbc@gmail.com>
* config/tc-xtensa.c (xtensa_maybe_create_literal_pool_frag):
Initialize lps->frag_count with auto_litpool_limit.
(xg_promote_candidate_litpool): New function.
(xtensa_move_literals): Extract candidate litpool promotion code
into separate function. Call it for all possible found
candidates.
(xtensa_switch_to_literal_fragment): Drop 'recursive' flag and
call to xtensa_mark_literal_pool_location that it guards.
Replace it with call to xtensa_maybe_create_literal_pool_frag.
Initialize pool_location with created literal pool candidate.
* testsuite/gas/xtensa/all.exp: Add new tests.
* testsuite/gas/xtensa/auto-litpools-first1.d: New test results.
* testsuite/gas/xtensa/auto-litpools-first1.s: New test.
* testsuite/gas/xtensa/auto-litpools-first2.d: New test results.
* testsuite/gas/xtensa/auto-litpools-first2.s: New test.
* testsuite/gas/xtensa/auto-litpools.d: Fix offsets changed due
to additional jump instruction.
---
gas/config/tc-xtensa.c | 66 ++++++++++++++-----------
gas/testsuite/gas/xtensa/all.exp | 2 +
gas/testsuite/gas/xtensa/auto-litpools-first1.d | 12 +++++
gas/testsuite/gas/xtensa/auto-litpools-first1.s | 3 ++
gas/testsuite/gas/xtensa/auto-litpools-first2.d | 15 ++++++
gas/testsuite/gas/xtensa/auto-litpools-first2.s | 3 ++
gas/testsuite/gas/xtensa/auto-litpools.d | 6 +--
7 files changed, 75 insertions(+), 32 deletions(-)
create mode 100644 gas/testsuite/gas/xtensa/auto-litpools-first1.d
create mode 100644 gas/testsuite/gas/xtensa/auto-litpools-first1.s
create mode 100644 gas/testsuite/gas/xtensa/auto-litpools-first2.d
create mode 100644 gas/testsuite/gas/xtensa/auto-litpools-first2.s
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index c45c70d..e1efaae 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -7547,6 +7547,10 @@ xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
lps->seg = now_seg;
lps->frag_list.next = &lps->frag_list;
lps->frag_list.prev = &lps->frag_list;
+ /* Put candidate literal pool at the beginning of every section,
+ so that even when section starts with literal load there's a
+ literal pool available. */
+ lps->frag_count = auto_litpool_limit;
}
lps->frag_count++;
@@ -11035,6 +11039,30 @@ xtensa_move_seg_list_to_beginning (seg_list *head)
static void mark_literal_frags (seg_list *);
static void
+xg_promote_candidate_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lp)
+{
+ fragS *poolbeg;
+ fragS *poolend;
+ symbolS *lsym;
+ char label[10 + 2 * sizeof (fragS *)];
+
+ poolbeg = lp->fragP;
+ lp->priority = 1;
+ poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
+ poolend = poolbeg->fr_next;
+ gas_assert (poolend->fr_type == rs_machine_dependent &&
+ poolend->fr_subtype == RELAX_LITERAL_POOL_END);
+ /* Create a local symbol pointing to the
+ end of the pool. */
+ sprintf (label, ".L0_LT_%p", poolbeg);
+ lsym = (symbolS *)local_symbol_make (label, lps->seg,
+ 0, poolend);
+ poolbeg->fr_symbol = lsym;
+ /* Rest is done in xtensa_relax_frag. */
+}
+
+static void
xtensa_move_literals (void)
{
seg_list *segment;
@@ -11121,27 +11149,17 @@ xtensa_move_literals (void)
/* This is still a "candidate" but the next one
will be too far away, so revert to the nearest
one, convert it and add the jump around. */
- fragS *poolbeg;
- fragS *poolend;
- symbolS *lsym;
- char label[10 + 2 * sizeof (fragS *)];
lp = lpf->prev;
- poolbeg = lp->fragP;
- lp->priority = 1;
- poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
- poolend = poolbeg->fr_next;
- gas_assert (poolend->fr_type == rs_machine_dependent &&
- poolend->fr_subtype == RELAX_LITERAL_POOL_END);
- /* Create a local symbol pointing to the
- end of the pool. */
- sprintf (label, ".L0_LT_%p", poolbeg);
- lsym = (symbolS *)local_symbol_make (label, lps->seg,
- 0, poolend);
- poolbeg->fr_symbol = lsym;
- /* Rest is done in xtensa_relax_frag. */
+ break;
}
}
}
+
+ /* Convert candidate and add the jump around. */
+ if (lp->fragP->fr_subtype ==
+ RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ xg_promote_candidate_litpool (lps, lp);
+
if (! litfrag->tc_frag_data.literal_frag)
{
/* Take earliest use of this literal to avoid
@@ -11413,7 +11431,6 @@ xtensa_switch_to_literal_fragment (emit_state *result)
static void
xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
{
- static bfd_boolean recursive = FALSE;
fragS *pool_location = get_literal_pool_location (now_seg);
segT lit_seg;
bfd_boolean is_init =
@@ -11423,23 +11440,14 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
if (pool_location == NULL
&& !use_literal_section
- && !recursive
&& !is_init && ! is_fini)
{
if (!auto_litpools)
{
as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
}
-
- /* When we mark a literal pool location, we want to put a frag in
- the literal pool that points to it. But to do that, we want to
- switch_to_literal_fragment. But literal sections don't have
- literal pools, so their location is always null, so we would
- recurse forever. This is kind of hacky, but it works. */
-
- recursive = TRUE;
- xtensa_mark_literal_pool_location ();
- recursive = FALSE;
+ xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
+ pool_location = get_literal_pool_location (now_seg);
}
lit_seg = cache_literal_section (FALSE);
diff --git a/gas/testsuite/gas/xtensa/all.exp b/gas/testsuite/gas/xtensa/all.exp
index 98041b5..1ab3827 100644
--- a/gas/testsuite/gas/xtensa/all.exp
+++ b/gas/testsuite/gas/xtensa/all.exp
@@ -101,6 +101,8 @@ if [istarget xtensa*-*-*] then {
run_dump_test "trampoline"
run_dump_test "first_frag_align"
run_dump_test "auto-litpools"
+ run_dump_test "auto-litpools-first1"
+ run_dump_test "auto-litpools-first2"
run_dump_test "loc"
run_dump_test "init-fini-literals"
}
diff --git a/gas/testsuite/gas/xtensa/auto-litpools-first1.d b/gas/testsuite/gas/xtensa/auto-litpools-first1.d
new file mode 100644
index 0000000..322cdc5
--- /dev/null
+++ b/gas/testsuite/gas/xtensa/auto-litpools-first1.d
@@ -0,0 +1,12 @@
+#as: --auto-litpools
+#objdump: -ds
+#name: auto-litpools-first1 (check that literal pool is created when source starts with literal)
+
+.*: +file format .*xtensa.*
+#...
+Contents of section .text:
+ 0000 ........ 20170331 .*
+#...
+00000000 <f>:
+.*0:.*j.8 .*
+#...
diff --git a/gas/testsuite/gas/xtensa/auto-litpools-first1.s b/gas/testsuite/gas/xtensa/auto-litpools-first1.s
new file mode 100644
index 0000000..7ac0bf8
--- /dev/null
+++ b/gas/testsuite/gas/xtensa/auto-litpools-first1.s
@@ -0,0 +1,3 @@
+f:
+ .literal .L0, 0x20170331
+ l32r a2, .L0
diff --git a/gas/testsuite/gas/xtensa/auto-litpools-first2.d b/gas/testsuite/gas/xtensa/auto-litpools-first2.d
new file mode 100644
index 0000000..a6b798e
--- /dev/null
+++ b/gas/testsuite/gas/xtensa/auto-litpools-first2.d
@@ -0,0 +1,15 @@
+#as: --auto-litpools
+#objdump: -ds
+#name: auto-litpools-first2 (check that literal pool with jump around is created for generated literal)
+
+.*: +file format .*xtensa.*
+#...
+Contents of section .text:
+ 0000 ........ ........ 20170331 .*
+#...
+00000000 <f>:
+ 0:.*addi.*a1.*
+ 3:.*j.*c.*
+#...
+ c:.*l32r.*a2, 8.*
+#...
diff --git a/gas/testsuite/gas/xtensa/auto-litpools-first2.s b/gas/testsuite/gas/xtensa/auto-litpools-first2.s
new file mode 100644
index 0000000..c097dac
--- /dev/null
+++ b/gas/testsuite/gas/xtensa/auto-litpools-first2.s
@@ -0,0 +1,3 @@
+f:
+ addi a1, a1, -16
+ movi a2, 0x20170331
diff --git a/gas/testsuite/gas/xtensa/auto-litpools.d b/gas/testsuite/gas/xtensa/auto-litpools.d
index 4d1a690..fc6f5cb 100644
--- a/gas/testsuite/gas/xtensa/auto-litpools.d
+++ b/gas/testsuite/gas/xtensa/auto-litpools.d
@@ -4,9 +4,9 @@
.*: +file format .*xtensa.*
#...
-.*4:.*l32r.a2, 0 .*
+.*8:.*l32r.a2, 4 .*
#...
-.*3e437:.*j.3e440 .*
+.*3e43b:.*j.3e444 .*
#...
-.*40750:.*l32r.a2, 3e43c .*
+.*40754:.*l32r.a2, 3e440 .*
#...
--
2.1.4