Patchwork [3/3] SH-2A FDPIC: backend support

login
register
mail settings
Submitter Andrew Stubbs
Date Aug. 19, 2010, 4:09 p.m.
Message ID <4C6D5727.5020407@codesourcery.com>
Download mbox | patch
Permalink /patch/62192/
State New
Headers show

Comments

Andrew Stubbs - Aug. 19, 2010, 4:09 p.m.
This patch adds FDPIC support for SH-2A uClinux. The binutils patch was 
already accepted and committed.

The result is a functional compiler that will build a working 
busybox-based uClinux system, and pass the majority of the tests in the 
GCC testsuite. It has been tested on a Renesas SH7203.

The compiler is known to be less than perfect, but it is a start and 
will provide a basis for future improvement. There is no existing SH 
FDPIC support, so this is not a regression.

The ABI for the new system is published here:
http://www.codesourcery.com/public/docs/sh-fdpic/sh-fdpic-abi.txt

OK to commit?

Andrew Stubbs
2010-08-19  Daniel Jacobowitz  <dan@codesourcery.com>
	    Joseph Myers  <joseph@codesourcery.com>
	    Mark Shinwell  <shinwell@codesourcery.com>
	    Andrew Stubbs  <ams@codesourcery.com>

	gcc/
	* config.gcc: Handle sh-*-uclinux* | sh[12]-*-uclinux*.
	Handle --enable-fdpic.
	* config/sh/constraints.md: Add Ccl constraint.
	* config/sh/lib1funcs.asm (set_fpscr): Handle FDPIC.
	* config/sh/predicates.md (pseudo_register_operand): New.
	* config/sh/sh-protos.h (sh_load_function_descriptor,
	sh_legitimate_constant_p, sh_our_fdpic_reg): Declare.
	(function_symbol): Update prototype.
	* config/sh/sh.c (sh_assemble_integer, sh_cannot_force_const_mem_p,
	sh_delegitimize_address, sh_reloc_rw_mask,
	sh_legitimate_constant_p, sh_cannot_force_const_mem_p,
	sh_load_function_descriptor, sh_our_fdpic_reg, sh_reloc_rw_mask): New.
	(TARGET_ASM_INTEGER, TARGET_DELEGITIMIZE_ADDRESS,
	TARGET_CANNOT_FORCE_CONST_MEM, TARGET_ASM_RELOC_RW_MASK): Define.
	(sh_override_options, expand_block_move, prepare_move_operands,
	sh_cannot_copy_insn_p, expand_ashiftrt, sh_expand_prologue,
	nonpic_symbol_mentioned_p, legitimize_pic_address,
	sh_trampoline_init, sh_output_mi_thunk, function_symbol):
	Support FDPIC.
	* config/sh/sh.h (TARGET_CPU_CPP_BUILTINS): Add __SH_FDPIC__
	and __FDPIC__.
	(CONDITIONAL_REGISTER_USAGE, TRAMPOLINE_SIZE,
	OUTPUT_ADDR_CONST_EXTRA, ASM_PREFERRED_EH_DATA_FORMAT,
	ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Support FDPIC.
	(DRIVER_SELF_SPECS): Insert SUBTARGET_DRIVER_SELF_SPECS.
	(SUBTARGET_DRIVER_SELF_SPECS, PIC_OFFSET_TABLE_REG_CALL_CLOBBERED,
	OUR_FDPIC_REG, SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P,
	CRT_GET_RFIB_DATA): Define.
	(LEGITIMATE_CONSTANT_P): Use sh_legitimate_constant_p.
	* config/sh/sh.md (R12_REG, UNSPEC_GOTFUNCDESC,
	UNSPEC_GOTOFFFUNCDESC, sym2GOTFUNCDESC, symGOTFUNCDESC2reg,
	sym2GOTOFFFUNCDESC, symGOTOFFFUNCDESC2reg): Define.
	(udivsi3_i1, udivsi3_i4, udivsi3_i4_single, udivsi3,
	divsi_inv_call_combine, divsi3_i4_media, divsi3_i4,
	divsi3_i4_single, divsi3, mulsi3, ashrsi3_n, ic_invalidate_line,
	initialize_trampoline, calli, call_valuei, call, call_pop,
	call_value, sibcalli, sibcall_pcrel, sibcall, sibcall_valuei,
	sibcall_valuei_pcrel, sibcall_value_pcrel, sibcall_value,
	call_value_pop, GOTaddr2picreg, symGOT_load, symGOTOFF2reg,
	shcompact_return_tramp, block_move_real, block_lump_real,
	block_move_real_i4, block_lump_real_i4): Support FDPIC, and
	update calls to functions with new parameters.
	(calli_fdpic, call_valuei_fdpic, sibcalli_fdpic,
	sibcalli_pcrel_fdpic, sibcall_pcrel_fdpic, sibcall_valuei_fdpic,
	sibcall_valuei_pcrel_fdpic, sibcall_value_pcrel_fdpic,
	use_initial_val, sym2GOTFUNCDESC, symGOTFUNCDESC2reg,
	sym2GOTOFFFUNCDESC, symGOTOFFFUNCDESC2reg): New.
	* config/sh/sh.opt (-mfdpic): New option.
	* config/sh/t-uclinux: New file.
	* config/sh/uclinux.h: New file.
	* doc/install.texi (Options specification): Add --enable-fdpic.
	* doc/invoke.texi (SH Options): Add -mfdpic.
	* longlong.h (udiv_qrnnd): Add FDPIC compatible version.

	gcc/testsuite/
	* gcc.target/sh/sh-relax.c: Add xfail for sh*-*-uclinux.

	libgcc/
	* libgcc/config.host: Handle sh-*-uclinux* and
	sh[2346lbe]*-*-uclinux*.

---
 src/gcc-mainline/gcc/config.gcc                    |    9 
 src/gcc-mainline/gcc/config/sh/constraints.md      |    6 
 src/gcc-mainline/gcc/config/sh/lib1funcs.asm       |    9 
 src/gcc-mainline/gcc/config/sh/predicates.md       |    7 
 src/gcc-mainline/gcc/config/sh/sh-protos.h         |    5 
 src/gcc-mainline/gcc/config/sh/sh.c                |  352 ++++++++++++--
 src/gcc-mainline/gcc/config/sh/sh.h                |   74 ++-
 src/gcc-mainline/gcc/config/sh/sh.md               |  500 +++++++++++++++++---
 src/gcc-mainline/gcc/config/sh/sh.opt              |    4 
 src/gcc-mainline/gcc/config/sh/t-uclinux           |    4 
 src/gcc-mainline/gcc/config/sh/uclinux.h           |   96 ++++
 src/gcc-mainline/gcc/doc/install.texi              |    4 
 src/gcc-mainline/gcc/doc/invoke.texi               |    5 
 src/gcc-mainline/gcc/longlong.h                    |   30 +
 .../gcc/testsuite/gcc.target/sh/sh-relax.c         |    1 
 src/gcc-mainline/libgcc/config.host                |    1 
 16 files changed, 962 insertions(+), 145 deletions(-)
 create mode 100644 src/gcc-mainline/gcc/config/sh/t-uclinux
 create mode 100644 src/gcc-mainline/gcc/config/sh/uclinux.h
Kaz Kojima - Aug. 20, 2010, 8:41 a.m.
Andrew Stubbs <ams@codesourcery.com> wrote:
> This patch adds FDPIC support for SH-2A uClinux. The binutils patch was 
> already accepted and committed.
> 
> The result is a functional compiler that will build a working 
> busybox-based uClinux system, and pass the majority of the tests in the 
> GCC testsuite. It has been tested on a Renesas SH7203.
> 
> The compiler is known to be less than perfect, but it is a start and 
> will provide a basis for future improvement. There is no existing SH 
> FDPIC support, so this is not a regression.
> 
> The ABI for the new system is published here:
> http://www.codesourcery.com/public/docs/sh-fdpic/sh-fdpic-abi.txt
> 
> OK to commit?

The copyright years of

  config/sh/lib1funcs.asm
  config/sh/constraints.md
  config/sh/sh.opt
  config/sh/uclinux.h

should be updated.  The target specific part is OK with
those changes.  I'd like to pre-approve the possible change
of use_initial_val based on the on-going arguments with rth
if it passes the usual tests.  Thanks for this work!

Regards,
	kaz

Patch

diff --git a/src/gcc-mainline/gcc/config.gcc b/src/gcc-mainline/gcc/config.gcc
index 9170fc8..4b44f4b 100644
--- a/src/gcc-mainline/gcc/config.gcc
+++ b/src/gcc-mainline/gcc/config.gcc
@@ -2208,6 +2208,7 @@  score-*-elf)
 sh-*-elf* | sh[12346l]*-*-elf* | \
 sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \
   sh-*-linux* | sh[2346lbe]*-*-linux* | \
+  sh-*-uclinux* | sh[12]-*-uclinux* | \
   sh-*-netbsdelf* | shl*-*-netbsdelf* | sh5-*-netbsd* | sh5l*-*-netbsd* | \
    sh64-*-netbsd* | sh64l*-*-netbsd*)
 	tmake_file="${tmake_file} sh/t-sh sh/t-elf"
@@ -2245,6 +2246,13 @@  sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \
 	sh*-*-linux*)	tmake_file="${tmake_file} sh/t-linux"
 			tm_file="${tm_file} linux.h glibc-stdint.h sh/linux.h" ;;
 	sh*-*-netbsd*)	tm_file="${tm_file} netbsd.h netbsd-elf.h sh/netbsd-elf.h" ;;
+	sh*-*-uclinux*)	if test x$enable_fdpic != xno; then
+				tmake_file="${tmake_file} t-slibgcc-elf-ver"
+				tm_file="${tm_file} sh/uclinux.h"
+				tm_defines="$tm_defines FDPIC_DEFAULT=1"
+			else
+				tm_file="${tm_file} flat.h sh/uclinux.h"
+			fi ;;
 	sh*-superh-elf)	if test x$with_libgloss != xno; then
                                 with_libgloss=yes
                                 tm_file="${tm_file} sh/newlib.h"
@@ -2271,6 +2279,7 @@  sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \
 	*-*-netbsd)
                 tmake_file="${tmake_file} sh/t-netbsd"
 		;;
+	sh*-*-uclinux*)	tmake_file="${tmake_file} sh/t-uclinux" ;;
 	sh64*-*-linux*)
 		tmake_file="${tmake_file} sh/t-sh64 sh/t-linux64"
 		tm_file="${tm_file} sh/sh64.h"
diff --git a/src/gcc-mainline/gcc/config/sh/constraints.md b/src/gcc-mainline/gcc/config/sh/constraints.md
index 6b0e5d2..640b28e 100644
--- a/src/gcc-mainline/gcc/config/sh/constraints.md
+++ b/src/gcc-mainline/gcc/config/sh/constraints.md
@@ -22,6 +22,7 @@ 
 ;;  Bsc: SCRATCH - for the scratch register in movsi_ie in the
 ;;       fldi0 / fldi0 cases
 ;; Cxx: Constants other than only CONST_INT
+;;  Ccl: call site label
 ;;  Css: signed 16-bit constant, literal or symbolic
 ;;  Csu: unsigned 16-bit constant, literal or symbolic
 ;;  Csy: label or symbol
@@ -183,6 +184,11 @@ 
    hence mova is being used, hence do not select this pattern."
   (match_code "scratch"))
 
+(define_constraint "Ccl"
+  "A call site label, for bsrf."
+  (and (match_code "unspec")
+       (match_test "XINT (op, 1) == UNSPEC_CALLER")))
+
 (define_constraint "Css"
   "A signed 16-bit constant, literal or symbolic."
   (and (match_code "const")
diff --git a/src/gcc-mainline/gcc/config/sh/lib1funcs.asm b/src/gcc-mainline/gcc/config/sh/lib1funcs.asm
index 2f0ca16..c32bfd3 100644
--- a/src/gcc-mainline/gcc/config/sh/lib1funcs.asm
+++ b/src/gcc-mainline/gcc/config/sh/lib1funcs.asm
@@ -1973,7 +1973,10 @@  GLOBAL(moddi3):
 	HIDDEN_FUNC(GLOBAL(set_fpscr))
 GLOBAL(set_fpscr):
 	lds r4,fpscr
-#ifdef __PIC__
+#if defined(__SH_FDPIC__)
+	mov.l	LOCAL(set_fpscr_L1),r0
+	mov.l	@(r0,r12),r1
+#elif defined(__PIC__)
 	mov.l	r12,@-r15
 #ifdef __vxworks
 	mov.l	LOCAL(set_fpscr_L0_base),r12
@@ -2018,7 +2021,8 @@  GLOBAL(set_fpscr):
 	mov.l r3,@(4,r1)
 #endif
 	.align 2
-#ifdef __PIC__
+#if defined __PIC__ || defined __SH_FDPIC__
+#ifndef __SH_FDPIC__
 #ifdef __vxworks
 LOCAL(set_fpscr_L0_base):
 	.long ___GOTT_BASE__
@@ -2028,6 +2032,7 @@  LOCAL(set_fpscr_L0_index):
 LOCAL(set_fpscr_L0):
 	.long _GLOBAL_OFFSET_TABLE_
 #endif
+#endif /* __SH_FDPIC__ */
 LOCAL(set_fpscr_L1):
 	.long GLOBAL(fpscr_values@GOT)
 #else
diff --git a/src/gcc-mainline/gcc/config/sh/predicates.md b/src/gcc-mainline/gcc/config/sh/predicates.md
index b6508b7..6815e08 100644
--- a/src/gcc-mainline/gcc/config/sh/predicates.md
+++ b/src/gcc-mainline/gcc/config/sh/predicates.md
@@ -831,3 +831,10 @@ 
     }
   return 0;
 })
+
+(define_predicate "pseudo_register_operand"
+  (match_code "reg")
+{
+  return (reload_completed || reload_in_progress
+  	  || REGNO (op) >= FIRST_PSEUDO_REGISTER);
+})
\ No newline at end of file
diff --git a/src/gcc-mainline/gcc/config/sh/sh-protos.h b/src/gcc-mainline/gcc/config/sh/sh-protos.h
index dc68af1..f717f65 100644
--- a/src/gcc-mainline/gcc/config/sh/sh-protos.h
+++ b/src/gcc-mainline/gcc/config/sh/sh-protos.h
@@ -156,7 +156,7 @@  extern void fpscr_set_from_mem (int, HARD_REG_SET);
 extern void sh_pr_interrupt (struct cpp_reader *);
 extern void sh_pr_trapa (struct cpp_reader *);
 extern void sh_pr_nosave_low_regs (struct cpp_reader *);
-extern rtx function_symbol (rtx, const char *, enum sh_function_kind);
+extern rtx function_symbol (rtx, const char *, enum sh_function_kind, rtx *);
 extern rtx sh_get_pr_initial_val (void);
 
 extern rtx sh_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
@@ -180,6 +180,9 @@  extern int sh2a_get_function_vector_number (rtx);
 extern int sh2a_is_function_vector_call (rtx);
 extern void sh_fix_range (const char *);
 extern bool sh_hard_regno_mode_ok (unsigned int, enum machine_mode);
+extern bool sh_legitimate_constant_p (rtx);
+extern rtx sh_load_function_descriptor (rtx);
+extern rtx sh_our_fdpic_reg (void);
 #endif /* ! GCC_SH_PROTOS_H */
 
 #ifdef SYMBIAN
diff --git a/src/gcc-mainline/gcc/config/sh/sh.c b/src/gcc-mainline/gcc/config/sh/sh.c
index 8ace99c..36b6561 100644
--- a/src/gcc-mainline/gcc/config/sh/sh.c
+++ b/src/gcc-mainline/gcc/config/sh/sh.c
@@ -237,6 +237,7 @@  static tree sh_media_builtin_decl (unsigned, bool);
 static rtx sh_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
 static void sh_file_start (void);
+static bool sh_assemble_integer (rtx, unsigned, int);
 static int flow_dependent_p (rtx, rtx);
 static void flow_dependent_p_1 (rtx, const_rtx, void *);
 static int shiftcosts (rtx);
@@ -245,12 +246,14 @@  static int addsubcosts (rtx);
 static int multcosts (rtx);
 static bool unspec_caller_rtx_p (rtx);
 static bool sh_cannot_copy_insn_p (rtx);
+static bool sh_cannot_force_const_mem_p (rtx);
 static bool sh_rtx_costs (rtx, int, int, int *, bool);
 static int sh_address_cost (rtx, bool);
 static int sh_pr_n_sets (void);
 static rtx sh_allocate_initial_value (rtx);
 static bool sh_legitimate_address_p (enum machine_mode, rtx, bool);
 static rtx sh_legitimize_address (rtx, rtx, enum machine_mode);
+static rtx sh_delegitimize_address (rtx);
 static int shmedia_target_regs_stack_space (HARD_REG_SET *);
 static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *);
 static int shmedia_target_regs_stack_adjust (HARD_REG_SET *);
@@ -288,6 +291,7 @@  static void sh_encode_section_info (tree, rtx, int);
 static int sh2a_function_vector_p (tree);
 static void sh_trampoline_init (rtx, tree, rtx);
 static rtx sh_trampoline_adjust_address (rtx);
+static int sh_reloc_rw_mask (void);
 
 static const struct attribute_spec sh_attribute_table[] =
 {
@@ -351,6 +355,9 @@  static const struct attribute_spec sh_attribute_table[] =
 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
 
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER sh_assemble_integer
+
 #undef TARGET_DEFAULT_TARGET_FLAGS
 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
 #undef TARGET_HANDLE_OPTION
@@ -424,6 +431,11 @@  static const struct attribute_spec sh_attribute_table[] =
 #undef TARGET_LEGITIMIZE_ADDRESS
 #define TARGET_LEGITIMIZE_ADDRESS sh_legitimize_address
 
+#if 0
+#undef TARGET_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS sh_delegitimize_address
+#endif
+
 #undef TARGET_CANNOT_MODIFY_JUMPS_P
 #define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p
 #undef TARGET_BRANCH_TARGET_REGISTER_CLASS
@@ -551,6 +563,12 @@  static const struct attribute_spec sh_attribute_table[] =
 /* Machine-specific symbol_ref flags.  */
 #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
 
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM sh_cannot_force_const_mem_p
+
+#undef TARGET_ASM_RELOC_RW_MASK
+#define TARGET_ASM_RELOC_RW_MASK sh_reloc_rw_mask
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Implement TARGET_HANDLE_OPTION.  */
@@ -861,6 +879,10 @@  sh_override_options (void)
     sh_branch_cost
       = TARGET_SH5 ? 1 : ! TARGET_SH2 || TARGET_HARD_SH4 ? 2 : 1;
 
+  if (TARGET_FDPIC
+      && (TARGET_SHMEDIA || TARGET_SHCOMPACT || !TARGET_SH2))
+    sorry ("non-SH2 FDPIC");
+
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     if (! VALID_REGISTER_P (regno))
       sh_register_names[regno][0] = '\0';
@@ -871,7 +893,7 @@  sh_override_options (void)
 
   flag_omit_frame_pointer = (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG);
 
-  if ((flag_pic && ! TARGET_PREFERGOT)
+  if (((flag_pic || TARGET_FDPIC) && ! TARGET_PREFERGOT)
       || (TARGET_SHMEDIA && !TARGET_PT_FIXED))
     flag_no_function_cse = 1;
 
@@ -1512,11 +1534,13 @@  expand_block_move (rtx *operands)
 	  rtx func_addr_rtx = gen_reg_rtx (Pmode);
 	  rtx r4 = gen_rtx_REG (SImode, 4);
 	  rtx r5 = gen_rtx_REG (SImode, 5);
+	  rtx lab;
 
-	  function_symbol (func_addr_rtx, "__movmemSI12_i4", SFUNC_STATIC);
+	  function_symbol (func_addr_rtx, "__movmemSI12_i4", SFUNC_STATIC,
+			   &lab);
 	  force_into (XEXP (operands[0], 0), r4);
 	  force_into (XEXP (operands[1], 0), r5);
-	  emit_insn (gen_block_move_real_i4 (func_addr_rtx));
+	  emit_insn (gen_block_move_real_i4 (func_addr_rtx, lab));
 	  return 1;
 	}
       else if (! TARGET_SMALLCODE)
@@ -1527,15 +1551,16 @@  expand_block_move (rtx *operands)
 	  rtx r4 = gen_rtx_REG (SImode, 4);
 	  rtx r5 = gen_rtx_REG (SImode, 5);
 	  rtx r6 = gen_rtx_REG (SImode, 6);
+	  rtx lab;
 
 	  entry_name = (bytes & 4 ? "__movmem_i4_odd" : "__movmem_i4_even");
-	  function_symbol (func_addr_rtx, entry_name, SFUNC_STATIC);
+	  function_symbol (func_addr_rtx, entry_name, SFUNC_STATIC, &lab);
 	  force_into (XEXP (operands[0], 0), r4);
 	  force_into (XEXP (operands[1], 0), r5);
 
 	  dwords = bytes >> 3;
 	  emit_insn (gen_move_insn (r6, GEN_INT (dwords - 1)));
-	  emit_insn (gen_block_lump_real_i4 (func_addr_rtx));
+	  emit_insn (gen_block_lump_real_i4 (func_addr_rtx, lab));
 	  return 1;
 	}
       else
@@ -1547,12 +1572,13 @@  expand_block_move (rtx *operands)
       rtx func_addr_rtx = gen_reg_rtx (Pmode);
       rtx r4 = gen_rtx_REG (SImode, 4);
       rtx r5 = gen_rtx_REG (SImode, 5);
+      rtx lab;
 
       sprintf (entry, "__movmemSI%d", bytes);
-      function_symbol (func_addr_rtx, entry, SFUNC_STATIC);
+      function_symbol (func_addr_rtx, entry, SFUNC_STATIC, &lab);
       force_into (XEXP (operands[0], 0), r4);
       force_into (XEXP (operands[1], 0), r5);
-      emit_insn (gen_block_move_real (func_addr_rtx));
+      emit_insn (gen_block_move_real (func_addr_rtx, lab));
       return 1;
     }
 
@@ -1565,8 +1591,9 @@  expand_block_move (rtx *operands)
       rtx r4 = gen_rtx_REG (SImode, 4);
       rtx r5 = gen_rtx_REG (SImode, 5);
       rtx r6 = gen_rtx_REG (SImode, 6);
+      rtx lab;
 
-      function_symbol (func_addr_rtx, "__movmem", SFUNC_STATIC);
+      function_symbol (func_addr_rtx, "__movmem", SFUNC_STATIC, &lab);
       force_into (XEXP (operands[0], 0), r4);
       force_into (XEXP (operands[1], 0), r5);
 
@@ -1579,7 +1606,7 @@  expand_block_move (rtx *operands)
       final_switch = 16 - ((bytes / 4) % 16);
       while_loop = ((bytes / 4) / 16 - 1) * 16;
       emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch)));
-      emit_insn (gen_block_lump_real (func_addr_rtx));
+      emit_insn (gen_block_lump_real (func_addr_rtx, lab));
       return 1;
     }
 
@@ -1592,8 +1619,10 @@  expand_block_move (rtx *operands)
 int
 prepare_move_operands (rtx operands[], enum machine_mode mode)
 {
+  rtx tmp, base, offset;
+
   if ((mode == SImode || mode == DImode)
-      && flag_pic
+      && (flag_pic || TARGET_FDPIC)
       && ! ((mode == Pmode || mode == ptr_mode)
 	    && tls_symbolic_operand (operands[1], Pmode) != TLS_MODEL_NONE))
     {
@@ -1684,12 +1713,22 @@  prepare_move_operands (rtx operands[], enum machine_mode mode)
 	    {
 	    case TLS_MODEL_GLOBAL_DYNAMIC:
 	      tga_ret = gen_rtx_REG (Pmode, R0_REG);
+	      if (TARGET_FDPIC)
+		{
+		  rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+		  emit_move_insn (pic_reg, OUR_FDPIC_REG);
+		}
 	      emit_call_insn (gen_tls_global_dynamic (tga_ret, op1));
 	      op1 = tga_ret;
 	      break;
 
 	    case TLS_MODEL_LOCAL_DYNAMIC:
 	      tga_ret = gen_rtx_REG (Pmode, R0_REG);
+	      if (TARGET_FDPIC)
+		{
+		  rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+		  emit_move_insn (pic_reg, OUR_FDPIC_REG);
+		}
 	      emit_call_insn (gen_tls_local_dynamic (tga_ret, op1));
 
 	      tmp = gen_reg_rtx (Pmode);
@@ -1719,6 +1758,11 @@  prepare_move_operands (rtx operands[], enum machine_mode mode)
 		}
 	      tga_op1 = !can_create_pseudo_p () ? op0 : gen_reg_rtx (Pmode);
 	      tmp = gen_sym2GOTTPOFF (op1);
+	      if (TARGET_FDPIC)
+		{
+		  rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+		  emit_move_insn (pic_reg, OUR_FDPIC_REG);
+		}
 	      emit_insn (gen_tls_initial_exec (tga_op1, tmp));
 	      op1 = tga_op1;
 	      break;
@@ -1746,6 +1790,21 @@  prepare_move_operands (rtx operands[], enum machine_mode mode)
 	}
     }
 
+  if (SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
+    {
+      split_const (operands[1], &base, &offset);
+      if (GET_CODE (base) == SYMBOL_REF
+	  && !offset_within_block_p (base, INTVAL (offset)))
+	{
+	  tmp = can_create_pseudo_p () ? gen_reg_rtx (mode) : operands[0];
+	  emit_move_insn (tmp, base);
+	  if (!arith_operand (offset, mode))
+	    offset = force_reg (mode, offset);
+	  emit_insn (gen_add3_insn (operands[0], tmp, offset));
+	  return 1;
+	}
+    }
+
   return 0;
 }
 
@@ -2693,6 +2752,26 @@  sh_file_start (void)
     }
 }
 
+/* Implementation of TARGET_ASM_INTEGER for SH.  Pointers to functions
+   need to be output as pointers to function descriptors for
+   FDPIC.  */
+
+static bool
+sh_assemble_integer (rtx value, unsigned int size, int aligned_p)
+{
+  if (TARGET_FDPIC
+      && size == UNITS_PER_WORD
+      && GET_CODE (value) == SYMBOL_REF
+      && SYMBOL_REF_FUNCTION_P (value))
+    {
+      fputs ("\t.long\t", asm_out_file);
+      output_addr_const (asm_out_file, value);
+      fputs ("@FUNCDESC\n", asm_out_file);
+      return true;
+    }
+  return default_assemble_integer (value, size, aligned_p);
+}
+
 /* Check if PAT includes UNSPEC_CALLER unspec pattern.  */
 
 static bool
@@ -2721,15 +2800,27 @@  sh_cannot_copy_insn_p (rtx insn)
 {
   rtx pat;
 
-  if (!reload_completed || !flag_pic)
-    return false;
-
   if (!NONJUMP_INSN_P (insn))
     return false;
   if (asm_noperands (insn) >= 0)
     return false;
 
   pat = PATTERN (insn);
+  if (GET_CODE (pat) == CLOBBER || GET_CODE (pat) == USE)
+    return false;
+
+  if (TARGET_FDPIC
+      && GET_CODE (pat) == PARALLEL)
+    {
+      rtx t = XVECEXP (pat, 0, XVECLEN (pat, 0) - 1);
+      if (GET_CODE (t) == USE
+	  && unspec_caller_rtx_p (XEXP (t, 0)))
+	return true;
+    }
+
+  if (!reload_completed || (!flag_pic && !TARGET_FDPIC))
+    return false;
+
   if (GET_CODE (pat) != SET)
     return false;
   pat = SET_SRC (pat);
@@ -3261,6 +3352,7 @@  expand_ashiftrt (rtx *operands)
   rtx wrk;
   char func[18];
   int value;
+  rtx lab;
 
   if (TARGET_SH3)
     {
@@ -3326,8 +3418,8 @@  expand_ashiftrt (rtx *operands)
   /* Load the value into an arg reg and call a helper.  */
   emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
   sprintf (func, "__ashiftrt_r4_%d", value);
-  function_symbol (wrk, func, SFUNC_STATIC);
-  emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk));
+  function_symbol (wrk, func, SFUNC_STATIC, &lab);
+  emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk, lab));
   emit_move_insn (operands[0], gen_rtx_REG (SImode, 4));
   return 1;
 }
@@ -7096,7 +7188,9 @@  sh_expand_prologue (void)
   else
     push_regs (&live_regs_mask, current_function_interrupt);
 
-  if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
+  if (flag_pic
+      && !TARGET_FDPIC
+      && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
     emit_insn (gen_GOTaddr2picreg ());
 
   if (SHMEDIA_REGS_STACK_ADJUST ())
@@ -7106,7 +7200,7 @@  sh_expand_prologue (void)
       function_symbol (gen_rtx_REG (Pmode, R0_REG),
 		       (TARGET_FPU_ANY
 			? "__GCC_push_shmedia_regs"
-			: "__GCC_push_shmedia_regs_nofpu"), SFUNC_GOT);
+			: "__GCC_push_shmedia_regs_nofpu"), SFUNC_GOT, NULL);
       emit_insn (gen_shmedia_save_restore_regs_compact
 		 (GEN_INT (-SHMEDIA_REGS_STACK_ADJUST ())));
     }
@@ -7128,7 +7222,7 @@  sh_expand_prologue (void)
       /* This must NOT go through the PLT, otherwise mach and macl
 	 may be clobbered.  */
       function_symbol (gen_rtx_REG (Pmode, R0_REG),
-		      "__GCC_shcompact_incoming_args", SFUNC_GOT);
+		      "__GCC_shcompact_incoming_args", SFUNC_GOT, NULL);
       emit_insn (gen_shcompact_incoming_args ());
     }
 }
@@ -7207,7 +7301,7 @@  sh_expand_epilogue (bool sibcall_p)
       function_symbol (gen_rtx_REG (Pmode, R0_REG),
 		       (TARGET_FPU_ANY
 			? "__GCC_pop_shmedia_regs"
-			: "__GCC_pop_shmedia_regs_nofpu"), SFUNC_GOT);
+			: "__GCC_pop_shmedia_regs_nofpu"), SFUNC_GOT, NULL);
       /* This must NOT go through the PLT, otherwise mach and macl
 	 may be clobbered.  */
       emit_insn (gen_shmedia_save_restore_regs_compact
@@ -9582,7 +9676,9 @@  nonpic_symbol_mentioned_p (rtx x)
 	  || XINT (x, 1) == UNSPEC_TPOFF
 	  || XINT (x, 1) == UNSPEC_PLT
 	  || XINT (x, 1) == UNSPEC_SYMOFF
-	  || XINT (x, 1) == UNSPEC_PCREL_SYMOFF))
+	  || XINT (x, 1) == UNSPEC_PCREL_SYMOFF
+	  || XINT (x, 1) == UNSPEC_GOTFUNCDESC
+	  || XINT (x, 1) == UNSPEC_GOTOFFFUNCDESC))
     return 0;
 
   fmt = GET_RTX_FORMAT (GET_CODE (x));
@@ -9618,7 +9714,26 @@  legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
       if (reg == 0)
 	reg = gen_reg_rtx (Pmode);
 
-      emit_insn (gen_symGOTOFF2reg (reg, orig));
+      if (TARGET_FDPIC
+	  && GET_CODE (orig) == SYMBOL_REF
+	  && SYMBOL_REF_FUNCTION_P (orig))
+	{
+	  /* Weak functions may be NULL which doesn't work with
+	     GOTOFFFUNCDESC because the runtime offset is not known.  */
+	  if (SYMBOL_REF_WEAK (orig))
+	    emit_insn (gen_symGOTFUNCDESC2reg (reg, orig));
+	  else
+	    emit_insn (gen_symGOTOFFFUNCDESC2reg (reg, orig));
+	}
+      else if (TARGET_FDPIC
+	       && (GET_CODE (orig) == LABEL_REF
+		   || (GET_CODE (orig) == SYMBOL_REF
+		       && SYMBOL_REF_DECL (orig)
+		       && TREE_READONLY (SYMBOL_REF_DECL (orig)))))
+	/* In FDPIC, GOTOFF can only be used for writable data.  */
+	emit_insn (gen_symGOT2reg (reg, orig));
+      else
+	emit_insn (gen_symGOTOFF2reg (reg, orig));
       return reg;
     }
   else if (GET_CODE (orig) == SYMBOL_REF)
@@ -9626,7 +9741,10 @@  legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
       if (reg == 0)
 	reg = gen_reg_rtx (Pmode);
 
-      emit_insn (gen_symGOT2reg (reg, orig));
+      if (TARGET_FDPIC && SYMBOL_REF_FUNCTION_P (orig))
+	emit_insn (gen_symGOTFUNCDESC2reg (reg, orig));
+      else
+	emit_insn (gen_symGOT2reg (reg, orig));
       return reg;
     }
   return orig;
@@ -9686,6 +9804,23 @@  sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
   return x;
 }
 
+static rtx
+sh_delegitimize_address (rtx orig_x)
+{
+  rtx x = orig_x;
+
+  if (GET_CODE (x) != MEM)
+    return orig_x;
+
+  x = XEXP (x, 0);
+  if (GET_CODE (x) == UNSPEC
+      && XINT (x, 1) == UNSPEC_SYMOFF
+      && GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF)
+    return XVECEXP (x, 0, 0);
+
+  return orig_x;
+}
+
 /* Attempt to replace *P, which is an address that needs reloading, with
    a valid memory address for an operand of mode MODE.
    Like for sh_legitimize_address, for the SH we try to get a normal form
@@ -10698,20 +10833,40 @@  sh_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
       emit_insn (gen_initialize_trampoline (tramp, cxt, fnaddr));
       return;
     }
-  emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX),
-		  gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd301d202 : 0xd202d301,
-				SImode));
-  emit_move_insn (adjust_address (tramp_mem, SImode, 4),
-		  gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009422b : 0x422b0009,
-				SImode));
-  emit_move_insn (adjust_address (tramp_mem, SImode, 8), cxt);
-  emit_move_insn (adjust_address (tramp_mem, SImode, 12), fnaddr);
+  if (TARGET_FDPIC)
+    {
+      rtx a = force_reg (Pmode, plus_constant (XEXP (tramp_mem, 0), 8));
+      emit_move_insn (adjust_address (tramp_mem, SImode, 0), a);
+      emit_move_insn (adjust_address (tramp_mem, SImode, 4), OUR_FDPIC_REG);
+      emit_move_insn (adjust_address (tramp_mem, SImode, 8),
+		      gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd203d302 : 0xd302d203,
+				    SImode));
+      emit_move_insn (adjust_address (tramp_mem, SImode, 12),
+		      gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x5c216122 : 0x61225c21,
+				    SImode));
+      emit_move_insn (adjust_address (tramp_mem, SImode, 16),
+		      gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009412b : 0x412b0009,
+				    SImode));
+      emit_move_insn (adjust_address (tramp_mem, SImode, 20), cxt);
+      emit_move_insn (adjust_address (tramp_mem, SImode, 24), fnaddr);
+    }
+  else
+    {
+      emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX),
+		      gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd301d202 : 0xd202d301,
+				    SImode));
+      emit_move_insn (adjust_address (tramp_mem, SImode, 4),
+		      gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009422b : 0x422b0009,
+				    SImode));
+      emit_move_insn (adjust_address (tramp_mem, SImode, 8), cxt);
+      emit_move_insn (adjust_address (tramp_mem, SImode, 12), fnaddr);
+    }
   if (TARGET_HARVARD)
     {
       if (!TARGET_INLINE_IC_INVALIDATE
 	  || (!(TARGET_SH4A_ARCH || TARGET_SH4_300) && TARGET_USERMODE))
 	emit_library_call (function_symbol (NULL, "__ic_invalidate",
-					    FUNCTION_ORDINARY),
+					    FUNCTION_ORDINARY, NULL),
 			   LCT_NORMAL, VOIDmode, 1, tramp, SImode);
       else
 	emit_insn (gen_ic_invalidate_line (tramp));
@@ -11539,10 +11694,18 @@  sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     sibcall = gen_sibcalli_thunk (funexp, const0_rtx);
   else
 #endif
-  if (TARGET_SH2 && flag_pic)
+  if (TARGET_SH2 && (flag_pic || TARGET_FDPIC))
     {
-      sibcall = gen_sibcall_pcrel (funexp, const0_rtx);
-      XEXP (XVECEXP (sibcall, 0, 2), 0) = scratch2;
+      if (TARGET_FDPIC)
+        {
+	  sibcall = gen_sibcall_pcrel_fdpic (funexp, const0_rtx);
+          XEXP (XVECEXP (sibcall, 0, 3), 0) = scratch2;
+        }
+      else
+        {
+	  sibcall = gen_sibcall_pcrel (funexp, const0_rtx);
+          XEXP (XVECEXP (sibcall, 0, 2), 0) = scratch2;
+        }
     }
   else
     {
@@ -11588,11 +11751,24 @@  sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   epilogue_completed = 0;
 }
 
+/* Return an RTX for the address of a function NAME of kind KIND,
+   placing the result in TARGET if not NULL.  LAB should be non-NULL
+   for SFUNC_STATIC, if FDPIC; it will be set to (const_int 0) if jsr
+   should be used, or a label_ref if bsrf should be used.  For FDPIC,
+   both SFUNC_GOT and SFUNC_STATIC will return the address of the
+   function itself, not a function descriptor, so they can only be
+   used with functions not using the FDPIC register that are known to
+   be called directory without a PLT entry.  */
+
 rtx
-function_symbol (rtx target, const char *name, enum sh_function_kind kind)
+function_symbol (rtx target, const char *name, enum sh_function_kind kind,
+		 rtx *lab)
 {
   rtx sym;
 
+  if (lab)
+    *lab = const0_rtx;
+
   /* If this is not an ordinary function, the name usually comes from a
      string literal or an sprintf buffer.  Make sure we use the same
      string consistently, so that cse will be able to unify address loads.  */
@@ -11600,7 +11776,7 @@  function_symbol (rtx target, const char *name, enum sh_function_kind kind)
     name = IDENTIFIER_POINTER (get_identifier (name));
   sym = gen_rtx_SYMBOL_REF (Pmode, name);
   SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION;
-  if (flag_pic)
+  if (flag_pic || TARGET_FDPIC)
     switch (kind)
       {
       case FUNCTION_ORDINARY:
@@ -11615,14 +11791,27 @@  function_symbol (rtx target, const char *name, enum sh_function_kind kind)
 	}
       case SFUNC_STATIC:
 	{
-	  /* ??? To allow cse to work, we use GOTOFF relocations.
-	     we could add combiner patterns to transform this into
-	     straight pc-relative calls with sym2PIC / bsrf when
-	     label load and function call are still 1:1 and in the
-	     same basic block during combine.  */
 	  rtx reg = target ? target : gen_reg_rtx (Pmode);
 
-	  emit_insn (gen_symGOTOFF2reg (reg, sym));
+	  if (TARGET_FDPIC)
+	    {
+	      /* We use PC-relative calls, since GOTOFF can only refer
+		 to writable data.  This works along with
+		 sh_sfunc_call.  */
+	      gcc_assert (lab != NULL);
+	      *lab = PATTERN (gen_call_site ());
+	      emit_insn (gen_sym_label2reg (reg, sym, *lab));
+	    }
+	  else
+	    {
+	      /* ??? To allow cse to work, we use GOTOFF relocations.
+		 we could add combiner patterns to transform this into
+		 straight pc-relative calls with sym2PIC / bsrf when
+		 label load and function call are still 1:1 and in the
+		 same basic block during combine.  */
+	      emit_insn (gen_symGOTOFF2reg (reg, sym));
+	    }
+
 	  sym = reg;
 	  break;
 	}
@@ -12268,4 +12457,83 @@  sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
 
 enum sh_divide_strategy_e sh_div_strategy = SH_DIV_STRATEGY_DEFAULT;
 
+bool
+sh_legitimate_constant_p (rtx x)
+{
+  if (SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
+    {
+      rtx base, offset;
+
+      split_const (x, &base, &offset);
+      if (GET_CODE (base) == SYMBOL_REF
+	  && !offset_within_block_p (base, INTVAL (offset)))
+	return false;
+    }
+
+  if (TARGET_FDPIC
+      && (SYMBOLIC_CONST_P (x)
+	  || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
+	      && SYMBOLIC_CONST_P (XEXP (XEXP (x, 0), 0)))))
+    return false;
+
+  if (TARGET_SHMEDIA)
+    return ((GET_MODE (x) != DFmode
+	     && GET_MODE_CLASS (GET_MODE (x)) != MODE_VECTOR_FLOAT)
+	    || (x) == CONST0_RTX (GET_MODE (x))
+	    || ! TARGET_SHMEDIA_FPU
+	    || TARGET_SHMEDIA64);
+
+  return (GET_CODE (x) != CONST_DOUBLE
+	  || GET_MODE (x) == DFmode || GET_MODE (x) == SFmode
+	  || GET_MODE (x) == DImode || GET_MODE (x) == VOIDmode);
+}
+
+bool
+sh_cannot_force_const_mem_p (rtx x ATTRIBUTE_UNUSED)
+{
+  if (TARGET_FDPIC)
+    return true;
+
+  return false;
+}
+
+/* Emit insns to load the function address from FUNCDESC (an FDPIC
+   function descriptor) into r1 and the GOT address into r12,
+   returning an rtx for r1.  */
+
+rtx
+sh_load_function_descriptor (rtx funcdesc)
+{
+  rtx r1 = gen_rtx_REG (Pmode, R1_REG);
+  rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+  rtx fnaddr = gen_rtx_MEM (Pmode, funcdesc);
+  rtx gotaddr = gen_rtx_MEM (Pmode, plus_constant (funcdesc, 4));
+
+  emit_move_insn (r1, fnaddr);
+  /* The ABI requires the entry point address to be loaded first, so
+     prevent the load from being moved after that of the GOT
+     address.  */
+  emit_insn (gen_blockage ());
+  emit_move_insn (pic_reg, gotaddr);
+  return r1;
+}
+
+/* Return an rtx holding the initial value of the FDPIC register (the
+   FDPIC pointer passed in from the caller).  */
+
+rtx
+sh_our_fdpic_reg (void)
+{
+  return get_hard_reg_initial_val (Pmode, PIC_REG);
+}
+
+/* Relocatable data for FDPIC binaries is not permitted in read-only
+   segments.  */
+
+static int
+sh_reloc_rw_mask (void)
+{
+  return (flag_pic || TARGET_FDPIC) ? 3 : 0;
+}
+
 #include "gt-sh.h"
diff --git a/src/gcc-mainline/gcc/config/sh/sh.h b/src/gcc-mainline/gcc/config/sh/sh.h
index ee3e059..531238e 100644
--- a/src/gcc-mainline/gcc/config/sh/sh.h
+++ b/src/gcc-mainline/gcc/config/sh/sh.h
@@ -94,6 +94,11 @@  do { \
     builtin_define ("__HITACHI__"); \
   if (TARGET_FMOVD) \
     builtin_define ("__FMOVD_ENABLED__"); \
+  if (TARGET_FDPIC) \
+    { \
+      builtin_define ("__SH_FDPIC__"); \
+      builtin_define ("__FDPIC__"); \
+    } \
   builtin_define (TARGET_LITTLE_ENDIAN \
 		  ? "__LITTLE_ENDIAN__" : "__BIG_ENDIAN__"); \
 } while (0)
@@ -133,6 +138,12 @@  do { \
       fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;				\
       call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;			\
     }									\
+  if (TARGET_FDPIC)							\
+    {									\
+      fixed_regs[PIC_REG] = 1;						\
+      call_used_regs[PIC_REG] = 1;					\
+      call_really_used_regs[PIC_REG] = 1;				\
+    }									\
   /* Renesas saves and restores mac registers on call.  */		\
   if (TARGET_HITACHI && ! TARGET_NOMACSAVE)				\
     {									\
@@ -468,7 +479,9 @@  do { \
 #define SH_DIV_STR_FOR_SIZE "call"
 #endif
 
-#define DRIVER_SELF_SPECS "%{m2a:%{ml:%eSH2a does not support little-endian}}"
+#define DRIVER_SELF_SPECS SUBTARGET_DRIVER_SELF_SPECS \
+  "%{m2a:%{ml:%eSH2a does not support little-endian}}"
+#define SUBTARGET_DRIVER_SELF_SPECS
 
 #define OPTIMIZATION_OPTIONS(LEVEL,SIZE) sh_optimization_options (LEVEL, SIZE)
 
@@ -1007,6 +1020,14 @@  extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
    code access to data items.  */
 #define PIC_OFFSET_TABLE_REGNUM	(flag_pic ? PIC_REG : INVALID_REGNUM)
 
+/* For FDPIC, the FDPIC register is call-clobbered (otherwise PLT
+   entries would need to handle saving and restoring it).  */
+#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED TARGET_FDPIC
+
+/* An rtx holding the initial value of the FDPIC register (the FDPIC
+   pointer passed in from the caller).  */
+#define OUR_FDPIC_REG		sh_our_fdpic_reg ()
+
 #define GOT_SYMBOL_NAME "*_GLOBAL_OFFSET_TABLE_"
 
 /* Definitions for register eliminations.
@@ -1790,7 +1811,8 @@  struct sh_args {
    6 000c 00000000 	l2:	.long   function  */
 
 /* Length in units of the trampoline for entering a nested function.  */
-#define TRAMPOLINE_SIZE  (TARGET_SHMEDIA64 ? 40 : TARGET_SH5 ? 24 : 16)
+#define TRAMPOLINE_SIZE \
+  (TARGET_SHMEDIA64 ? 40 : TARGET_SH5 ? 24 : TARGET_FDPIC ? 32 : 16)
 
 /* Alignment required for a trampoline in bits .  */
 #define TRAMPOLINE_ALIGNMENT \
@@ -1851,6 +1873,10 @@  struct sh_args {
       || GENERAL_REGISTER_P ((unsigned) reg_renumber[(REGNO)])) \
    : (REGNO) == R0_REG || (unsigned) reg_renumber[(REGNO)] == R0_REG)
 
+/* True if SYMBOL + OFFSET constants must refer to something within
+   SYMBOL's section.  */
+#define SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P 0
+
 /* Maximum number of registers that can appear in a valid memory
    address.  */
 
@@ -1863,16 +1889,7 @@  struct sh_args {
 /* Nonzero if the constant value X is a legitimate general operand.  */
 /* can_store_by_pieces constructs VOIDmode CONST_DOUBLEs.  */
 
-#define LEGITIMATE_CONSTANT_P(X) \
-  (TARGET_SHMEDIA							\
-   ? ((GET_MODE (X) != DFmode						\
-       && GET_MODE_CLASS (GET_MODE (X)) != MODE_VECTOR_FLOAT)		\
-      || (X) == CONST0_RTX (GET_MODE (X))				\
-      || ! TARGET_SHMEDIA_FPU						\
-      || TARGET_SHMEDIA64)						\
-   : (GET_CODE (X) != CONST_DOUBLE					\
-      || GET_MODE (X) == DFmode || GET_MODE (X) == SFmode		\
-      || GET_MODE (X) == DImode || GET_MODE (X) == VOIDmode))
+#define LEGITIMATE_CONSTANT_P(X) sh_legitimate_constant_p (X)
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
@@ -2529,6 +2546,14 @@  struct sh_args {
 	    output_addr_const (STREAM, XVECEXP (X, 0, 1));		\
 	    fputs ("-.)", STREAM);					\
 	    break;							\
+	  case UNSPEC_GOTFUNCDESC:					\
+	    output_addr_const ((STREAM), XVECEXP ((X), 0, 0));		\
+	    fputs ("@GOTFUNCDESC", (STREAM));				\
+	    break;							\
+	  case UNSPEC_GOTOFFFUNCDESC:					\
+	    output_addr_const ((STREAM), XVECEXP ((X), 0, 0));		\
+	    fputs ("@GOTOFFFUNCDESC", (STREAM));			\
+	    break;							\
 	  default:							\
 	    goto FAIL;							\
 	  }								\
@@ -2674,12 +2699,20 @@  extern int current_function_interrupt;
 #define EH_RETURN_STACKADJ_REGNO STATIC_CHAIN_REGNUM
 #define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (Pmode, EH_RETURN_STACKADJ_REGNO)
 
+#ifdef __SH_FDPIC__
+#define CRT_GET_RFIB_DATA(dbase) \
+  ({ register int r12 __asm__("r12"); (dbase) = r12; })
+#endif
+
 /* We have to distinguish between code and data, so that we apply
    datalabel where and only where appropriate.  Use sdataN for data.  */
 #define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \
- ((flag_pic && (GLOBAL) ? DW_EH_PE_indirect : 0) \
-  | (flag_pic ? DW_EH_PE_pcrel : DW_EH_PE_absptr) \
-  | ((CODE) ? 0 : (TARGET_SHMEDIA64 ? DW_EH_PE_sdata8 : DW_EH_PE_sdata4)))
+  ((TARGET_FDPIC \
+    ? ((GLOBAL) ? DW_EH_PE_indirect | DW_EH_PE_datarel \
+       : DW_EH_PE_pcrel) \
+    : ((flag_pic && (GLOBAL) ? DW_EH_PE_indirect : 0) \
+       | (flag_pic ? DW_EH_PE_pcrel : DW_EH_PE_absptr))) \
+   | ((CODE) ? 0 : (TARGET_SHMEDIA64 ? DW_EH_PE_sdata8 : DW_EH_PE_sdata4)))
 
 /* Handle special EH pointer encodings.  Absolute, pc-relative, and
    indirect are handled automatically.  */
@@ -2692,6 +2725,17 @@  extern int current_function_interrupt;
 	SYMBOL_REF_FLAGS (ADDR) |= SYMBOL_FLAG_FUNCTION; \
 	if (0) goto DONE; \
       } \
+    if (TARGET_FDPIC \
+        && ((ENCODING) & 0xf0) == (DW_EH_PE_indirect | DW_EH_PE_datarel)) \
+      { \
+        fputs ("\t.ualong ", FILE); \
+        output_addr_const (FILE, ADDR); \
+        if (GET_CODE (ADDR) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (ADDR)) \
+          fputs ("@GOTFUNCDESC", FILE); \
+        else \
+          fputs ("@GOT", FILE); \
+        goto DONE; \
+      } \
   } while (0)
 
 #if (defined CRT_BEGIN || defined CRT_END) && ! __SHMEDIA__
diff --git a/src/gcc-mainline/gcc/config/sh/sh.md b/src/gcc-mainline/gcc/config/sh/sh.md
index 495e151..5f9d16d 100644
--- a/src/gcc-mainline/gcc/config/sh/sh.md
+++ b/src/gcc-mainline/gcc/config/sh/sh.md
@@ -99,6 +99,7 @@ 
   (R8_REG	8)
   (R9_REG	9)
   (R10_REG	10)
+  (R12_REG	12)
   (R20_REG	20)
   (R21_REG	21)
   (R22_REG	22)
@@ -165,6 +166,10 @@ 
   ;; (unspec [OFFSET ANCHOR] UNSPEC_PCREL_SYMOFF) == OFFSET - (ANCHOR - .).
   (UNSPEC_PCREL_SYMOFF	46)
 
+  (UNSPEC_GOTFUNCDESC	50)
+  (UNSPEC_GOTOFFFUNCDESC	51)
+  (UNSPEC_INITVAL	52)
+
   ;; These are used with unspec_volatile.
   (UNSPECV_BLOCKAGE	0)
   (UNSPECV_ALIGN	1)
@@ -1602,14 +1607,17 @@ 
 ;; If we let reload allocate r0, then this problem can never happen.
 
 (define_insn "udivsi3_i1"
-  [(set (match_operand:SI 0 "register_operand" "=z")
+  [(set (match_operand:SI 0 "register_operand" "=z,z")
 	(udiv:SI (reg:SI R4_REG) (reg:SI R5_REG)))
    (clobber (reg:SI T_REG))
    (clobber (reg:SI PR_REG))
    (clobber (reg:SI R4_REG))
-   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+   (use (match_operand:SI 1 "arith_reg_operand" "r,r"))
+   (use (match_operand 2 "" "Z,Ccl"))]
   "TARGET_SH1 && ! TARGET_SH4"
-  "jsr	@%1%#"
+  "@
+   jsr	@%1%#
+   bsrf	%1\\n%O2:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
@@ -1659,7 +1667,7 @@ 
 }")
 
 (define_insn "udivsi3_i4"
-  [(set (match_operand:SI 0 "register_operand" "=y")
+  [(set (match_operand:SI 0 "register_operand" "=y,y")
 	(udiv:SI (reg:SI R4_REG) (reg:SI R5_REG)))
    (clobber (reg:SI T_REG))
    (clobber (reg:SI PR_REG))
@@ -1671,15 +1679,18 @@ 
    (clobber (reg:SI R4_REG))
    (clobber (reg:SI R5_REG))
    (use (reg:PSI FPSCR_REG))
-   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+   (use (match_operand:SI 1 "arith_reg_operand" "r,r"))
+   (use (match_operand 2 "" "Z,Ccl"))]
   "TARGET_SH4 && ! TARGET_FPU_SINGLE"
-  "jsr	@%1%#"
+  "@
+   jsr	@%1%#
+   bsrf	%1\\n%O2:%#"
   [(set_attr "type" "sfunc")
    (set_attr "fp_mode" "double")
    (set_attr "needs_delay_slot" "yes")])
 
 (define_insn "udivsi3_i4_single"
-  [(set (match_operand:SI 0 "register_operand" "=y")
+  [(set (match_operand:SI 0 "register_operand" "=y,y")
 	(udiv:SI (reg:SI R4_REG) (reg:SI R5_REG)))
    (clobber (reg:SI T_REG))
    (clobber (reg:SI PR_REG))
@@ -1690,9 +1701,12 @@ 
    (clobber (reg:SI R1_REG))
    (clobber (reg:SI R4_REG))
    (clobber (reg:SI R5_REG))
-   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+   (use (match_operand:SI 1 "arith_reg_operand" "r,r"))
+   (use (match_operand 2 "" "Z,Ccl"))]
   "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE"
-  "jsr	@%1%#"
+  "@
+   jsr	@%1%#
+   bsrf	%1\\n%O2:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
@@ -1747,16 +1761,17 @@ 
 	  emit_move_insn (operands[0], operands[2]);
 	  DONE;
 	}
-      function_symbol (operands[3], \"__udivsi3_i4i\", SFUNC_GOT);
+      function_symbol (operands[3], \"__udivsi3_i4i\", SFUNC_GOT, NULL);
       last = gen_udivsi3_i4_int (operands[0], operands[3]);
     }
   else if (TARGET_DIVIDE_CALL_FP)
     {
-      function_symbol (operands[3], \"__udivsi3_i4\", SFUNC_STATIC);
+      rtx lab;
+      function_symbol (operands[3], \"__udivsi3_i4\", SFUNC_STATIC, &lab);
       if (TARGET_FPU_SINGLE)
-	last = gen_udivsi3_i4_single (operands[0], operands[3]);
+	last = gen_udivsi3_i4_single (operands[0], operands[3], lab);
       else
-	last = gen_udivsi3_i4 (operands[0], operands[3]);
+	last = gen_udivsi3_i4 (operands[0], operands[3], lab);
     }
   else if (TARGET_SHMEDIA_FPU)
     {
@@ -1776,19 +1791,20 @@ 
     {
       function_symbol (operands[3],
 		       TARGET_FPU_ANY ? \"__udivsi3_i4\" : \"__udivsi3\",
-		       SFUNC_STATIC);
+		       SFUNC_STATIC, NULL);
 
       if (TARGET_SHMEDIA)
 	last = gen_udivsi3_i1_media (operands[0], operands[3]);
       else if (TARGET_FPU_ANY)
-	last = gen_udivsi3_i4_single (operands[0], operands[3]);
+	last = gen_udivsi3_i4_single (operands[0], operands[3], const0_rtx);
       else
-	last = gen_udivsi3_i1 (operands[0], operands[3]);
+	last = gen_udivsi3_i1 (operands[0], operands[3], const0_rtx);
     }
   else
     {
-      function_symbol (operands[3], \"__udivsi3\", SFUNC_STATIC);
-      last = gen_udivsi3_i1 (operands[0], operands[3]);
+      rtx lab;
+      function_symbol (operands[3], \"__udivsi3\", SFUNC_STATIC, &lab);
+      last = gen_udivsi3_i1 (operands[0], operands[3], lab);
     }
   emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
   emit_move_insn (gen_rtx_REG (SImode, 5), operands[2]);
@@ -1917,7 +1933,7 @@ 
       emit_move_insn (gen_rtx_REG (DImode, R20_REG), x);
       break;
     }
-  sym = function_symbol (NULL, name, kind);
+  sym = function_symbol (NULL, name, kind, NULL);
   emit_insn (gen_divsi3_media_2 (operands[0], sym));
   DONE;
 }"
@@ -1938,29 +1954,35 @@ 
 }")
 
 (define_insn "divsi3_i4"
-  [(set (match_operand:SI 0 "register_operand" "=y")
+  [(set (match_operand:SI 0 "register_operand" "=y,y")
 	(div:SI (reg:SI R4_REG) (reg:SI R5_REG)))
    (clobber (reg:SI PR_REG))
    (clobber (reg:DF DR0_REG))
    (clobber (reg:DF DR2_REG))
    (use (reg:PSI FPSCR_REG))
-   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+   (use (match_operand:SI 1 "arith_reg_operand" "r,r"))
+   (use (match_operand 2 "" "Z,Ccl"))]
   "TARGET_SH4 && ! TARGET_FPU_SINGLE"
-  "jsr	@%1%#"
+  "@
+   jsr	@%1%#
+   bsrf	%1\\n%O2:%#"
   [(set_attr "type" "sfunc")
    (set_attr "fp_mode" "double")
    (set_attr "needs_delay_slot" "yes")])
 
 (define_insn "divsi3_i4_single"
-  [(set (match_operand:SI 0 "register_operand" "=y")
+  [(set (match_operand:SI 0 "register_operand" "=y,y")
 	(div:SI (reg:SI R4_REG) (reg:SI R5_REG)))
    (clobber (reg:SI PR_REG))
    (clobber (reg:DF DR0_REG))
    (clobber (reg:DF DR2_REG))
    (clobber (reg:SI R2_REG))
-   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+   (use (match_operand:SI 1 "arith_reg_operand" "r,r"))
+   (use (match_operand 2 "" "Z,Ccl"))]
   "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE"
-  "jsr	@%1%#"
+  "@
+   jsr	@%1%#
+   bsrf	%1\\n%O2:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
@@ -2000,16 +2022,17 @@ 
   /* Emit the move of the address to a pseudo outside of the libcall.  */
   if (TARGET_DIVIDE_CALL_TABLE)
     {
-      function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT);
+      function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT, NULL);
       last = gen_divsi3_i4_int (operands[0], operands[3]);
     }
   else if (TARGET_DIVIDE_CALL_FP)
     {
-      function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC);
+      rtx lab;
+      function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC, &lab);
       if (TARGET_FPU_SINGLE)
-	last = gen_divsi3_i4_single (operands[0], operands[3]);
+	last = gen_divsi3_i4_single (operands[0], operands[3], lab);
       else
-	last = gen_divsi3_i4 (operands[0], operands[3]);
+	last = gen_divsi3_i4 (operands[0], operands[3], lab);
     }
   else if (TARGET_SH2A)
     {
@@ -2114,23 +2137,23 @@ 
 	  emit_move_insn (gen_rtx_REG (Pmode, R20_REG), tab_base);
 	}
       if (TARGET_FPU_ANY && TARGET_SH1)
-	function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC);
+	function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC, NULL);
       else if (TARGET_DIVIDE_CALL2)
-	function_symbol (operands[3], \"__sdivsi3_2\", SFUNC_STATIC);
+	function_symbol (operands[3], \"__sdivsi3_2\", SFUNC_STATIC, NULL);
       else
-	function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT);
+	function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT, NULL);
 
       if (TARGET_SHMEDIA)
 	last = ((TARGET_DIVIDE_CALL2 ? gen_divsi3_media_2 : gen_divsi3_i1_media)
 		(operands[0], operands[3]));
       else if (TARGET_FPU_ANY)
-	last = gen_divsi3_i4_single (operands[0], operands[3]);
+	last = gen_divsi3_i4_single (operands[0], operands[3], const0_rtx);
       else
 	last = gen_divsi3_i1 (operands[0], operands[3]);
     }
   else
     {
-      function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT);
+      function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT, NULL);
       last = gen_divsi3_i1 (operands[0], operands[3]);
     }
   emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
@@ -2722,7 +2745,7 @@  label:
     {
       /* The address must be set outside the libcall,
 	 since it goes into a pseudo.  */
-      rtx sym = function_symbol (NULL, \"__mulsi3\", SFUNC_STATIC);
+      rtx sym = function_symbol (NULL, \"__mulsi3\", SFUNC_STATIC, NULL);
       rtx addr = force_reg (SImode, sym);
       rtx insns = gen_mulsi3_call (operands[0], operands[1],
 				   operands[2], addr);
@@ -3693,12 +3716,15 @@  label:
 (define_insn "ashrsi3_n"
   [(set (reg:SI R4_REG)
 	(ashiftrt:SI (reg:SI R4_REG)
-		     (match_operand:SI 0 "const_int_operand" "i")))
+		     (match_operand:SI 0 "const_int_operand" "i,i")))
    (clobber (reg:SI T_REG))
    (clobber (reg:SI PR_REG))
-   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+   (use (match_operand:SI 1 "arith_reg_operand" "r,r"))
+   (use (match_operand 2 "" "Z,Ccl"))]
   "TARGET_SH1"
-  "jsr	@%1%#"
+  "@
+   jsr	@%1%#
+   bsrf	%1\\n%O2:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
@@ -5132,7 +5158,8 @@  label:
     }
   else if (TARGET_SHCOMPACT)
     {
-      operands[1] = function_symbol (NULL, \"__ic_invalidate\", SFUNC_STATIC);
+      operands[1] = function_symbol (NULL, \"__ic_invalidate\", SFUNC_STATIC,
+				     NULL);
       operands[1] = force_reg (Pmode, operands[1]);
       emit_insn (gen_ic_invalidate_line_compact (operands[0], operands[1]));
       DONE;
@@ -5201,7 +5228,7 @@  label:
 
   tramp = force_reg (Pmode, operands[0]);
   sfun = force_reg (Pmode, function_symbol (NULL, \"__init_trampoline\",
-					    SFUNC_STATIC));
+					    SFUNC_STATIC, NULL));
   emit_move_insn (gen_rtx_REG (SImode, R2_REG), operands[1]);
   emit_move_insn (gen_rtx_REG (SImode, R3_REG), operands[2]);
 
@@ -7141,7 +7168,29 @@  label:
 	 (match_operand 1 "" ""))
    (use (reg:PSI FPSCR_REG))
    (clobber (reg:SI PR_REG))]
-  "TARGET_SH1"
+  "TARGET_SH1 && !TARGET_FDPIC"
+  "*
+   {
+     if (TARGET_SH2A && (dbr_sequence_length () == 0))
+	return \"jsr/n\\t@%0\";
+     else
+	return \"jsr\\t@%0%#\";
+   }"
+
+  [(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")
+   (set_attr "fp_set" "unknown")])
+
+(define_insn "calli_fdpic"
+  [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r"))
+	 (match_operand 1 "" ""))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (clobber (reg:SI PR_REG))]
+  "TARGET_SH1 && TARGET_FDPIC"
   "*
    {
      if (TARGET_SH2A && (dbr_sequence_length () == 0))
@@ -7276,7 +7325,29 @@  label:
 	      (match_operand 2 "" "")))
    (use (reg:PSI FPSCR_REG))
    (clobber (reg:SI PR_REG))]
-  "TARGET_SH1"
+  "TARGET_SH1 && !TARGET_FDPIC"
+  "*
+   {
+     if (TARGET_SH2A && (dbr_sequence_length () == 0))
+	return \"jsr/n\\t@%1\";
+     else
+	return \"jsr\\t@%1%#\";
+   }"
+  [(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")
+   (set_attr "fp_set" "unknown")])
+
+(define_insn "call_valuei_fdpic"
+  [(set (match_operand 0 "" "=rf")
+	(call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
+	      (match_operand 2 "" "")))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (clobber (reg:SI PR_REG))]
+  "TARGET_SH1 && TARGET_FDPIC"
   "*
    {
      if (TARGET_SH2A && (dbr_sequence_length () == 0))
@@ -7418,6 +7489,12 @@  label:
   ""
   "
 {
+  if (TARGET_FDPIC)
+    {
+      rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+      emit_move_insn (pic_reg, OUR_FDPIC_REG);
+    }
+
   if (TARGET_SHMEDIA)
     {
       operands[0] = shmedia_prepare_call_address (operands[0], 0);
@@ -7454,7 +7531,7 @@  label:
 
       operands[0]
 	= function_symbol (NULL, \"__GCC_shcompact_call_trampoline\",
-			   SFUNC_GOT);
+			   SFUNC_GOT, NULL);
       operands[0] = force_reg (SImode, operands[0]);
 
       emit_move_insn (r0, func);
@@ -7478,7 +7555,7 @@  label:
       emit_insn (gen_symGOTPLT2reg (reg, XEXP (operands[0], 0)));
       XEXP (operands[0], 0) = reg;
     }
-  if (!flag_pic && TARGET_SH2A
+  if (!flag_pic && !TARGET_FDPIC && TARGET_SH2A
       && MEM_P (operands[0])
       && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
     {
@@ -7489,7 +7566,7 @@  label:
 	  DONE;
 	}
     }
-  if (flag_pic && TARGET_SH2
+  if ((flag_pic || TARGET_FDPIC) && TARGET_SH2
       && MEM_P (operands[0])
       && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
     {
@@ -7502,7 +7579,13 @@  label:
     operands[1] = operands[2];
   }
 
-  emit_call_insn (gen_calli (operands[0], operands[1]));
+  if (TARGET_FDPIC)
+    {
+      operands[0] = sh_load_function_descriptor (operands[0]);
+      emit_call_insn (gen_calli_fdpic (operands[0], operands[1]));
+    }
+  else
+    emit_call_insn (gen_calli (operands[0], operands[1]));
   DONE;
 }")
 
@@ -7583,7 +7666,7 @@  label:
   emit_insn (gen_force_mode_for_call ());
 
   operands[0] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\",
-				 SFUNC_GOT);
+				 SFUNC_GOT, NULL);
   operands[0] = force_reg (SImode, operands[0]);
 
   emit_move_insn (r0, func);
@@ -7609,6 +7692,12 @@  label:
   ""
   "
 {
+  if (TARGET_FDPIC)
+    {
+      rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+      emit_move_insn (pic_reg, OUR_FDPIC_REG);
+    }
+
   if (TARGET_SHMEDIA)
     {
       operands[1] = shmedia_prepare_call_address (operands[1], 0);
@@ -7646,7 +7735,7 @@  label:
 
       operands[1]
 	= function_symbol (NULL, \"__GCC_shcompact_call_trampoline\",
-			   SFUNC_GOT);
+			   SFUNC_GOT, NULL);
       operands[1] = force_reg (SImode, operands[1]);
 
       emit_move_insn (r0, func);
@@ -7672,7 +7761,7 @@  label:
       emit_insn (gen_symGOTPLT2reg (reg, XEXP (operands[1], 0)));
       XEXP (operands[1], 0) = reg;
     }
-  if (!flag_pic && TARGET_SH2A
+  if (!flag_pic && !TARGET_FDPIC && TARGET_SH2A
       && MEM_P (operands[1])
       && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
     {
@@ -7683,7 +7772,7 @@  label:
 	  DONE;
 	}
     }
-  if (flag_pic && TARGET_SH2
+  if ((flag_pic || TARGET_FDPIC) && TARGET_SH2
       && MEM_P (operands[1])
       && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
     {
@@ -7694,7 +7783,14 @@  label:
   else
     operands[1] = force_reg (SImode, XEXP (operands[1], 0));
 
-  emit_call_insn (gen_call_valuei (operands[0], operands[1], operands[2]));
+  if (TARGET_FDPIC)
+    {
+      operands[1] = sh_load_function_descriptor (operands[1]);
+      emit_call_insn (gen_call_valuei_fdpic (operands[0], operands[1],
+					     operands[2]));
+    }
+  else
+    emit_call_insn (gen_call_valuei (operands[0], operands[1], operands[2]));
   DONE;
 }")
 
@@ -7703,7 +7799,21 @@  label:
 	 (match_operand 1 "" ""))
    (use (reg:PSI FPSCR_REG))
    (return)]
-  "TARGET_SH1"
+  "TARGET_SH1 && !TARGET_FDPIC"
+  "jmp	@%0%#"
+  [(set_attr "needs_delay_slot" "yes")
+   (set (attr "fp_mode")
+	(if_then_else (eq_attr "fpu_single" "yes")
+		      (const_string "single") (const_string "double")))
+   (set_attr "type" "jump_ind")])
+
+(define_insn "sibcalli_fdpic"
+  [(call (mem:SI (match_operand:SI 0 "register_operand" "k"))
+	 (match_operand 1 "" ""))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (return)]
+  "TARGET_SH1 && TARGET_FDPIC"
   "jmp	@%0%#"
   [(set_attr "needs_delay_slot" "yes")
    (set (attr "fp_mode")
@@ -7717,7 +7827,22 @@  label:
    (use (match_operand 2 "" ""))
    (use (reg:PSI FPSCR_REG))
    (return)]
-  "TARGET_SH2"
+  "TARGET_SH2 && !TARGET_FDPIC"
+  "braf	%0\\n%O2:%#"
+  [(set_attr "needs_delay_slot" "yes")
+   (set (attr "fp_mode")
+	(if_then_else (eq_attr "fpu_single" "yes")
+		      (const_string "single") (const_string "double")))
+   (set_attr "type" "jump_ind")])
+
+(define_insn "sibcalli_pcrel_fdpic"
+  [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "k"))
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (return)]
+  "TARGET_SH2 && TARGET_FDPIC"
   "braf	%0\\n%O2:%#"
   [(set_attr "needs_delay_slot" "yes")
    (set (attr "fp_mode")
@@ -7747,7 +7872,7 @@  label:
    (use (reg:PSI FPSCR_REG))
    (clobber (match_scratch:SI 2 "=k"))
    (return)]
-  "TARGET_SH2"
+  "TARGET_SH2 && !TARGET_FDPIC"
   "#"
   "reload_completed"
   [(const_int 0)]
@@ -7768,6 +7893,34 @@  label:
 		      (const_string "single") (const_string "double")))
    (set_attr "type" "jump_ind")])
 
+(define_insn_and_split "sibcall_pcrel_fdpic"
+  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" ""))
+	 (match_operand 1 "" ""))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (clobber (match_scratch:SI 2 "=k"))
+   (return)]
+  "TARGET_SH2 && TARGET_FDPIC"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx lab = PATTERN (gen_call_site ());
+  rtx call_insn;
+
+  emit_insn (gen_sym_label2reg (operands[2], operands[0], lab));
+  call_insn = emit_call_insn (gen_sibcalli_pcrel_fdpic (operands[2], operands[1],
+						  copy_rtx (lab)));
+  SIBLING_CALL_P (call_insn) = 1;
+  DONE;
+}"
+  [(set_attr "needs_delay_slot" "yes")
+   (set (attr "fp_mode")
+	(if_then_else (eq_attr "fpu_single" "yes")
+		      (const_string "single") (const_string "double")))
+   (set_attr "type" "jump_ind")])
+
 (define_insn "sibcall_compact"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "k,k"))
 	 (match_operand 1 "" ""))
@@ -7806,6 +7959,12 @@  label:
   ""
   "
 {
+  if (TARGET_FDPIC)
+    {
+      rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+      emit_move_insn (pic_reg, OUR_FDPIC_REG);
+    }
+
   if (TARGET_SHMEDIA)
     {
       operands[0] = shmedia_prepare_call_address (operands[0], 1);
@@ -7852,7 +8011,7 @@  label:
 
       operands[0]
 	= function_symbol (NULL, \"__GCC_shcompact_call_trampoline\",
-			   SFUNC_GOT);
+			   SFUNC_GOT, NULL);
       operands[0] = force_reg (SImode, operands[0]);
 
       /* We don't need a return trampoline, since the callee will
@@ -7878,7 +8037,7 @@  label:
       emit_insn (gen_symGOT2reg (reg, XEXP (operands[0], 0)));
       XEXP (operands[0], 0) = reg;
     }
-  if (flag_pic && TARGET_SH2
+  if ((flag_pic || TARGET_FDPIC) && TARGET_SH2
       && MEM_P (operands[0])
       && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF
       /* The PLT needs the PIC register, but the epilogue would have
@@ -7886,13 +8045,24 @@  label:
 	 static functions.  */
       && SYMBOL_REF_LOCAL_P (XEXP (operands[0], 0)))
     {
-      emit_call_insn (gen_sibcall_pcrel (XEXP (operands[0], 0), operands[1]));
+      if (TARGET_FDPIC)
+        emit_call_insn (gen_sibcall_pcrel_fdpic (XEXP (operands[0], 0),
+       	                                         operands[1]));
+      else
+        emit_call_insn (gen_sibcall_pcrel (XEXP (operands[0], 0),
+                                           operands[1]));
       DONE;
     }
   else
     operands[0] = force_reg (SImode, XEXP (operands[0], 0));
 
-  emit_call_insn (gen_sibcalli (operands[0], operands[1]));
+  if (TARGET_FDPIC)
+    {
+      operands[0] = sh_load_function_descriptor (operands[0]);
+      emit_call_insn (gen_sibcalli_fdpic (operands[0], operands[1]));
+    }
+  else
+    emit_call_insn (gen_sibcalli (operands[0], operands[1]));
   DONE;
 }")
 
@@ -7902,7 +8072,22 @@  label:
 	      (match_operand 2 "" "")))
    (use (reg:PSI FPSCR_REG))
    (return)]
-  "TARGET_SH1"
+  "TARGET_SH1 && !TARGET_FDPIC"
+  "jmp	@%1%#"
+  [(set_attr "needs_delay_slot" "yes")
+   (set (attr "fp_mode")
+	(if_then_else (eq_attr "fpu_single" "yes")
+		      (const_string "single") (const_string "double")))
+   (set_attr "type" "jump_ind")])
+
+(define_insn "sibcall_valuei_fdpic"
+  [(set (match_operand 0 "" "=rf")
+	(call (mem:SI (match_operand:SI 1 "register_operand" "k"))
+	      (match_operand 2 "" "")))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (return)]
+  "TARGET_SH1 && TARGET_FDPIC"
   "jmp	@%1%#"
   [(set_attr "needs_delay_slot" "yes")
    (set (attr "fp_mode")
@@ -7917,7 +8102,23 @@  label:
    (use (match_operand 3 "" ""))
    (use (reg:PSI FPSCR_REG))
    (return)]
-  "TARGET_SH2"
+  "TARGET_SH2 && !TARGET_FDPIC"
+  "braf	%1\\n%O3:%#"
+  [(set_attr "needs_delay_slot" "yes")
+   (set (attr "fp_mode")
+	(if_then_else (eq_attr "fpu_single" "yes")
+		      (const_string "single") (const_string "double")))
+   (set_attr "type" "jump_ind")])
+
+(define_insn "sibcall_valuei_pcrel_fdpic"
+  [(set (match_operand 0 "" "=rf")
+	(call (mem:SI (match_operand:SI 1 "arith_reg_operand" "k"))
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:PSI PIC_REG))
+   (return)]
+  "TARGET_SH2 && TARGET_FDPIC"
   "braf	%1\\n%O3:%#"
   [(set_attr "needs_delay_slot" "yes")
    (set (attr "fp_mode")
@@ -7932,7 +8133,7 @@  label:
    (use (reg:PSI FPSCR_REG))
    (clobber (match_scratch:SI 3 "=k"))
    (return)]
-  "TARGET_SH2"
+  "TARGET_SH2 && !TARGET_FDPIC"
   "#"
   "reload_completed"
   [(const_int 0)]
@@ -7946,6 +8147,39 @@  label:
 							operands[3],
 							operands[2],
 							copy_rtx (lab)));
+							  
+  SIBLING_CALL_P (call_insn) = 1;
+  DONE;
+}"
+  [(set_attr "needs_delay_slot" "yes")
+   (set (attr "fp_mode")
+	(if_then_else (eq_attr "fpu_single" "yes")
+		      (const_string "single") (const_string "double")))
+   (set_attr "type" "jump_ind")])
+
+(define_insn_and_split "sibcall_value_pcrel_fdpic"
+  [(set (match_operand 0 "" "=rf")
+	(call (mem:SI (match_operand:SI 1 "symbol_ref_operand" ""))
+	      (match_operand 2 "" "")))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:PSI PIC_REG))
+   (clobber (match_scratch:SI 3 "=k"))
+   (return)]
+  "TARGET_SH2 && TARGET_FDPIC"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx lab = PATTERN (gen_call_site ());
+  rtx call_insn;
+
+  emit_insn (gen_sym_label2reg (operands[3], operands[1], lab));
+  call_insn = emit_call_insn (gen_sibcall_valuei_pcrel_fdpic (operands[0],
+							      operands[3],
+							      operands[2],
+							      copy_rtx (lab)));
+							  
   SIBLING_CALL_P (call_insn) = 1;
   DONE;
 }"
@@ -7996,6 +8230,12 @@  label:
   ""
   "
 {
+  if (TARGET_FDPIC)
+    {
+      rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+      emit_move_insn (pic_reg, OUR_FDPIC_REG);
+    }
+
   if (TARGET_SHMEDIA)
     {
       operands[1] = shmedia_prepare_call_address (operands[1], 1);
@@ -8043,7 +8283,7 @@  label:
 
       operands[1]
 	= function_symbol (NULL, \"__GCC_shcompact_call_trampoline\",
-			   SFUNC_GOT);
+			   SFUNC_GOT, NULL);
       operands[1] = force_reg (SImode, operands[1]);
 
       /* We don't need a return trampoline, since the callee will
@@ -8070,7 +8310,7 @@  label:
       emit_insn (gen_symGOT2reg (reg, XEXP (operands[1], 0)));
       XEXP (operands[1], 0) = reg;
     }
-  if (flag_pic && TARGET_SH2
+  if ((flag_pic || TARGET_FDPIC) && TARGET_SH2
       && MEM_P (operands[1])
       && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
       /* The PLT needs the PIC register, but the epilogue would have
@@ -8078,15 +8318,28 @@  label:
 	 static functions.  */
       && SYMBOL_REF_LOCAL_P (XEXP (operands[1], 0)))
     {
-      emit_call_insn (gen_sibcall_value_pcrel (operands[0],
-					       XEXP (operands[1], 0),
-					       operands[2]));
+      if (TARGET_FDPIC)
+	emit_call_insn (gen_sibcall_value_pcrel_fdpic (operands[0],
+						       XEXP (operands[1], 0),
+						       operands[2]));
+      else
+	emit_call_insn (gen_sibcall_value_pcrel (operands[0],
+						 XEXP (operands[1], 0),
+						 operands[2]));
       DONE;
     }
   else
     operands[1] = force_reg (SImode, XEXP (operands[1], 0));
 
-  emit_call_insn (gen_sibcall_valuei (operands[0], operands[1], operands[2]));
+  if (TARGET_FDPIC)
+    {
+      operands[1] = sh_load_function_descriptor (operands[1]);
+      emit_call_insn (gen_sibcall_valuei_fdpic (operands[0], operands[1],
+						operands[2]));
+    }
+  else
+    emit_call_insn (gen_sibcall_valuei (operands[0], operands[1],
+					operands[2]));
   DONE;
 }")
 
@@ -8171,7 +8424,7 @@  label:
   emit_insn (gen_force_mode_for_call ());
 
   operands[1] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\",
-				 SFUNC_GOT);
+				 SFUNC_GOT, NULL);
   operands[1] = force_reg (SImode, operands[1]);
 
   emit_move_insn (r0, func);
@@ -8341,6 +8594,13 @@  label:
   [(set_attr "in_delay_slot" "no")
    (set_attr "type" "arith")])
 
+(define_insn_and_split "use_initial_val"
+  [(unspec [(match_operand 0 "pseudo_register_operand" "r")] UNSPEC_INITVAL)]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)])
+
 (define_expand "GOTaddr2picreg"
   [(set (reg:SI R0_REG)
 	(unspec:SI [(const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))]
@@ -8357,6 +8617,13 @@  label:
       DONE;
     }
 
+  if (TARGET_FDPIC)
+    {
+      rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG);
+      emit_move_insn (pic_reg, OUR_FDPIC_REG);
+      DONE;
+    }
+
   operands[0] = gen_rtx_REG (Pmode, PIC_REG);
   operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
 
@@ -8469,8 +8736,14 @@  label:
   ""
   "
 {
+  rtx picreg;
   rtx mem;
 
+  if (TARGET_FDPIC)
+    picreg = OUR_FDPIC_REG;
+  else
+    picreg = gen_rtx_REG (Pmode, PIC_REG);
+
   operands[2] = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
   operands[3] = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
 
@@ -8479,7 +8752,7 @@  label:
       rtx reg = operands[2];
 
       if (Pmode == DImode)
-	{      
+	{
 	  if (flag_pic > 1)
 	    emit_insn (gen_movdi_const_32bit (reg, operands[1]));
 	  else
@@ -8496,9 +8769,7 @@  label:
   else
     emit_move_insn (operands[2], operands[1]);
 
-  emit_move_insn (operands[3], gen_rtx_PLUS (Pmode,
-					     operands[2],
-					     gen_rtx_REG (Pmode, PIC_REG)));
+  emit_move_insn (operands[3], gen_rtx_PLUS (Pmode, operands[2], picreg));
 
   /* When stack protector inserts codes after the result is set to
      R0, @(rX, r12) will cause a spill failure for R0.  Don't schedule
@@ -8544,6 +8815,27 @@  label:
   DONE;
 }")
 
+(define_expand "sym2GOTFUNCDESC"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_GOTFUNCDESC))]
+  "TARGET_FDPIC"
+  "")
+
+(define_expand "symGOTFUNCDESC2reg"
+  [(match_operand 0 "" "") (match_operand 1 "" "")]
+  "TARGET_FDPIC"
+  "
+{
+  rtx gotsym, insn;
+
+  gotsym = gen_sym2GOTFUNCDESC (operands[1]);
+  PUT_MODE (gotsym, Pmode);
+  insn = emit_insn (gen_symGOT_load (operands[0], gotsym));
+
+  MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1;
+
+  DONE;
+}")
+
 (define_expand "symGOTPLT2reg"
   [(match_operand 0 "" "") (match_operand 1 "" "")]
   ""
@@ -8567,23 +8859,50 @@  label:
   ""
   "
 {
+  rtx picreg;
   rtx gotoffsym, insn;
   rtx t = (!can_create_pseudo_p ()
 	   ? operands[0]
 	   : gen_reg_rtx (GET_MODE (operands[0])));
 
+  if (TARGET_FDPIC)
+    picreg = OUR_FDPIC_REG;
+  else
+    picreg = gen_rtx_REG (Pmode, PIC_REG);
+
   gotoffsym = gen_sym2GOTOFF (operands[1]);
   PUT_MODE (gotoffsym, Pmode);
   emit_move_insn (t, gotoffsym);
-  insn = emit_move_insn (operands[0],
-			 gen_rtx_PLUS (Pmode, t,
-				       gen_rtx_REG (Pmode, PIC_REG)));
+  insn = emit_move_insn (operands[0], gen_rtx_PLUS (Pmode, t, picreg));
 
   set_unique_reg_note (insn, REG_EQUAL, operands[1]);
 
   DONE;
 }")
 
+(define_expand "sym2GOTOFFFUNCDESC"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_GOTOFFFUNCDESC))]
+  "TARGET_FDPIC"
+  "")
+
+(define_expand "symGOTOFFFUNCDESC2reg"
+  [(match_operand 0 "" "") (match_operand 1 "" "")]
+  "TARGET_FDPIC"
+  "
+{
+  rtx picreg = OUR_FDPIC_REG;
+  rtx gotoffsym;
+  rtx t = (!can_create_pseudo_p ()
+	   ? operands[0]
+	   : gen_reg_rtx (GET_MODE (operands[0])));
+
+  gotoffsym = gen_sym2GOTOFFFUNCDESC (operands[1]);
+  PUT_MODE (gotoffsym, Pmode);
+  emit_move_insn (t, gotoffsym);
+  emit_move_insn (operands[0], gen_rtx_PLUS (Pmode, t, picreg));
+  DONE;
+}")
+
 (define_expand "symPLT_label2reg"
   [(set (match_operand:SI 0 "" "")
 	(const:SI
@@ -9059,7 +9378,8 @@  mov.l\\t1f,r0\\n\\
 {
   rtx reg = gen_rtx_REG (Pmode, R0_REG);
 
-  function_symbol (reg, \"__GCC_shcompact_return_trampoline\", SFUNC_STATIC);
+  function_symbol (reg, \"__GCC_shcompact_return_trampoline\", SFUNC_STATIC,
+		   NULL);
   emit_jump_insn (gen_shcompact_return_tramp_i ());
   DONE;
 }")
@@ -9602,18 +9922,22 @@  mov.l\\t1f,r0\\n\\
 (define_insn "block_move_real"
   [(parallel [(set (mem:BLK (reg:SI R4_REG))
 		   (mem:BLK (reg:SI R5_REG)))
-	      (use (match_operand:SI 0 "arith_reg_operand" "r"))
+	      (use (match_operand:SI 0 "arith_reg_operand" "r,r"))
+	      (use (match_operand 1 "" "Z,Ccl"))
 	      (clobber (reg:SI PR_REG))
 	      (clobber (reg:SI R0_REG))])]
   "TARGET_SH1 && ! TARGET_HARD_SH4"
-  "jsr	@%0%#"
+  "@
+   jsr	@%0%#
+   bsrf	%0\\n%O1:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
 (define_insn "block_lump_real"
   [(parallel [(set (mem:BLK (reg:SI R4_REG))
 		   (mem:BLK (reg:SI R5_REG)))
-	      (use (match_operand:SI 0 "arith_reg_operand" "r"))
+	      (use (match_operand:SI 0 "arith_reg_operand" "r,r"))
+	      (use (match_operand 1 "" "Z,Ccl"))
 	      (use (reg:SI R6_REG))
 	      (clobber (reg:SI PR_REG))
 	      (clobber (reg:SI T_REG))
@@ -9622,27 +9946,33 @@  mov.l\\t1f,r0\\n\\
 	      (clobber (reg:SI R6_REG))
 	      (clobber (reg:SI R0_REG))])]
   "TARGET_SH1 && ! TARGET_HARD_SH4"
-  "jsr	@%0%#"
+  "@
+   jsr	@%0%#
+   bsrf	%0\\n%O1:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
 (define_insn "block_move_real_i4"
   [(parallel [(set (mem:BLK (reg:SI R4_REG))
 		   (mem:BLK (reg:SI R5_REG)))
-	      (use (match_operand:SI 0 "arith_reg_operand" "r"))
+	      (use (match_operand:SI 0 "arith_reg_operand" "r,r"))
+	      (use (match_operand 1 "" "Z,Ccl"))
 	      (clobber (reg:SI PR_REG))
 	      (clobber (reg:SI R0_REG))
 	      (clobber (reg:SI R1_REG))
 	      (clobber (reg:SI R2_REG))])]
   "TARGET_HARD_SH4"
-  "jsr	@%0%#"
+  "@
+   jsr	@%0%#
+   bsrf	%0\\n%O1:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
 (define_insn "block_lump_real_i4"
   [(parallel [(set (mem:BLK (reg:SI R4_REG))
 		   (mem:BLK (reg:SI R5_REG)))
-	      (use (match_operand:SI 0 "arith_reg_operand" "r"))
+	      (use (match_operand:SI 0 "arith_reg_operand" "r,r"))
+	      (use (match_operand 1 "" "Z,Ccl"))
 	      (use (reg:SI R6_REG))
 	      (clobber (reg:SI PR_REG))
 	      (clobber (reg:SI T_REG))
@@ -9654,7 +9984,9 @@  mov.l\\t1f,r0\\n\\
 	      (clobber (reg:SI R2_REG))
 	      (clobber (reg:SI R3_REG))])]
   "TARGET_HARD_SH4"
-  "jsr	@%0%#"
+  "@
+   jsr	@%0%#
+   bsrf	%0\\n%O1:%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
diff --git a/src/gcc-mainline/gcc/config/sh/sh.opt b/src/gcc-mainline/gcc/config/sh/sh.opt
index 95e2ca4..cae464d 100644
--- a/src/gcc-mainline/gcc/config/sh/sh.opt
+++ b/src/gcc-mainline/gcc/config/sh/sh.opt
@@ -248,6 +248,10 @@  mdivsi3_libfunc=
 Target RejectNegative Joined Var(sh_divsi3_libfunc) Init("")
 Specify name for 32 bit signed division function
 
+mfdpic
+Target Report Var(TARGET_FDPIC)
+Generate ELF FDPIC code
+
 mfmovd
 Target RejectNegative Mask(FMOVD)
 Enable the use of 64-bit floating point registers in fmov instructions.  See -mdalign if 64-bit alignment is required.
diff --git a/src/gcc-mainline/gcc/config/sh/t-uclinux b/src/gcc-mainline/gcc/config/sh/t-uclinux
new file mode 100644
index 0000000..13f006a
--- /dev/null
+++ b/src/gcc-mainline/gcc/config/sh/t-uclinux
@@ -0,0 +1,4 @@ 
+# Compile crtbeginS.o and crtendS.o with pic.
+CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC
+
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o $(OPT_EXTRA_PARTS)
diff --git a/src/gcc-mainline/gcc/config/sh/uclinux.h b/src/gcc-mainline/gcc/config/sh/uclinux.h
new file mode 100644
index 0000000..e02b17d
--- /dev/null
+++ b/src/gcc-mainline/gcc/config/sh/uclinux.h
@@ -0,0 +1,96 @@ 
+/* Definitions for SH based uClinux system using ELF objects with
+   special linker post-processing to produce FLAT executables.
+
+   Copyright (C) 2008
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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 3, or (at your option)
+any later version.
+
+GCC 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 GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared:crt1.o%s} crti.o%s \
+   %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}" \
+   FDPIC_STARTFILE_SPEC
+
+#undef  ENDFILE_SPEC
+#define ENDFILE_SPEC "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+
+#define LINK_EH_SPEC "%{mfdpic:%{!static:--eh-frame-hdr}} "
+
+#ifdef FDPIC_DEFAULT
+#undef SUBTARGET_LINK_SPEC
+#define SUBTARGET_LINK_SPEC \
+  "%{shared:-shared} \
+   %{!static: \
+     %{rdynamic:-export-dynamic} \
+     %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}} \
+   %{static:-static}"
+#undef SUBTARGET_LINK_EMUL_SUFFIX
+#define SUBTARGET_LINK_EMUL_SUFFIX "_fd"
+#undef SUBTARGET_DRIVER_SELF_SPECS
+#define SUBTARGET_DRIVER_SELF_SPECS "%{!mno-fdpic:-mfdpic} "
+#undef SUBTARGET_ASM_SPEC
+#define SUBTARGET_ASM_SPEC "%{!mno-fdpic:--fdpic}"
+#define FDPIC_STARTFILE_SPEC "%{!mno-fdpic: crtreloc.o%s}"
+#else
+#undef SUBTARGET_LINK_SPEC
+#define SUBTARGET_LINK_SPEC "%{shared:-shared} %{static:-static} %{!elf2flt*:-elf2flt}"
+#undef SUBTARGET_LINK_EMUL_SUFFIX
+#define SUBTARGET_LINK_EMUL_SUFFIX "_uclinux"
+#define FDPIC_STARTFILE_SPEC "%{mfdpic: crtreloc.o%s}"
+#endif
+
+/* While the speed-optimized implementations of udivsi3_i4i / sdivsi3_i4i
+   in libgcc are not available for SH2, the space-optimized ones in
+   libgcc-Os-4-200 are.  Thus, when not optimizing for space, link
+   libgcc-Os-4-200 after libgcc, so that -mdiv=call-table works for -m2.  */
+#undef LIBGCC_SPEC
+#define LIBGCC_SPEC "%{Os: -lgcc-Os-4-200} -lgcc %{!Os: -lgcc-Os-4-200}"
+
+/* we have init/fini section. */
+#define HAS_INIT_SECTION
+
+/* Bring in standard linux defines */
+#undef TARGET_OS_CPP_BUILTINS
+#define TARGET_OS_CPP_BUILTINS()		\
+  do						\
+    {						\
+	builtin_define ("__gnu_linux__");	\
+	builtin_define_std ("linux");		\
+	builtin_define_std ("unix");		\
+	builtin_assert ("system=linux");	\
+	builtin_assert ("system=unix");		\
+	builtin_assert ("system=posix");	\
+	builtin_define ("__uClinux__");		\
+    }						\
+  while (0)
+
+/* The GNU C++ standard library requires that these macros be defined.  */
+#undef CPLUSPLUS_CPP_SPEC
+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+
+/* Since libgcc is compiled with -fpic for this target, we can't use
+   __sdivsi3_1 as the division strategy for -O0 and -Os.  */
+#undef SH_DIV_STRATEGY_DEFAULT
+#define SH_DIV_STRATEGY_DEFAULT SH_DIV_CALL2
+#undef SH_DIV_STR_FOR_SIZE
+#define SH_DIV_STR_FOR_SIZE "call2"
+
+/* The uclinux binary format relies on relocations against a segment being
+   within that segment.  Conservatively apply this rule to individual
+   sections.  */
+#undef SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P
+#define SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P 1
diff --git a/src/gcc-mainline/gcc/doc/install.texi b/src/gcc-mainline/gcc/doc/install.texi
index fc9b988..188556a 100644
--- a/src/gcc-mainline/gcc/doc/install.texi
+++ b/src/gcc-mainline/gcc/doc/install.texi
@@ -1545,6 +1545,10 @@  When neither of these configure options are used, the default will be
 128-bit @code{long double} when built against GNU C Library 2.4 and later,
 64-bit @code{long double} otherwise.
 
+@item --enable-fdpic
+On SH uClinux systems, generate ELF FDPIC code rather than code
+expected to be postprocessed into the FLT binary format.
+
 @item --with-gmp=@var{pathname}
 @itemx --with-gmp-include=@var{pathname}
 @itemx --with-gmp-lib=@var{pathname}
diff --git a/src/gcc-mainline/gcc/doc/invoke.texi b/src/gcc-mainline/gcc/doc/invoke.texi
index edce703..20e8290 100644
--- a/src/gcc-mainline/gcc/doc/invoke.texi
+++ b/src/gcc-mainline/gcc/doc/invoke.texi
@@ -16509,6 +16509,11 @@  to generate symbols that will cause ptabs / ptrel to trap.
 This option is only meaningful when @option{-mno-pt-fixed} is in effect.
 It will then prevent cross-basic-block cse, hoisting and most scheduling
 of symbol loads.  The default is @option{-mno-invalid-symbols}.
+
+@item -mfdpic
+@opindex fdpic
+Generate code using the FDPIC ABI for uClinux, as documented at
+@w{@uref{http://www.codesourcery.com/public/docs/sh-fdpic/sh-fdpic-abi.txt}}.
 @end table
 
 @node SPARC Options
diff --git a/src/gcc-mainline/gcc/longlong.h b/src/gcc-mainline/gcc/longlong.h
index 49daa6e..aea5dec 100644
--- a/src/gcc-mainline/gcc/longlong.h
+++ b/src/gcc-mainline/gcc/longlong.h
@@ -988,6 +988,34 @@  UDItype __umulsidi3 (USItype, USItype);
 /* This is the same algorithm as __udiv_qrnnd_c.  */
 #define UDIV_NEEDS_NORMALIZATION 1
 
+#ifdef __FDPIC__
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    Wtype dummy_;								\
+    extern UWtype __udiv_qrnnd_16 (UWtype, UWtype)			\
+                        __attribute__ ((visibility ("hidden")));	\
+    /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */	\
+    __asm__ (								\
+	"mov%M5 %5,r5\n"						\
+"	mov r12,%2\n"							\
+"	swap.w %4,r4\n"							\
+"	swap.w r5,r6\n"							\
+"	mov.l @%6,r1\n"							\
+"	mov.l @(4,%6),r12\n"						\
+"	jsr @r1\n"							\
+"	shll16 r6\n"							\
+"	swap.w r4,r4\n"							\
+"	mov.l @%6,r1\n"							\
+"	mov.l @(4,%6),r12\n"						\
+"	jsr @r1\n"							\
+"	mov %2,r12\n"							\
+"	swap.w r1,%0\n"							\
+"	or r1,%0"							\
+	: "=r" (q), "=&z" (r), "=&r" (dummy_)				\
+	: "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16)		\
+	: "r1", "r2", "r4", "r5", "r6", "pr", "t");			\
+  } while (0)
+#else
 #define udiv_qrnnd(q, r, n1, n0, d) \
   do {									\
     extern UWtype __udiv_qrnnd_16 (UWtype, UWtype)			\
@@ -1007,7 +1035,7 @@  UDItype __umulsidi3 (USItype, USItype);
 	: "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16)		\
 	: "r1", "r2", "r4", "r5", "r6", "pr", "t");			\
   } while (0)
-
+#endif
 #define UDIV_TIME 80
 
 #define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
diff --git a/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c b/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c
index 54422de..f9b2da2 100644
--- a/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c
+++ b/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c
@@ -1,6 +1,7 @@ 
 /* Check that -mrelax works.  */
 /* { dg-do run { target { { sh-*-* sh?-*-* } && { ! { sh*-*-vxworks* && nonpic } } } } } */
 /* { dg-options "-O1 -mrelax" } */
+/* { dg-xfail-if "" { "sh*-*-uclinux" } { "*" } { "" } } */
 
 extern void abort (void);
 extern int qwerty (int);
diff --git a/src/gcc-mainline/libgcc/config.host b/src/gcc-mainline/libgcc/config.host
index 35dd250..a61ad27 100644
--- a/src/gcc-mainline/libgcc/config.host
+++ b/src/gcc-mainline/libgcc/config.host
@@ -519,6 +519,7 @@  score-*-elf)
 sh-*-elf* | sh[12346l]*-*-elf* | \
 sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \
   sh-*-linux* | sh[2346lbe]*-*-linux* | \
+  sh-*-uclinux* | sh[2346lbe]*-*-uclinux* | \
   sh-*-netbsdelf* | shl*-*-netbsdelf* | sh5-*-netbsd* | sh5l*-*-netbsd* | \
    sh64-*-netbsd* | sh64l*-*-netbsd*)
 	case ${host} in