===================================================================
@@ -664,7 +664,7 @@ void
nios2_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
{
fprintf (file, "\tmov\tr8, ra\n");
- if (flag_pic)
+ if (flag_pic == 1)
{
fprintf (file, "\tnextpc\tr2\n");
fprintf (file, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
@@ -673,6 +673,18 @@ nios2_function_profiler (FILE *file, int labelno A
fprintf (file, "\tldw\tr2, %%call(_mcount)(r2)\n");
fprintf (file, "\tcallr\tr2\n");
}
+ else if (flag_pic == 2)
+ {
+ fprintf (file, "\tnextpc\tr2\n");
+ fprintf (file, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
+ fprintf (file, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n");
+ fprintf (file, "\tadd\tr2, r2, r3\n");
+ fprintf (file, "\tmovhi\tr3, %%call_hiadj(_mcount)\n");
+ fprintf (file, "\taddi\tr3, %%call_lo(_mcount)\n");
+ fprintf (file, "\tadd\tr3, r2, r3\n");
+ fprintf (file, "\tldw\tr2, 0(r3)\n");
+ fprintf (file, "\tcallr\tr2\n");
+ }
else
fprintf (file, "\tcall\t_mcount\n");
fprintf (file, "\tmov\tra, r8\n");
@@ -920,7 +932,7 @@ nios2_handle_custom_fpu_cfg (const char *cfgname,
}
else
warning (0, "ignoring unrecognized switch %<-mcustom-fpu-cfg%> "
- "value %<%s%>", cfg);
+ "value %<%s%>", cfgname);
/* Guard against errors in the standard configurations. */
nios2_custom_check_insns ();
@@ -1116,20 +1128,64 @@ nios2_call_tls_get_addr (rtx ti)
return ret;
}
+/* Return true for large offsets requiring hiadj/lo relocation pairs. */
+static bool
+nios2_large_offset_p (int unspec)
+{
+ gcc_assert (nios2_unspec_reloc_name (unspec) != NULL);
+
+ if (flag_pic == 2
+ /* FIXME: TLS GOT offset relocations will eventually also get this
+ treatment, after binutils support for those are also completed. */
+ && (unspec == UNSPEC_PIC_SYM || unspec == UNSPEC_PIC_CALL_SYM))
+ return true;
+
+ /* 'gotoff' offsets are always hiadj/lo. */
+ if (unspec == UNSPEC_PIC_GOTOFF_SYM)
+ return true;
+
+ return false;
+}
+
+/* Return true for conforming unspec relocations. Also used in
+ constraints.md and predicates.md. */
+bool
+nios2_unspec_reloc_p (rtx op)
+{
+ return (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == UNSPEC
+ && ! nios2_large_offset_p (XINT (XEXP (op, 0), 1)));
+}
+
+/* Helper to generate unspec constant. */
static rtx
-nios2_unspec_address (rtx loc, rtx base_reg, int unspec)
+nios2_unspec_offset (rtx loc, int unspec)
{
- rtx unspec_offset =
- gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc),
- unspec));
- return gen_rtx_PLUS (Pmode, base_reg, unspec_offset);
+ return gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc),
+ unspec));
}
+/* Generate GOT pointer based address with large offset. */
static rtx
+nios2_large_got_address (rtx sym, rtx offset)
+{
+ rtx addr = gen_reg_rtx (Pmode);
+ emit_insn (gen_add3_insn (addr, pic_offset_table_rtx,
+ force_reg (Pmode, offset)));
+ return addr;
+}
+
+/* Generate a GOT pointer based address. */
+static rtx
nios2_got_address (rtx loc, int unspec)
{
+ rtx offset = nios2_unspec_offset (loc, unspec);
crtl->uses_pic_offset_table = 1;
- return nios2_unspec_address (loc, pic_offset_table_rtx, unspec);
+
+ if (nios2_large_offset_p (unspec))
+ return nios2_large_got_address (loc, offset);
+
+ return gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset);
}
/* Generate the code to access LOC, a thread local SYMBOL_REF. The
@@ -1151,8 +1207,8 @@ nios2_legitimize_tls_address (rtx loc)
case TLS_MODEL_LOCAL_DYNAMIC:
tmp = gen_reg_rtx (Pmode);
emit_move_insn (tmp, nios2_got_address (loc, UNSPEC_ADD_TLS_LDM));
- return nios2_unspec_address (loc, nios2_call_tls_get_addr (tmp),
- UNSPEC_ADD_TLS_LDO);
+ return gen_rtx_PLUS (Pmode, nios2_call_tls_get_addr (tmp),
+ nios2_unspec_offset (loc, UNSPEC_ADD_TLS_LDO));
case TLS_MODEL_INITIAL_EXEC:
tmp = gen_reg_rtx (Pmode);
@@ -1163,8 +1219,8 @@ nios2_legitimize_tls_address (rtx loc)
case TLS_MODEL_LOCAL_EXEC:
tp = gen_rtx_REG (Pmode, TP_REGNO);
- return nios2_unspec_address (loc, tp, UNSPEC_ADD_TLS_LE);
-
+ return gen_rtx_PLUS (Pmode, tp,
+ nios2_unspec_offset (loc, UNSPEC_ADD_TLS_LE));
default:
gcc_unreachable ();
}
@@ -1599,7 +1655,16 @@ nios2_section_type_flags (tree decl, const char *n
return flags;
}
+/* Return true if SYMBOL_REF X binds locally. */
+static bool
+nios2_symbol_binds_local_p (const_rtx x)
+{
+ return (SYMBOL_REF_DECL (x)
+ ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
+ : SYMBOL_REF_LOCAL_P (x));
+}
+
/* Position independent code related. */
/* Emit code to load the PIC register. */
@@ -1616,8 +1681,13 @@ nios2_load_pic_register (void)
static rtx
nios2_load_pic_address (rtx sym, int unspec)
{
- rtx gotaddr = nios2_got_address (sym, unspec);
- return gen_const_mem (Pmode, gotaddr);
+ if (flag_pic == 2
+ && GET_CODE (sym) == SYMBOL_REF
+ && nios2_symbol_binds_local_p (sym))
+ /* Under -fPIC, generate a GOTOFF address for local symbols. */
+ return nios2_got_address (sym, UNSPEC_PIC_GOTOFF_SYM);
+
+ return gen_const_mem (Pmode, nios2_got_address (sym, unspec));
}
/* Nonzero if the constant value X is a legitimate general operand
@@ -1626,6 +1696,11 @@ nios2_load_pic_address (rtx sym, int unspec)
bool
nios2_legitimate_pic_operand_p (rtx x)
{
+ if (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == UNSPEC
+ && nios2_large_offset_p (XINT (XEXP (x, 0), 1)))
+ return true;
+
return ! (GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == LABEL_REF || GET_CODE (x) == CONST);
}
@@ -1701,7 +1776,7 @@ nios2_legitimize_address (rtx x, rtx oldx ATTRIBUT
rtx unspec, offset, reg = XEXP (x, 0);
split_const (XEXP (x, 1), &unspec, &offset);
if (GET_CODE (unspec) == UNSPEC
- && nios2_unspec_reloc_name (XINT (unspec, 1)) != NULL
+ && !nios2_large_offset_p (XINT (unspec, 1))
&& offset != const0_rtx)
{
unspec = copy_rtx (unspec);
@@ -1728,7 +1803,8 @@ nios2_emit_move_sequence (rtx *operands, enum mach
}
if (GET_CODE (from) == SYMBOL_REF || GET_CODE (from) == LABEL_REF
- || GET_CODE (from) == CONST)
+ || (GET_CODE (from) == CONST
+ && GET_CODE (XEXP (from, 0)) != UNSPEC))
from = nios2_legitimize_constant_address (from);
operands[0] = to;
@@ -1845,20 +1921,23 @@ nios2_print_operand (FILE *file, rtx op, int lette
output_addr_const (file, op);
return;
}
- else if (letter == 'H')
- {
- fprintf (file, "%%hiadj(");
+ else if (letter == 'H' || letter == 'L')
+ {
+ fprintf (file, "%%");
+ if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == UNSPEC)
+ {
+ rtx unspec = XEXP (op, 0);
+ int unspec_reloc = XINT (unspec, 1);
+ gcc_assert (nios2_large_offset_p (unspec_reloc));
+ fprintf (file, "%s_", nios2_unspec_reloc_name (unspec_reloc));
+ op = XVECEXP (unspec, 0, 0);
+ }
+ fprintf (file, letter == 'H' ? "hiadj(" : "lo(");
output_addr_const (file, op);
fprintf (file, ")");
return;
- }
- else if (letter == 'L')
- {
- fprintf (file, "%%lo(");
- output_addr_const (file, op);
- fprintf (file, ")");
- return;
- }
+ }
break;
case SUBREG:
@@ -1910,6 +1989,8 @@ nios2_unspec_reloc_name (int unspec)
return "got";
case UNSPEC_PIC_CALL_SYM:
return "call";
+ case UNSPEC_PIC_GOTOFF_SYM:
+ return "gotoff";
case UNSPEC_LOAD_TLS_IE:
return "tls_ie";
case UNSPEC_ADD_TLS_LE:
@@ -1925,16 +2006,6 @@ nios2_unspec_reloc_name (int unspec)
}
}
-/* Return true for conforming unspec relocations. Also used in
- constraints.md and predicates.md. */
-bool
-nios2_unspec_reloc_p (rtx op)
-{
- return (GET_CODE (op) == CONST
- && GET_CODE (XEXP (op, 0)) == UNSPEC
- && nios2_unspec_reloc_name (XINT (XEXP (op, 0), 1)) != NULL);
-}
-
/* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */
static bool
nios2_output_addr_const_extra (FILE *file, rtx op)
===================================================================
@@ -73,6 +73,7 @@
UNSPEC_LOAD_GOT_REGISTER
UNSPEC_PIC_SYM
UNSPEC_PIC_CALL_SYM
+ UNSPEC_PIC_GOTOFF_SYM
UNSPEC_TLS
UNSPEC_TLS_LDM
UNSPEC_LOAD_TLS_IE
===================================================================
@@ -0,0 +1,67 @@
+/* Check that the GOT pointer is being initialized correctly to allow
+ access to the full 64K maximum GOT size for -fpic, rather than only 32K
+ (which would happen if the GOT pointer points to the base of the GOT,
+ as the GOT16 and CALL16 relocations are signed). */
+
+/* { dg-options "-fpic" } */
+/* { dg-do run { target nios2-*-linux-gnu } } */
+
+extern void abort (void);
+
+static int n = 0;
+
+void
+doit (int m)
+{
+ if (m != n)
+ abort ();
+ n++;
+}
+
+#define X(N) \
+ void f_##N (void) { doit (0x##N); }
+
+#define F(N) f_##N ();
+
+#define A(N) \
+ X(N##0) X(N##1) X(N##2) X(N##3) X(N##4) X(N##5) X(N##6) X(N##7) \
+ X(N##8) X(N##9) X(N##a) X(N##b) X(N##c) X(N##d) X(N##e) X(N##f) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \
+ F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \
+ }
+
+#define B(N) \
+ A(N##0) A(N##1) A(N##2) A(N##3) A(N##4) A(N##5) A(N##6) A(N##7) \
+ A(N##8) A(N##9) A(N##a) A(N##b) A(N##c) A(N##d) A(N##e) A(N##f) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \
+ F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \
+ }
+
+#define C(N) \
+ B(N##0) B(N##1) B(N##2) B(N##3) B(N##4) B(N##5) B(N##6) B(N##7) \
+ B(N##8) B(N##9) B(N##a) B(N##b) B(N##c) B(N##d) B(N##e) B(N##f) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \
+ F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \
+ }
+
+#define D(N) \
+ C(N##0) C(N##1) C(N##2) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) \
+ }
+
+/* This defines 16x16x16x3 leaf functions, requiring something over
+ 48K of GOT space overall. */
+D(0)
+
+int
+main (void)
+{
+ f_0 ();
+ if (n != 16*16*16*3)
+ abort ();
+ return 0;
+}
===================================================================
@@ -0,0 +1,68 @@
+/* Check that a program that requires large-GOT support builds and
+ executes without error. This program defines a very large number
+ of leaf functions; compiled with -fPIC, they all require GOT
+ entries, which will overflow the range addressible by 16-bit -fpic
+ offsets by about a factor of 2. */
+
+/* { dg-options "-fPIC" } */
+/* { dg-do run { target nios2-*-linux-gnu } } */
+
+extern void abort (void);
+
+static int n = 0;
+
+void
+doit (int m)
+{
+ if (m != n)
+ abort ();
+ n++;
+}
+
+#define X(N) \
+ void f_##N (void) { doit (0x##N); }
+
+#define F(N) f_##N ();
+
+#define A(N) \
+ X(N##0) X(N##1) X(N##2) X(N##3) X(N##4) X(N##5) X(N##6) X(N##7) \
+ X(N##8) X(N##9) X(N##a) X(N##b) X(N##c) X(N##d) X(N##e) X(N##f) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \
+ F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \
+ }
+
+#define B(N) \
+ A(N##0) A(N##1) A(N##2) A(N##3) A(N##4) A(N##5) A(N##6) A(N##7) \
+ A(N##8) A(N##9) A(N##a) A(N##b) A(N##c) A(N##d) A(N##e) A(N##f) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \
+ F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \
+ }
+
+#define C(N) \
+ B(N##0) B(N##1) B(N##2) B(N##3) B(N##4) B(N##5) B(N##6) B(N##7) \
+ B(N##8) B(N##9) B(N##a) B(N##b) B(N##c) B(N##d) B(N##e) B(N##f) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \
+ F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \
+ }
+
+#define D(N) \
+ C(N##0) C(N##1) C(N##2) C(N##3) C(N##4) C(N##5) C(N##6) C(N##7) \
+ void f_##N (void) { \
+ F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \
+ }
+
+/* This defines 16x16x16x8 leaf functions, requiring something over
+ 128K of GOT space overall. */
+D(0)
+
+int
+main (void)
+{
+ f_0 ();
+ if (n != 16*16*16*8)
+ abort ();
+ return 0;
+}
===================================================================
@@ -36,8 +36,6 @@ see the files COPYING3 and COPYING.RUNTIME respect
See crt0.s for the code that calls init and fini. */
- .file "crti.asm"
-
.section ".init"
.align 2
.global _init
===================================================================
@@ -23,13 +23,9 @@ see the files COPYING3 and COPYING.RUNTIME respect
/* This file just makes sure that the .fini and .init sections do in
-fact return. Users may put any desired instructions in those sections.
-This file is the last thing linked into any executable.
-*/
- .file "crtn.asm"
+ fact return. Users may put any desired instructions in those sections.
+ This file is the last thing linked into any executable. */
-
-
.section ".init"
ldw ra, 44(sp)
ldw r23, 40(sp)
===================================================================
@@ -3,3 +3,6 @@ LIB2ADD += $(srcdir)/config/nios2/lib2-divmod.c \
$(srcdir)/config/nios2/lib2-divtable.c \
$(srcdir)/config/nios2/lib2-mul.c \
$(srcdir)/config/nios2/tramp.c
+
+# Disable use of GP-relative addressing in startup code.
+CRTSTUFF_T_CFLAGS += -mno-gpopt