Index: gcc/config/arm/arm-protos.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.60.4.20
diff -u -r1.60.4.20 arm-protos.h
--- gcc/config/arm/arm-protos.h	29 Mar 2005 03:00:11 -0000	1.60.4.20
+++ gcc/config/arm/arm-protos.h	23 Apr 2005 04:41:06 -0000
@@ -64,6 +64,7 @@
 extern enum reg_class vfp_secondary_reload_class (enum machine_mode, rtx);
 extern int tls_symbolic_operand (rtx, enum machine_mode);
 extern bool arm_tls_operand_p (rtx x);
+extern bool arm_pc_pic_operand_p (rtx x);
 
 /* Predicates.  */
 extern int s_register_operand (rtx, enum machine_mode);
Index: gcc/config/arm/arm.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.303.2.79
diff -u -r1.303.2.79 arm.c
--- gcc/config/arm/arm.c	12 Apr 2005 06:17:07 -0000	1.303.2.79
+++ gcc/config/arm/arm.c	23 Apr 2005 04:41:09 -0000
@@ -1003,7 +1003,7 @@
   
   /* If stack checking is disabled, we can use r10 as the PIC register,
      which keeps r9 available.  */
-  if (flag_pic)
+  if (0 && flag_pic)
     arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
   
   if (TARGET_APCS_FLOAT)
@@ -3120,6 +3120,10 @@
 rtx
 legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 {
+  if (GET_CODE (orig) == UNSPEC
+      && XINT (orig, 1) == UNSPEC_GOTSLOTPC)
+    abort ();
+
   if (GET_CODE (orig) == SYMBOL_REF
       || GET_CODE (orig) == LABEL_REF)
     {
@@ -3149,27 +3153,80 @@
       else
 	address = reg;
 
-      if (TARGET_ARM)
-	emit_insn (gen_pic_load_addr_arm (address, orig));
-      else
-	emit_insn (gen_pic_load_addr_thumb (address, orig));
+      if (arm_pic_register != INVALID_REGNUM)
+	{
+	  /* Using GP-based PIC addressing.  */
+	  if (TARGET_ARM)
+	    emit_insn (gen_pic_load_addr_arm (address, orig));
+	  else
+	    emit_insn (gen_pic_load_addr_thumb (address, orig));
+
+	  if ((GET_CODE (orig) == LABEL_REF
+	       || (GET_CODE (orig) == SYMBOL_REF && 
+		   SYMBOL_REF_LOCAL_P (orig)))
+	      && NEED_GOT_RELOC)
+	    pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
+	  else
+	    {
+	      pic_ref = gen_rtx_MEM (Pmode,
+				     gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
+						   address));
+	      RTX_UNCHANGING_P (pic_ref) = 1;
+	    }
 
-      if ((GET_CODE (orig) == LABEL_REF
-	   || (GET_CODE (orig) == SYMBOL_REF && 
-	       SYMBOL_REF_LOCAL_P (orig)))
-	  && NEED_GOT_RELOC)
-	pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
+	  current_function_uses_pic_offset_table = 1;
+	}
       else
 	{
-	  pic_ref = gen_rtx_MEM (Pmode,
-				 gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
-					       address));
-	  RTX_UNCHANGING_P (pic_ref) = 1;
+	  /* Using PC-based PIC addressing.  */
+	  rtx label, tmp;
+	  int offset;
+
+	  label = gen_label_rtx ();
+	  offset = TARGET_ARM ? 8 : 4;
+
+	  if (GET_CODE (orig) == LABEL_REF 
+	      || (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (orig)))
+	    {
+	      /* This symbol is defined locally.  We don't need a GOT entry.  */
+	      tmp = gen_rtx_MINUS (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig), UNSPEC_PIC_SYM), gen_rtx_PLUS (Pmode, 
+							      gen_rtx_LABEL_REF (Pmode, label),
+							      GEN_INT (offset)));
+
+	      load_tls_operand (tmp, address);
+
+	      if (TARGET_ARM)
+		emit_insn (gen_pic_add_dot_plus_eight (address, label));
+	      else
+		emit_insn (gen_pic_add_dot_plus_four (address, label));
+	    }
+	  else
+	    {
+	      rtx x = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig), UNSPEC_GOTSLOTPC);
+	      rtx dummy_label;
+
+	      dummy_label = gen_label_rtx ();
+	      LABEL_PRESERVE_P (dummy_label) = 1;
+	      LABEL_NUSES (dummy_label) = 1;
+	      
+	      tmp = gen_rtx_MINUS (Pmode, x, gen_rtx_PLUS (Pmode, 
+							   gen_rtx_LABEL_REF (Pmode, label),
+							   GEN_INT (offset)));
+
+	      load_tls_operand (tmp, address);
+
+	      if (TARGET_ARM)
+		emit_insn (gen_tls_load_dot_plus_eight (address, address, label, dummy_label));
+	      else
+		emit_insn (gen_tls_load_dot_plus_four (address, address, label, dummy_label));
+	    }
+
+	  pic_ref = address;
 	}
 
       insn = emit_move_insn (reg, pic_ref);
 #endif
-      current_function_uses_pic_offset_table = 1;
+
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
 	 by loop.  */
       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
@@ -3179,11 +3236,17 @@
   else if (GET_CODE (orig) == CONST)
     {
       rtx base, offset;
+      bool minus = FALSE;
 
       if (GET_CODE (XEXP (orig, 0)) == PLUS
 	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
 	return orig;
 
+      if (GET_CODE (XEXP (orig, 0)) == MINUS
+	  && GET_CODE (XEXP (XEXP (orig, 0), 0)) == UNSPEC
+	  && XINT (XEXP (XEXP (orig, 0), 0), 1) == UNSPEC_GOTSLOTPC)
+	return orig;
+
       if (GET_CODE (XEXP (orig, 0)) == UNSPEC)
 	return orig;
 
@@ -3201,6 +3264,13 @@
 	  offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
 					   base == reg ? 0 : reg);
 	}
+      else if (GET_CODE (XEXP (orig, 0)) == MINUS)
+	{
+	  minus = TRUE;
+	  base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+	  offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+					   base == reg ? 0 : reg);
+	}
       else
 	abort ();
 
@@ -3228,7 +3298,7 @@
 	  return reg;
 	}
 
-      return gen_rtx_PLUS (Pmode, base, offset);
+      return minus ? gen_rtx_MINUS (Pmode, base, offset) : gen_rtx_PLUS (Pmode, base, offset);
     }
 
   return orig;
@@ -3267,7 +3337,7 @@
   rtx l1, pic_tmp, pic_tmp2, pic_rtx;
   rtx global_offset_table;
 
-  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
+  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE || arm_pic_register == INVALID_REGNUM)
     return;
 
   if (!flag_pic)
@@ -3341,8 +3411,11 @@
 static int
 pcrel_constant_p (rtx x)
 {
+  if (GET_CODE (x) == CONST)
+    return pcrel_constant_p (XEXP (x, 0));
+
   if (GET_CODE (x) == MINUS)
-    return symbol_mentioned_p (XEXP (x, 0)) && label_mentioned_p (XEXP (x, 1));
+    return (((GET_CODE (XEXP (x, 0)) == UNSPEC && XINT (XEXP (x, 0), 1) == UNSPEC_PIC_SYM)) || symbol_mentioned_p (XEXP (x, 0))) && label_mentioned_p (XEXP (x, 1));
 
   if (GET_CODE (x) == UNSPEC
       && XINT (x, 1) == UNSPEC_TLS
@@ -3946,12 +4019,32 @@
   return SYMBOL_REF_TLS_MODEL (op);
 }
 
+bool
+arm_pc_pic_operand_p (rtx op)
+{
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op, 0)) == MINUS
+      && GET_CODE (XEXP (XEXP (op, 0), 0)) == UNSPEC
+      && XINT (XEXP (XEXP (op, 0), 0), 1) == UNSPEC_GOTSLOTPC)
+    return 1;
+
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op, 0)) == MINUS
+      && GET_CODE (XEXP (XEXP (op, 0), 0)) == UNSPEC
+      && XINT (XEXP (XEXP (op, 0), 0), 1) == UNSPEC_PIC_SYM)
+    return 1;
+
+  return 0;
+}
+
 /* Valid input to a move instruction.  */
 int
 move_input_operand (rtx op, enum machine_mode mode)
 {
   if (tls_symbolic_operand (op, mode))
     return 0;
+  if (pcrel_constant_p (op))
+    return 1;
   return general_operand (op, mode);
 }
 
@@ -15634,11 +15727,34 @@
   return TRUE;
 }
 
+static bool
+arm_emit_got_decoration (FILE *fp, rtx x)
+{
+  rtx val;
+
+  val = XVECEXP (x, 0, 0);
+
+  fputs ("_gotslotpc_(", fp);
+
+  output_addr_const (fp, val);
+
+  fputc (')', fp);
+
+  return TRUE;
+}
+
 bool
 arm_output_addr_const_extra (FILE *fp, rtx x)
 {
   if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
     return arm_emit_tls_decoration (fp, x);
+  else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_GOTSLOTPC)
+    return arm_emit_got_decoration (fp, x);
+  else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PIC_SYM)
+    {
+      output_addr_const (fp, XVECEXP (x, 0, 0));
+      return TRUE;
+    }
   else if (GET_CODE (x) == CONST_VECTOR)
     return arm_emit_vector_const (fp, x);
   
Index: gcc/config/arm/arm.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.145.2.31
diff -u -r1.145.2.31 arm.md
--- gcc/config/arm/arm.md	28 Mar 2005 19:04:37 -0000	1.145.2.31
+++ gcc/config/arm/arm.md	23 Apr 2005 04:41:11 -0000
@@ -88,6 +88,7 @@
    (UNSPEC_WMADDS   18) ; Used by the intrinsic form of the iWMMXt WMADDS instruction.
    (UNSPEC_WMADDU   19) ; Used by the intrinsic form of the iWMMXt WMADDU instruction.
    (UNSPEC_TLS      20) ; A symbol that has been treated properly for TLS usage.
+   (UNSPEC_GOTSLOTPC 21)
   ]
 )
 
@@ -4179,7 +4180,8 @@
         && (CONSTANT_P (operands[1])
 	   || symbol_mentioned_p (operands[1])
 	   || label_mentioned_p (operands[1]))
-	&& ! tls_mentioned_p (operands[1]))
+	&& ! tls_mentioned_p (operands[1])
+	&& ! arm_pc_pic_operand_p (operands[1]))
       operands[1] = legitimize_pic_address (operands[1], SImode,
 					    (no_new_pseudos ? operands[0] : 0));
   } 
@@ -4412,7 +4414,8 @@
 			(mem:SI (unspec:SI [(plus:SI (match_dup 0)
 			     			     (const (plus:SI (pc) (const_int 8))))]
 		   		 UNSPEC_PIC_BASE)))	
-   	      (use (label_ref (match_operand 1 "" "")))])]
+   	      (use (label_ref (match_operand 1 "" "")))
+	      (use (label_ref (match_operand 1 "" "")))])]
   ""
 )
 
