]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
t-elf, [...]: New files.
authorAlexandre Oliva <aoliva@redhat.com>
Sat, 2 Sep 2000 03:28:47 +0000 (03:28 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Sat, 2 Sep 2000 03:28:47 +0000 (03:28 +0000)
* config/sh/t-elf, config/sh/crt1.asm, config/sh/crti.asm,
config/sh/crtn.asm: New files.
* config/sh/t-sh (EXTRA_MULTILIB_PARTS): Set.
(crt1.o, crti.o, crtn.o): New targets.
* configure.in [sh-*-elf*, sh-*-rtemself*] (tmake_file): Added
sh/t-elf.
* configure: Rebuilt.
* config/sh/sh.h (INIT_SECTION_ASM_OP, FINI_SECTION_ASM_OP,
STARTFILE_SPEC, ENDFILE_SPEC, CRT_CALL_STATIC_FUNCTION): Define.
* config/sh/elf.h (INIT_SECTION_ASM_OP, FINI_SECTION_ASM_OP):
Undefine for config/elfos.h to redefine.
(STARTFILE_SPEC, ENDFILE_SPEC): Redefine after config/elfos.h.

* config/sh/sh-protos.h (nonpic_symbol_mentioned_p,
legitimize_pic_address, output_pic_addr_const): Declare.
* config/sh/sh.h (CONDITIONAL_REGISTER_USAGE): Fix PIC register.
(PREFERGOT_BIT, TARGET_PREFERGOT): Likewise.
(TARGET_SWITCHES): New switch -mprefergot.
(OVERRIDE_OPTIONS): Set flag_no_function_cse unless -mprefergot.
(PIC_OFFSET_TABLE_REGNUM): Define.
(GOT_SYMBOL_TABLE): Likewise.
(LEGITIMIZE_ADDRESS): Use legitimize_pic_address.
(ENCODE_SECTION_INFO): Define.
(FINALIZE_PIC): New macros.
(LEGITIMATE_PIC_OPERAND_P, SYMBOLIC_CONST_P): New macro.
(ASM_OUTPUT_INT, ASM_OUTPUT_SHORT): Use output_pic_addr_const.
* config/sh/sh.c (print_operand_address): Use output_pic_addr_const.
(prepare_move_operands): Call emit_pic_move or
emit_pic_const_move if appropriate.
(output_far_jump): For PIC, use braf and output long offset.
(machine_dependent_reorg):
(sh_expand_prologue): Save and initialize the PIC register.
(sh_expand_epilogue): Restore it.
(initial_elimination_offset): Account for it.
(nonpic_symbol_mentioned_p): New function.
(legitimize_pic_address): Likewise.
(output_pic_addr_const): Likewise.
* config/sh/sh.md (calli_pcrel, call_valuei_pcrel): New insns.
(call, call_value): Use them.
(GOTaddr2picreg, sym_label2reg, symGOT2reg, symGOTOFF2reg,
symPLT_label2reg): New expands.
* invoke.texi (SH Options): Document -mprefergot.

From-SVN: r36111

14 files changed:
gcc/ChangeLog
gcc/config/sh/crt1.asm [new file with mode: 0644]
gcc/config/sh/crti.asm [new file with mode: 0644]
gcc/config/sh/crtn.asm [new file with mode: 0644]
gcc/config/sh/elf.h
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md
gcc/config/sh/t-elf [new file with mode: 0644]
gcc/config/sh/t-sh
gcc/configure
gcc/configure.in
gcc/invoke.texi

index 16fce73aed3ab78cbb105991947896c59e11481f..03a624c8f5961ae0f480afa28a758c26cad89c5d 100644 (file)
@@ -1,3 +1,50 @@
+2000-09-02  Alexandre Oliva  <aoliva@redhat.com>
+
+       * config/sh/t-elf, config/sh/crt1.asm, config/sh/crti.asm,
+       config/sh/crtn.asm: New files.
+       * config/sh/t-sh (EXTRA_MULTILIB_PARTS): Set.
+       (crt1.o, crti.o, crtn.o): New targets.
+       * configure.in [sh-*-elf*, sh-*-rtemself*] (tmake_file): Added
+       sh/t-elf.
+       * configure: Rebuilt.
+       * config/sh/sh.h (INIT_SECTION_ASM_OP, FINI_SECTION_ASM_OP,
+       STARTFILE_SPEC, ENDFILE_SPEC, CRT_CALL_STATIC_FUNCTION): Define.
+       * config/sh/elf.h (INIT_SECTION_ASM_OP, FINI_SECTION_ASM_OP):
+       Undefine for config/elfos.h to redefine.
+       (STARTFILE_SPEC, ENDFILE_SPEC): Redefine after config/elfos.h.
+
+2000-09-02  Alexandre Oliva  <aoliva@redhat.com>, Niibe Yutaka  <gniibe@m17n.org>, Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * config/sh/sh-protos.h (nonpic_symbol_mentioned_p,
+       legitimize_pic_address, output_pic_addr_const): Declare.
+       * config/sh/sh.h (CONDITIONAL_REGISTER_USAGE): Fix PIC register.
+       (PREFERGOT_BIT, TARGET_PREFERGOT): Likewise.
+       (TARGET_SWITCHES): New switch -mprefergot.
+       (OVERRIDE_OPTIONS): Set flag_no_function_cse unless -mprefergot.
+       (PIC_OFFSET_TABLE_REGNUM): Define.
+       (GOT_SYMBOL_TABLE): Likewise.
+       (LEGITIMIZE_ADDRESS): Use legitimize_pic_address.
+       (ENCODE_SECTION_INFO): Define.
+       (FINALIZE_PIC): New macros.
+       (LEGITIMATE_PIC_OPERAND_P, SYMBOLIC_CONST_P): New macro.
+       (ASM_OUTPUT_INT, ASM_OUTPUT_SHORT): Use output_pic_addr_const.
+       * config/sh/sh.c (print_operand_address): Use output_pic_addr_const.
+       (prepare_move_operands): Call emit_pic_move or
+       emit_pic_const_move if appropriate.
+       (output_far_jump): For PIC, use braf and output long offset.
+       (machine_dependent_reorg): 
+       (sh_expand_prologue): Save and initialize the PIC register.
+       (sh_expand_epilogue): Restore it.
+       (initial_elimination_offset): Account for it.
+       (nonpic_symbol_mentioned_p): New function.
+       (legitimize_pic_address): Likewise.
+       (output_pic_addr_const): Likewise.
+       * config/sh/sh.md (calli_pcrel, call_valuei_pcrel): New insns.
+       (call, call_value): Use them.
+       (GOTaddr2picreg, sym_label2reg, symGOT2reg, symGOTOFF2reg,
+       symPLT_label2reg): New expands.
+       * invoke.texi (SH Options): Document -mprefergot.
+
 2000-09-01  Alexandre Oliva  <aoliva@redhat.com>
 
        * rtl.h (ASM_OPERANDS_INPUT_CONSTRAINT_EXP): New macro.
diff --git a/gcc/config/sh/crt1.asm b/gcc/config/sh/crt1.asm
new file mode 100644 (file)
index 0000000..a5eb4b4
--- /dev/null
@@ -0,0 +1,107 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+   This file was pretty much copied from newlib.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+       .section .text
+       .global start
+start:
+       mov.l   stack_k,r15
+
+       ! zero out bss
+       mov.l   edata_k,r0
+       mov.l   end_k,r1
+       mov     #0,r2
+start_l:
+       mov.l   r2,@r0
+       add     #4,r0
+       cmp/ge  r0,r1
+       bt      start_l
+
+#if defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY)
+       mov.l set_fpscr_k, r1
+       jsr @r1
+       mov #0,r4
+       lds r3,fpscr
+#endif /*  defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__) */
+
+       ! arrange for exit to call fini
+       mov.l   atexit_k,r0
+       jsr     @r0
+       mov.l   fini_k,r4
+
+       ! call init
+       mov.l   init_k,r0
+       jsr     @r0
+       nop
+
+       ! call the mainline     
+       mov.l   main_k,r0
+       jsr     @r0
+       nop
+
+       ! call exit
+       mov     r0,r4
+       mov.l   exit_k,r0
+       jsr     @r0
+       nop
+
+       .align 2
+#if defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__)
+set_fpscr_k:
+       .long   ___set_fpscr
+#endif /*  defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(SH4_SINGLE_ONLY) */
+stack_k:
+       .long   _stack  
+edata_k:
+       .long   _edata
+end_k:
+       .long   _end
+main_k:
+       .long   _main
+exit_k:
+       .long   _exit
+atexit_k:
+       .long   _atexit
+init_k:
+       .long   _init
+fini_k:
+       .long   _fini
+
+       ! supplied for backward compatibility only, in case of linking
+       ! code whose main() was compiled with an older version of GCC.
+       .global ___main
+___main:
+       rts
+       nop
+
+#ifdef __ELF__
+       .section .stack,"aw"
+#else
+       .section .stack
+#endif
+_stack:        .long   0xdeaddead
diff --git a/gcc/config/sh/crti.asm b/gcc/config/sh/crti.asm
new file mode 100644 (file)
index 0000000..ece8666
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+   This file was adapted from glibc sources.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* The code in sections .init and .fini is supposed to be a single
+   regular function.  The function in .init is called directly from
+   start in crt1.asm.  The function in .fini is atexit()ed in crt1.asm
+   too.
+
+   crti.asm contributes the prologue of a function to these sections,
+   and crtn.asm comes up the epilogue.  STARTFILE_SPEC should list
+   crti.o before any other object files that might add code to .init
+   or .fini sections, and ENDFILE_SPEC should list crtn.o after any
+   such object files.  */
+
+       .section .init
+/* The alignment below can't be smaller, otherwide the mova below
+   breaks.  Yes, we might align just the label, but then we'd be
+   exchanging an alignment here for one there, since the code fragment
+   below ensures 4-byte alignment on __ELF__.  */
+#ifdef __ELF__
+       .p2align 2
+#else
+       .p2align 1
+#endif
+       .global  _init
+_init:
+#ifdef __ELF__
+       mov.l   r12,@-r15
+       mova    0f,r0
+       mov.l   0f,r12
+#endif
+       mov.l   r14,@-r15
+#ifdef __ELF__
+       add     r0,r12
+#endif
+       sts.l   pr,@-r15
+#ifdef __ELF__
+       bra     1f
+#endif
+       mov     r15,r14
+#ifdef __ELF__
+0:     .long   _GLOBAL_OFFSET_TABLE_
+1:
+#endif
+
+       .section .fini
+/* The alignment below can't be smaller, otherwide the mova below
+   breaks.  Yes, we might align just the label, but then we'd be
+   exchanging an alignment here for one there, since the code fragment
+   below ensures 4-byte alignment on __ELF__.  */
+#ifdef __ELF__
+       .p2align 2
+#else
+       .p2align 1
+#endif
+       .global  _fini
+_fini: 
+#ifdef __ELF__
+       mov.l   r12,@-r15
+       mova    0f,r0
+       mov.l   0f,r12
+#endif
+       mov.l   r14,@-r15
+#ifdef __ELF__
+       add     r0,r12
+#endif
+       sts.l   pr,@-r15
+#ifdef __ELF__
+       bra     1f
+#endif
+       mov     r15,r14
+#ifdef __ELF__
+0:     .long   _GLOBAL_OFFSET_TABLE_
+1:
+#endif
diff --git a/gcc/config/sh/crtn.asm b/gcc/config/sh/crtn.asm
new file mode 100644 (file)
index 0000000..86a4ee3
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+   This file was adapted from glibc sources.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* See an explanation about .init and .fini in crti.asm.  */
+
+       .section .init
+       mov     r15,r14
+       lds.l   @r15+,pr
+       mov.l   @r15+,r14
+       rts
+#ifdef __ELF__
+       mov.l   @r15+,r12
+#else
+       nop
+#endif
+
+       .section .fini
+       mov     r15,r14
+       lds.l   @r15+,pr
+       mov.l   @r15+,r14
+       rts
+#ifdef __ELF__
+       mov.l   @r15+,r12
+#else
+       nop
+#endif
index 9d9e00389956ca98be8f39c2088c7e7777187c40..148b6b973b1b3b1efe8f58cee887489e6b19e020 100644 (file)
@@ -43,6 +43,8 @@ Boston, MA 02111-1307, USA.  */
 #undef ASM_OUTPUT_DESTRUCTOR
 #undef ASM_DECLARE_FUNCTION_NAME
 #undef MAX_OFILE_ALIGNMENT
+#undef INIT_SECTION_ASM_OP
+#undef FINI_SECTION_ASM_OP
 
 /* Be ELF-like.  */
 #include "svr4.h"
@@ -110,13 +112,15 @@ do {                                                                      \
   fprintf ((FILE), "\t.stabs \"\",%d,0,0,Letext\nLetext:\n", N_SO);    \
 } while (0)
 
-/* Arrange to call __main, rather than using crtbegin.o and crtend.o
-   and relying on .init and .fini being executed at appropriate times.  */
-#undef INIT_SECTION_ASM_OP
-#undef FINI_SECTION_ASM_OP
-#undef STARTFILE_SPEC
-#undef ENDFILE_SPEC
-
 /* HANDLE_SYSV_PRAGMA (defined by svr4.h) takes precedence over HANDLE_PRAGMA.
    We want to use the HANDLE_PRAGMA from sh.h.  */
 #undef HANDLE_SYSV_PRAGMA
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+  "%{!shared: crt1.o%s} crti.o%s \
+   %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+  "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s"
index acc316ea376a8279d7502688156bee0b5272ba64..375ade8b7d91cb79d0b5372669ebb655ea37d7ad 100644 (file)
@@ -42,10 +42,13 @@ extern int fp_zero_operand PARAMS ((rtx));
 extern int fp_one_operand PARAMS ((rtx));
 extern int fp_int_operand PARAMS ((rtx));
 extern rtx get_fpscr_rtx PARAMS ((void));
+extern rtx legitimize_pic_address PARAMS ((rtx, enum machine_mode, rtx));
+extern int nonpic_symbol_mentioned_p PARAMS ((rtx));
 extern void emit_sf_insn PARAMS ((rtx));
 extern void emit_df_insn PARAMS ((rtx));
 extern void print_operand_address PARAMS ((FILE *, rtx));
 extern void print_operand PARAMS ((FILE *, rtx, int));
+extern void output_pic_addr_const PARAMS ((FILE *, rtx));
 extern int expand_block_move PARAMS ((rtx *));
 extern int prepare_move_operands PARAMS ((rtx[], enum machine_mode mode));
 extern void from_compare PARAMS ((rtx *, int));
index 9e2ced69ed0fe6c0b8401bd88625b1d30014fd8d..930ff738b05b40a07e0dfd185d8efac0b2caa2bd 100644 (file)
@@ -201,7 +201,7 @@ print_operand_address (stream, x)
       break;
 
     default:
-      output_addr_const (stream, x);
+      output_pic_addr_const (stream, x);
       break;
     }
 }
@@ -457,6 +457,31 @@ prepare_move_operands (operands, mode)
      rtx operands[];
      enum machine_mode mode;
 {
+  if (mode == SImode && flag_pic)
+    {
+      rtx temp;
+      if (SYMBOLIC_CONST_P (operands[1]))
+       {
+         if (GET_CODE (operands[0]) == MEM)
+           operands[1] = force_reg (Pmode, operands[1]);
+         else
+           {
+             temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+             operands[1] = legitimize_pic_address (operands[1], SImode, temp);
+           }
+       }
+      else if (GET_CODE (operands[1]) == CONST
+              && GET_CODE (XEXP (operands[1], 0)) == PLUS
+              && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
+       {
+         temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
+                                        SImode, gen_reg_rtx (Pmode));
+         operands[1] = expand_binop (SImode, add_optab, temp,
+                                     XEXP (XEXP (operands[1], 0), 1),
+                                     gen_reg_rtx (Pmode), 0, OPTAB_LIB_WIDEN);
+       }
+    }
+
   if (! reload_in_progress && ! reload_completed)
     {
       /* Copy the source to a register if both operands aren't registers.  */
@@ -702,7 +727,10 @@ output_far_jump (insn, op)
   else
     {
       far = 1;
-      jump = "mov.l    %O0,%1;jmp      @%1";
+      if (flag_pic)
+       jump = "mov.l   %O0,%1;braf     %1";
+      else
+       jump = "mov.l   %O0,%1;jmp      @%1";
     }
   /* If we have a scratch register available, use it.  */
   if (GET_CODE (PREV_INSN (insn)) == INSN
@@ -730,7 +758,10 @@ output_far_jump (insn, op)
     output_asm_insn (".align   2", 0);
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (this.lab));
   this.op = op;
-  output_asm_insn (far ? ".long        %O2" : ".word %O2-%O0", &this.lab);
+  if (far && flag_pic)
+    output_asm_insn (".long    %O2-%O0", &this.lab);
+  else
+    output_asm_insn (far ? ".long      %O2" : ".word %O2-%O0", &this.lab);
   return "";
 }
 
@@ -3214,6 +3245,19 @@ machine_dependent_reorg (first)
                      /* Remove the clobber of r0.  */
                      XEXP (clobber, 0) = gen_rtx_SCRATCH (Pmode);
                    }
+                 /* This is a mova needing a label.  Create it.  */
+                 else if (GET_CODE (src) == CONST
+                          && GET_CODE (XEXP (src, 0)) == UNSPEC
+                          && XINT (XEXP (src, 0), 1) == 1
+                          && GET_CODE (XVECEXP (XEXP (src, 0),
+                                                0, 0)) == CONST)
+                   {
+                     lab = add_constant (XVECEXP (XEXP (src, 0),
+                                                  0, 0), mode, 0);
+                     newsrc = gen_rtx_LABEL_REF (VOIDmode, lab);
+                     newsrc = gen_rtx_UNSPEC (VOIDmode,
+                                              gen_rtvec (1, newsrc), 1);
+                   }
                  else
                    {
                      lab = add_constant (src, mode, 0);
@@ -3874,7 +3918,20 @@ sh_expand_prologue ()
      that already happens to be at the function start into the prologue.  */
   if (target_flags != save_flags)
     emit_insn (gen_toggle_sz ());
+  if (flag_pic && (current_function_uses_pic_offset_table
+                  || regs_ever_live[PIC_OFFSET_TABLE_REGNUM]))
+    {
+      if ((live_regs_mask & (1 << PIC_OFFSET_TABLE_REGNUM)) != 0)
+       abort ();
+      d += UNITS_PER_WORD;
+      live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM);
+    }
   push_regs (live_regs_mask, live_regs_mask2);
+
+  if (flag_pic && (current_function_uses_pic_offset_table
+                  || regs_ever_live[PIC_OFFSET_TABLE_REGNUM]))
+    emit_insn (gen_GOTaddr2picreg ());
+
   if (target_flags != save_flags)
     emit_insn (gen_toggle_sz ());
 
@@ -3926,6 +3983,8 @@ sh_expand_epilogue ()
 
   if (target_flags != save_flags)
     emit_insn (gen_toggle_sz ());
+  if (flag_pic && current_function_uses_pic_offset_table)
+    live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM);
   if (live_regs_mask & (1 << PR_REG))
     pop (PR_REG);
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -4329,6 +4388,11 @@ initial_elimination_offset (from, to)
 
   int live_regs_mask, live_regs_mask2;
   live_regs_mask = calc_live_regs (&regs_saved, &live_regs_mask2);
+  if (flag_pic && current_function_uses_pic_offset_table)
+    {
+      regs_saved++;
+      live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM);
+    }
   total_auto_space = rounded_frame_size (regs_saved);
   target_flags = save_flags;
 
@@ -5189,3 +5253,184 @@ sh_insn_length_adjustment (insn)
     }
   return 0;
 }
+\f
+/* Return TRUE if X references a SYMBOL_REF whose symbol doesn't have
+   @GOT or @GOTOFF.  */
+int
+nonpic_symbol_mentioned_p (x)
+     rtx x;
+{
+  register const char *fmt;
+  register int i;
+
+  if (GET_CODE (x) == SYMBOL_REF)
+    return 1;
+
+  if (GET_CODE (x) == UNSPEC
+      && (XINT (x, 1) >= 6 && XINT (x, 1) <= 9))
+      return 0;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           if (nonpic_symbol_mentioned_p (XVECEXP (x, i, j)))
+             return 1;
+       }
+      else if (fmt[i] == 'e' && nonpic_symbol_mentioned_p (XEXP (x, i)))
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Convert a non-PIC address in `orig' to a PIC address using @GOT or
+   @GOTOFF in `reg'. */
+rtx
+legitimize_pic_address (orig, mode, reg)
+     rtx orig;
+     enum machine_mode mode;
+     rtx reg;
+{
+  if (GET_CODE (orig) == LABEL_REF
+      || (GET_CODE (orig) == SYMBOL_REF
+         && (CONSTANT_POOL_ADDRESS_P (orig)
+             /* SYMBOL_REF_FLAG is set on static symbols.  */
+             || SYMBOL_REF_FLAG (orig))))
+    {
+      if (reg == 0)
+       reg = gen_reg_rtx (Pmode);
+
+      emit_insn (gen_symGOTOFF2reg (reg, orig));
+      return reg;
+    }
+  else if (GET_CODE (orig) == SYMBOL_REF)
+    {
+      if (reg == 0)
+       reg = gen_reg_rtx (Pmode);
+
+      emit_insn (gen_symGOT2reg (reg, orig));
+      return reg;
+    }
+  return orig;
+}
+\f
+/* Like output_addr_const(), but recognize PIC unspecs and special
+   expressions.  */
+void
+output_pic_addr_const (file, x)
+     FILE *file;
+     rtx x;
+{
+  char buf[256];
+
+  switch (GET_CODE (x))
+    {
+    case PC:
+      if (flag_pic)
+       putc ('.', file);
+      else
+       abort ();
+      break;
+
+    case SYMBOL_REF:
+      assemble_name (file, XSTR (x, 0));
+      break;
+
+    case LABEL_REF:
+      x = XEXP (x, 0);
+      /* FALLTHRU */
+    case CODE_LABEL:
+      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
+      assemble_name (asm_out_file, buf);
+      break;
+
+    case CONST:
+      output_pic_addr_const (file, XEXP (x, 0));
+      break;
+
+    case CONST_INT:
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
+      break;
+
+    case CONST_DOUBLE:
+      if (GET_MODE (x) == VOIDmode)
+       {
+         /* We can use %d if the number is <32 bits and positive.  */
+         if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
+           fprintf (file, "0x%lx%08lx",
+                    (unsigned long) CONST_DOUBLE_HIGH (x),
+                    (unsigned long) CONST_DOUBLE_LOW (x));
+         else
+           fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
+       }
+      else
+       /* We can't handle floating point constants;
+          PRINT_OPERAND must handle them.  */
+       output_operand_lossage ("floating constant misused");
+      break;
+
+    case PLUS:
+      /* Some assemblers need integer constants to appear first.  */
+      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+       {
+         output_pic_addr_const (file, XEXP (x, 0));
+         fprintf (file, "+");
+         output_pic_addr_const (file, XEXP (x, 1));
+       }
+      else if (GET_CODE (XEXP (x, 1)) == CONST_INT
+              || GET_CODE (XEXP (x, 0)) == PC)
+       {
+         output_pic_addr_const (file, XEXP (x, 1));
+         fprintf (file, "+");
+         output_pic_addr_const (file, XEXP (x, 0));
+       }
+      else
+       abort ();
+      break;
+
+    case MINUS:
+      output_pic_addr_const (file, XEXP (x, 0));
+      fprintf (file, "-");
+      if (GET_CODE (XEXP (x, 1)) == CONST)
+       {
+         putc ('(', file);
+         output_pic_addr_const (file, XEXP (x, 1));
+         putc (')', file);
+       }
+      else
+       output_pic_addr_const (file, XEXP (x, 1));
+      break;
+
+    case UNSPEC:
+      if ((XVECLEN (x, 0)) > 3)
+       abort ();
+      output_pic_addr_const (file, XVECEXP (x, 0, 0));
+      switch (XINT (x, 1))
+       {
+       case 6:
+         /* GLOBAL_OFFSET_TABLE or local symbols, no suffix.  */
+         break;
+       case 7:
+         fputs ("@GOT", file);
+         break;
+       case 8:
+         fputs ("@GOTOFF", file);
+         break;
+        case 9:
+         fputs ("@PLT", file);
+         break;
+       default:
+         output_operand_lossage ("invalid UNSPEC as operand");
+         break;
+       }
+      break;
+
+    default:
+      output_operand_lossage ("invalid expression as operand");
+    }
+}
index 1ea39d673b08a13811d22cfb15e6d27745ca9b93..82b56b55f04076b2ec85f27b1092e739c2fbffef 100644 (file)
@@ -78,6 +78,11 @@ extern int code_for_indirect_jump_scratch;
            }                                                           \
        }                                                               \
     }                                                                  \
+  if (flag_pic)                                                                \
+    {                                                                  \
+      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;                         \
+      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;                     \
+    }                                                                  \
   /* Hitachi saves and restores mac registers on call.  */             \
   if (TARGET_HITACHI && ! TARGET_NOMACSAVE)                            \
     {                                                                  \
@@ -106,6 +111,7 @@ extern int target_flags;
 #define RELAX_BIT      (1<<15)
 #define HITACHI_BIT     (1<<22)
 #define NOMACSAVE_BIT   (1<<23)
+#define PREFERGOT_BIT  (1<<24)
 #define PADSTRUCT_BIT  (1<<28)
 #define LITTLE_ENDIAN_BIT (1<<29)
 #define IEEE_BIT (1<<30)
@@ -178,6 +184,9 @@ extern int target_flags;
 /* Nonzero if generating code for a little endian SH.  */
 #define TARGET_LITTLE_ENDIAN     (target_flags & LITTLE_ENDIAN_BIT)
 
+/* Nonzero if we should prefer @GOT calls when generating PIC.  */
+#define TARGET_PREFERGOT       (target_flags & PREFERGOT_BIT)
+
 #define TARGET_SWITCHES                        \
 { {"1",                SH1_BIT},                       \
   {"2",                SH2_BIT},                       \
@@ -198,6 +207,7 @@ extern int target_flags;
   {"l",                LITTLE_ENDIAN_BIT},             \
   {"no-ieee",          -IEEE_BIT},                     \
   {"padstruct", PADSTRUCT_BIT},                \
+  {"prefergot",        PREFERGOT_BIT},                 \
   {"relax",    RELAX_BIT},                     \
   {"space",    SPACE_BIT},                     \
   SUBTARGET_SWITCHES                            \
@@ -256,6 +266,9 @@ do {                                                                        \
    else                                                                        \
     flag_omit_frame_pointer = 0;                                       \
                                                                        \
+  if (! TARGET_PREFERGOT)                                              \
+    flag_no_function_cse = 1;                                          \
+                                                                       \
   /* Never run scheduling before reload, since that can                        \
      break global alloc, and generates slower code anyway due          \
      to the pressure on R0.  */                                                \
@@ -538,6 +551,12 @@ do {                                                                       \
    current function's return address.  */
 #define RETURN_ADDRESS_POINTER_REGNUM 23
 
+/* Register to hold the addressing base for position independent
+   code access to data items.  */
+#define PIC_OFFSET_TABLE_REGNUM        12
+
+#define GOT_SYMBOL_NAME "*_GLOBAL_OFFSET_TABLE_"
+
 /* Value should be nonzero if functions must have frame pointers.
    Zero means the frame pointer need not be set up (and parms may be accessed
    via the stack pointer) in functions that seem suitable.  */
@@ -1400,6 +1419,8 @@ extern int current_function_anonymous_args;
 
 #define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)                    \
 {                                                              \
+  if (flag_pic)                                                        \
+    (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX);       \
   if (GET_CODE (X) == PLUS                                     \
       && (GET_MODE_SIZE (MODE) == 4                            \
          || GET_MODE_SIZE (MODE) == 8)                         \
@@ -1708,6 +1729,44 @@ extern int current_function_anonymous_args;
     && GET_CODE (PATTERN (X)) != CLOBBER       \
     && get_attr_is_sfunc (X)))
 
+\f
+/* Position Independent Code.  */
+/* Define this macro if references to a symbol must be treated
+   differently depending on something about the variable or function
+   named by the symbol (such as what section it is in).
+
+   On SH, if using PIC, mark a SYMBOL_REF for a non-global symbol
+   so that we may access it using GOTOFF instead of GOT.  */
+
+#define ENCODE_SECTION_INFO(DECL) \
+do                                                                     \
+  {                                                                    \
+    if (flag_pic)                                                      \
+      {                                                                        \
+       rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd'            \
+                  ? TREE_CST_RTL (DECL) : DECL_RTL (DECL));            \
+                                                                       \
+       SYMBOL_REF_FLAG (XEXP (rtl, 0)) =                               \
+         (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd'                    \
+          || ! TREE_PUBLIC (DECL));                                    \
+      }                                                                        \
+  }                                                                    \
+while (0)
+
+#define FINALIZE_PIC                                                   \
+  current_function_uses_pic_offset_table |= profile_flag | profile_block_flag
+
+/* We can't directly access anything that contains a symbol,
+   nor can we indirect via the constant pool.  */
+#define LEGITIMATE_PIC_OPERAND_P(X)                            \
+       (! nonpic_symbol_mentioned_p (X)                        \
+        && (! CONSTANT_POOL_ADDRESS_P (X)                      \
+            || ! nonpic_symbol_mentioned_p (get_pool_constant (X))))
+
+#define SYMBOLIC_CONST_P(X)    \
+((GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF)     \
+  && nonpic_symbol_mentioned_p (X))
+\f
 /* Compute the cost of an address.  For the SH, all valid addresses are
    the same cost.  */
 /* ??? Perhaps we should make reg+reg addresses have higher cost because
@@ -2003,12 +2062,12 @@ do { char dstr[30];                                     \
 
 #define ASM_OUTPUT_INT(STREAM, EXP)            \
   (fprintf ((STREAM), "\t.long\t"),            \
-   output_addr_const ((STREAM), (EXP)),        \
+   output_pic_addr_const ((STREAM), (EXP)),    \
    fputc ('\n', (STREAM)))
 
 #define ASM_OUTPUT_SHORT(STREAM, EXP)  \
   (fprintf ((STREAM), "\t.short\t"),   \
-   output_addr_const ((STREAM), (EXP)),        \
+   output_pic_addr_const ((STREAM), (EXP)),    \
    fputc ('\n', (STREAM)))
 
 #define ASM_OUTPUT_CHAR(STREAM, EXP)           \
@@ -2279,3 +2338,34 @@ do {                                                                     \
   fpscr_set_from_mem ((MODE), (HARD_REGS_LIVE))
 
 #define DWARF_LINE_MIN_INSTR_LENGTH 2
+
+#undef INIT_SECTION_ASM_OP
+#define INIT_SECTION_ASM_OP    ".section\t.init"
+#undef FINI_SECTION_ASM_OP
+#define FINI_SECTION_ASM_OP    ".section\t.fini"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+  "crt1.o%s crti.o%s crtbegin.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+  "crtend.o%s crtn.o%s"
+
+/* SH constant pool breaks the devices in crtstuff.c to control section
+   in where code resides.  We have to write it as asm code.  */
+#define CRT_CALL_STATIC_FUNCTION(func) \
+  if (0) \
+     /* This avoids warnings about the static function being unused.  */ \
+     func (); \
+  else \
+    /* We should be passing FUNC to the asm statement as an asm input  \
+       operand, but this breaks with -fPIC.  FIXME.  */                        \
+    asm \
+      ("mov.l  1f,r1\n\
+       mova    2f,r0\n\
+       braf    r1\n\
+       lds     r0,pr\n\
+0:     .p2align 2\n\
+1:     .long   " USER_LABEL_PREFIX #func " - 0b\n\
+2:")
index fc3068491241fa69703c869f3acc068312cc0961..9ac6436d189be6940ab602822c983e10beab69c5 100644 (file)
                      (const_string "single") (const_string "double")))
    (set_attr "needs_delay_slot" "yes")])
 
+;; This is a pc-rel call, using bsrf, for use with PIC.
+
+(define_insn "calli_pcrel"
+  [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r"))
+        (match_operand 1 "" ""))
+   (use (reg:SI 48))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI 17))]
+  ""
+  "bsrf        %0\\n%O2:%#"
+  [(set_attr "type" "call")
+   (set (attr "fp_mode")
+       (if_then_else (eq_attr "fpu_single" "yes")
+                     (const_string "single") (const_string "double")))
+   (set_attr "needs_delay_slot" "yes")])
+
 (define_insn "call_valuei"
   [(set (match_operand 0 "" "=rf")
        (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
                      (const_string "single") (const_string "double")))
    (set_attr "needs_delay_slot" "yes")])
 
+(define_insn "call_valuei_pcrel"
+  [(set (match_operand 0 "" "=rf")
+       (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
+             (match_operand 2 "" "")))
+   (use (reg:SI 48))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI 17))]
+  ""
+  "bsrf        %1\\n%O3:%#"
+  [(set_attr "type" "call")
+   (set (attr "fp_mode")
+       (if_then_else (eq_attr "fpu_single" "yes")
+                     (const_string "single") (const_string "double")))
+   (set_attr "needs_delay_slot" "yes")])
+
 (define_expand "call"
   [(parallel [(call (mem:SI (match_operand 0 "arith_reg_operand" ""))
                            (match_operand 1 "" ""))
              (use (reg:SI 48))
              (clobber (reg:SI 17))])]
   ""
-  "operands[0] = force_reg (SImode, XEXP (operands[0], 0));")
+  "
+if (flag_pic && ! TARGET_SH1 && ! flag_unroll_loops
+    && GET_CODE (operands[0]) == MEM
+    && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
+  {
+    rtx reg = gen_reg_rtx (SImode), lab = gen_label_rtx ();
+
+    if (SYMBOL_REF_FLAG (XEXP (operands[0], 0)))
+      emit_insn (gen_sym_label2reg (reg, XEXP (operands[0], 0), lab));
+    else
+      emit_insn (gen_symPLT_label2reg (reg, XEXP (operands[0], 0), lab));
+    operands[0] = reg;
+    emit_call_insn (gen_calli_pcrel (operands[0], operands[1], lab));
+    DONE;
+  }
+else
+  operands[0] = force_reg (SImode, XEXP (operands[0], 0));")
 
 (define_expand "call_value"
   [(parallel [(set (match_operand 0 "arith_reg_operand" "")
              (use (reg:SI 48))
              (clobber (reg:SI 17))])]
   ""
-  "operands[1] = force_reg (SImode, XEXP (operands[1], 0));")
+  "
+if (flag_pic && ! TARGET_SH1 && ! flag_unroll_loops
+    && GET_CODE (operands[1]) == MEM
+    && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+  {
+    rtx reg = gen_reg_rtx (SImode), lab = gen_label_rtx ();
+
+    if (SYMBOL_REF_FLAG (XEXP (operands[1], 0)))
+      emit_insn (gen_sym_label2reg (reg, XEXP (operands[1], 0), lab));
+    else
+      emit_insn (gen_symPLT_label2reg (reg, XEXP (operands[1], 0), lab));
+    operands[1] = reg;
+    emit_call_insn (gen_call_valuei_pcrel (operands[0], operands[1],
+                                          operands[2], lab));
+    DONE;
+  }
+else
+  operands[1] = force_reg (SImode, XEXP (operands[1], 0));")
 
 (define_insn "indirect_jump"
   [(set (pc)
   [(set_attr "in_delay_slot" "no")
    (set_attr "type" "arith")])
 
+(define_expand "GOTaddr2picreg"
+  [(set (reg:SI 0) (const (unspec [(const (unspec [(match_dup 1)] 6))] 1)))
+  (set (match_dup 0) (const (unspec [(match_dup 1)] 6)))
+  (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI 0)))]
+  "" "
+{
+  operands[0] = pic_offset_table_rtx;
+  current_function_uses_pic_offset_table = 1;
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+}
+")
+
+(define_expand "sym_label2reg"
+  [(set (match_operand:SI 0 "" "")
+       (const (minus:SI
+               (unspec [(match_operand:SI 1 "" "")] 6)
+               (const (plus:SI (label_ref (match_operand:SI 2 "" ""))
+                               (const_int 2))))))]
+  "" "")
+
+(define_expand "symGOT2reg"
+  [(set (match_operand:SI 0 "" "")
+        (const (unspec [(match_operand:SI 1 "" "")] 7)))
+  (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))
+  (set (match_dup 0) (mem:SI (match_dup 0)))]
+  ""
+  "
+{
+  operands[2] = pic_offset_table_rtx;
+  current_function_uses_pic_offset_table = 1;
+}")
+
+(define_expand "symGOTOFF2reg"
+  [(set (match_operand:SI 0 "" "")
+       (const (unspec [(match_operand:SI 1 "" "")] 8)))
+  (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))]
+  ""
+  "
+{
+  operands[2] = pic_offset_table_rtx;
+  current_function_uses_pic_offset_table = 1;
+}")
+
+(define_expand "symPLT_label2reg"
+  [(set (match_operand:SI 0 "" "")
+       (const (minus:SI
+               (plus:SI (pc)
+                        (unspec [(match_operand:SI 1 "" "")] 9))
+               (const (plus:SI (label_ref (match_operand:SI 2 "" ""))
+                               (const_int 2))))))]
+  "" "")
+
 ;; case instruction for switch statements.
 
 ;; Operand 0 is index
 {
   operands[1] = get_fpscr_rtx ();
   operands[2] = gen_rtx_SYMBOL_REF (SImode, \"__fpscr_values\");
+  if (flag_pic)
+    operands[2] = legitimize_pic_address (operands[2], SImode,
+                                         no_new_pseudos ? operands[0] : 0);
 }")
 
 (define_expand "fpu_switch1"
 {
   operands[1] = get_fpscr_rtx ();
   operands[2] = gen_rtx_SYMBOL_REF (SImode, \"__fpscr_values\");
+  if (flag_pic)
+    operands[2] = legitimize_pic_address (operands[2], SImode,
+                                         no_new_pseudos ? operands[0] : 0);
   operands[3] = no_new_pseudos ? operands[0] : gen_reg_rtx (SImode);
 }")
 
diff --git a/gcc/config/sh/t-elf b/gcc/config/sh/t-elf
new file mode 100644 (file)
index 0000000..29807d7
--- /dev/null
@@ -0,0 +1,9 @@
+EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o \
+       crtbegin.o crtend.o crtbeginS.o crtendS.o
+
+# Compile crtbeginS.o and crtendS.o with pic.
+CRTSTUFF_T_CFLAGS_S = -fPIC
+
+# Don't compile libgcc with -fpic for now.  It's unlikely that we'll
+# build shared libraries for embedded SH.
+# TARGET_LIBGCC2_CFLAGS = -fpic
index cb187aa855cfbb939c58afaaa6534d26c778ff45..99ae929d0f0e0b39718cfcc066f398c90544ebb7 100644 (file)
@@ -27,3 +27,12 @@ MULTILIB_MATCHES = m2=m3 m2=m4-nofpu
 
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
+
+$(T)crt1.o: $(srcdir)/config/sh/crt1.asm $(GCC_PASSES)
+       $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crt1.o -x assembler-with-cpp $(srcdir)/config/sh/crt1.asm
+$(T)crti.o: $(srcdir)/config/sh/crti.asm $(GCC_PASSES)
+       $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/sh/crti.asm
+$(T)crtn.o: $(srcdir)/config/sh/crtn.asm $(GCC_PASSES)
+       $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/sh/crtn.asm
+
+EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o crtbegin.o crtend.o
index 15e7109d0bd849439b2fe0795746cba6de290fd8..ed7f32a6872fb447e27eedfc0489265f5e12c17a 100755 (executable)
@@ -6308,11 +6308,12 @@ for machine in $build $host $target; do
                use_collect2=yes
                ;;
        sh-*-elf*)
+               tmake_file="sh/t-sh sh/t-elf"
                tm_file="sh/sh.h sh/elf.h"
                float_format=sh
                ;;
        sh-*-rtemself*)
-               tmake_file="sh/t-sh t-rtems"
+               tmake_file="sh/t-sh sh/t-elf t-rtems"
                tm_file="sh/sh.h sh/elf.h sh/rtemself.h"
                float_format=sh
                ;;
index 213f8dc5502f37e5a14087cee5457bb8e47318c6..bee31c0643775c923c4c7bbc995d56110ea2f95d 100644 (file)
@@ -3344,11 +3344,12 @@ changequote([,])dnl
                use_collect2=yes
                ;;
        sh-*-elf*)
+               tmake_file="sh/t-sh sh/t-elf"
                tm_file="sh/sh.h sh/elf.h"
                float_format=sh
                ;;
        sh-*-rtemself*)
-               tmake_file="sh/t-sh t-rtems"
+               tmake_file="sh/t-sh sh/t-elf t-rtems"
                tm_file="sh/sh.h sh/elf.h sh/rtemself.h"
                float_format=sh
                ;;
index b68b14c1a4050af31ae05201436d46e41ec5dd1f..523c320253d8ae5d695ae1d00ba1249d7fb07f7e 100644 (file)
@@ -418,6 +418,7 @@ in the following sections.
 -mb  -ml  -mdalign  -mrelax
 -mbigtable  -mfmovd  -mhitachi  -mnomacsave
 -misize  -mpadstruct  -mspace
+-mprefergot
 
 @emph{System V Options}
 -Qy  -Qn  -YP,@var{paths}  -Ym,@var{dir}
@@ -6713,6 +6714,10 @@ which is incompatible with the SH ABI.
 
 @item -mspace
 Optimize for space instead of speed.  Implied by @code{-Os}.
+
+@item -mprefergot
+When generating position-independent code, emit function calls using
+the Global Offset Table instead of the Procedure Linkage Table.
 @end table
 
 @node System V Options