Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 170267)
+++ gcc/config/mips/mips.md	(working copy)
@@ -97,6 +97,8 @@ (define_c_enum "unspec" [
   UNSPEC_UPDATE_GOT_VERSION
 
   ;; Symbolic accesses.
+  UNSPEC_LA_EXTEND
+  UNSPEC_LA_EXTEND_LO
   UNSPEC_LOAD_CALL
   UNSPEC_LOAD_GOT
   UNSPEC_TLS_LDM
@@ -2813,8 +2815,33 @@ (define_insn "*<optab>_trunc<mode>_exts"
 
 (define_expand "zero_extendsidi2"
   [(set (match_operand:DI 0 "register_operand")
-        (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
-  "TARGET_64BIT")
+        (zero_extend:DI (match_operand:SI 1 "general_operand")))]
+  "TARGET_64BIT"
+{
+  if (immediate_operand (operands[1], SImode))
+    {
+      mips_expand_zero_extend_symbol (operands[0], operands[1]);
+      DONE;
+    }
+})
+
+(define_insn "zero_extendsidi_high_address"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+        (unspec:DI [(zero_extend:DI (match_operand:SI 1 "immediate_operand" "i"))] UNSPEC_LA_EXTEND))]
+  "TARGET_64BIT"
+  "ori\t%0,%.,%h1"
+  [(set_attr "move_type" "const")
+   (set_attr "mode" "DI")])
+
+(define_insn "zero_extendsidi_low_address"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+         (unspec:DI [(lo_sum:DI 
+                       (match_operand:DI 1 "register_operand" "d")
+                       (match_operand:SI 2 "immediate_operand" "i"))] UNSPEC_LA_EXTEND_LO))]
+  "TARGET_64BIT"
+  "daddiu\t%0,%1,%R2"
+  [(set_attr "move_type" "const")
+   (set_attr "mode" "DI")])
 
 (define_insn_and_split "*zero_extendsidi2"
   [(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -3868,7 +3895,10 @@ (define_insn "load_got<mode>"
 		   (match_operand:P 2 "immediate_operand" "")]
 		  UNSPEC_LOAD_GOT))]
   ""
-  "<load>\t%0,%R2(%1)"
+  {if (TARGET_NB32)
+     return "lwu\t%0,%R2(%1)";
+   else
+     return "<load>\t%0,%R2(%1)"; }
   [(set_attr "got" "load")
    (set_attr "mode" "<MODE>")])
 
@@ -5929,7 +5959,10 @@ (define_insn "load_call<mode>"
 		   (match_operand:P 2 "immediate_operand" "")
 		   (reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL))]
   "TARGET_USE_GOT"
-  "<load>\t%0,%R2(%1)"
+  {if (TARGET_NB32)
+     return "lwu\t%0,%R2(%1)";
+   else
+     return "<load>\t%0,%R2(%1)"; }
   [(set_attr "got" "load")
    (set_attr "mode" "<MODE>")])
 
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 170267)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -339,4 +339,6 @@ typedef rtx (*mulsidi3_gen_fn) (rtx, rtx
 extern mulsidi3_gen_fn mips_mulsidi3_gen_fn (enum rtx_code);
 #endif
 
+extern void mips_expand_zero_extend_symbol (rtx, rtx);
+
 #endif /* ! GCC_MIPS_PROTOS_H */
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 170267)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2812,7 +2812,9 @@ mips_split_symbol (rtx temp, rtx addr, e
 		break;
 
 	      default:
-		high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
+		high = gen_rtx_HIGH (ptr_mode, copy_rtx (addr));
+		if (GET_MODE (high) != Pmode)
+		  high = gen_rtx_ZERO_EXTEND (Pmode, high);
 		high = mips_force_temporary (temp, high);
 		*low_out = gen_rtx_LO_SUM (Pmode, high, addr);
 		break;
@@ -4743,6 +4745,7 @@ mips_get_arg_info (struct mips_arg_info 
       break;
 
     case ABI_N32:
+    case ABI_NB32:
     case ABI_64:
       /* Scalar, complex and vector floating-point types are passed in
 	 floating-point registers, as long as this is a named rather
@@ -8175,6 +8178,8 @@ mips_mdebug_abi_name (void)
       return "abiO64";
     case ABI_N32:
       return "abiN32";
+    case ABI_NB32:
+      return "abiNB32";
     case ABI_64:
       return "abi64";
     case ABI_EABI:
@@ -9998,12 +10003,17 @@ mips_emit_loadgp (void)
     case LOADGP_ABSOLUTE:
       if (mips_gnu_local_gp == NULL)
 	{
-	  mips_gnu_local_gp = gen_rtx_SYMBOL_REF (Pmode, "__gnu_local_gp");
+	  mips_gnu_local_gp = gen_rtx_SYMBOL_REF (ptr_mode, "__gnu_local_gp");
 	  SYMBOL_REF_FLAGS (mips_gnu_local_gp) |= SYMBOL_FLAG_LOCAL;
 	}
-      emit_insn (Pmode == SImode
-		 ? gen_loadgp_absolute_si (pic_reg, mips_gnu_local_gp)
-		 : gen_loadgp_absolute_di (pic_reg, mips_gnu_local_gp));
+      if (TARGET_NB32)
+	{
+	  emit_insn (gen_zero_extendsidi2 (pic_reg, mips_gnu_local_gp));
+	}
+      else
+	emit_insn (Pmode == SImode
+		   ? gen_loadgp_absolute_si (pic_reg, mips_gnu_local_gp)
+		   : gen_loadgp_absolute_di (pic_reg, mips_gnu_local_gp));
       break;
 
     case LOADGP_OLDABI:
@@ -11233,6 +11243,11 @@ mips_process_load_label (rtx target)
       mips_multi_add_insn ("addiu\t%@,%@,%%got_ofst(%0)", target, 0);
       break;
 
+    case ABI_NB32:
+      mips_multi_add_insn ("lwu\t%@,%%got_page(%0)(%+)", target, 0);
+      mips_multi_add_insn ("daddiu\t%@,%@,%%got_ofst(%0)", target, 0);
+      break;
+
     case ABI_64:
       mips_multi_add_insn ("ld\t%@,%%got_page(%0)(%+)", target, 0);
       mips_multi_add_insn ("daddiu\t%@,%@,%%got_ofst(%0)", target, 0);
@@ -15468,6 +15483,8 @@ mips_handle_option (size_t code, const c
 	mips_abi = ABI_O64;
       else if (strcmp (arg, "n32") == 0)
 	mips_abi = ABI_N32;
+      else if (strcmp (arg, "nb32") == 0)
+	mips_abi = ABI_NB32;
       else if (strcmp (arg, "64") == 0)
 	mips_abi = ABI_64;
       else if (strcmp (arg, "eabi") == 0)
@@ -15985,7 +16002,7 @@ mips_conditional_register_usage (void)
     }
   /* Odd registers in the range $f21-$f31 (inclusive) are call-clobbered
      for n32.  */
-  if (mips_abi == ABI_N32)
+  if (mips_abi == ABI_N32 || mips_abi == ABI_NB32)
     {
       int regno;
       for (regno = FP_REG_FIRST + 21; regno <= FP_REG_FIRST + 31; regno+=2)
@@ -16400,6 +16417,25 @@ mips_shift_truncation_mask (enum machine
   return GET_MODE_BITSIZE (mode) - 1;
 }
 
+void mips_expand_zero_extend_symbol (rtx dest, rtx sym)
+{
+  rtx t1, t2;
+
+  if (can_create_pseudo_p ())
+    {
+      t1 = gen_reg_rtx (DImode);
+      t2 = gen_reg_rtx (DImode);
+    }
+  else
+    {
+      t1 = dest;
+      t2 = dest;
+    }
+  emit_insn (gen_zero_extendsidi_high_address (t1, sym));
+  mips_emit_binary (ASHIFT, t2, t1, GEN_INT (16));
+  emit_insn (gen_zero_extendsidi_low_address (dest, t2, sym));
+}
+
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	(revision 170267)
+++ gcc/config/mips/mips.h	(working copy)
@@ -43,6 +43,7 @@ extern int target_flags_explicit;
 #define ABI_64  2
 #define ABI_EABI 3
 #define ABI_O64  4
+#define ABI_NB32 5
 
 /* Masks that affect tuning.
 
@@ -303,7 +304,10 @@ enum mips_code_readable_setting {
 				     || TUNE_24K)
 
 #define TARGET_OLDABI		    (mips_abi == ABI_32 || mips_abi == ABI_O64)
-#define TARGET_NEWABI		    (mips_abi == ABI_N32 || mips_abi == ABI_64)
+#define TARGET_NEWABI		    (mips_abi == ABI_N32	\
+				     || mips_abi == ABI_NB32	\
+				     || mips_abi == ABI_64)
+#define TARGET_NB32		    (mips_abi == ABI_NB32)
 
 /* TARGET_HARD_FLOAT and TARGET_SOFT_FLOAT reflect whether the FPU is
    directly accessible, while the command-line options select
@@ -478,6 +482,11 @@ enum mips_code_readable_setting {
 	  builtin_define ("_ABIO64=4");					\
 	  builtin_define ("_MIPS_SIM=_ABIO64");				\
 	  break;							\
+									\
+	case ABI_NB32:							\
+	  builtin_define ("_ABINB32=5");				\
+	  builtin_define ("_MIPS_SIM=_ABINB32");			\
+	  break;							\
 	}								\
 									\
       builtin_define_with_int_value ("_MIPS_SZINT", INT_TYPE_SIZE);	\
@@ -669,6 +678,10 @@ enum mips_code_readable_setting {
 #define MULTILIB_ABI_DEFAULT "mabi=n32"
 #endif
 
+#if MIPS_ABI_DEFAULT == ABI_NB32
+#define MULTILIB_ABI_DEFAULT "mabi=nb32"
+#endif
+
 #if MIPS_ABI_DEFAULT == ABI_64
 #define MULTILIB_ABI_DEFAULT "mabi=64"
 #endif
@@ -742,6 +755,7 @@ enum mips_code_readable_setting {
 
 #if MIPS_ABI_DEFAULT == ABI_O64 \
   || MIPS_ABI_DEFAULT == ABI_N32 \
+  || MIPS_ABI_DEFAULT == ABI_NB32 \
   || MIPS_ABI_DEFAULT == ABI_64
 #define OPT_ARCH64 "mabi=32|mgp32:;"
 #define OPT_ARCH32 "mabi=32|mgp32"
@@ -1475,7 +1489,7 @@ enum mips_code_readable_setting {
 
 /* Pmode is always the same as ptr_mode, but not always the same as word_mode.
    Extensions of pointers to word_mode must be signed.  */
-#define POINTERS_EXTEND_UNSIGNED false
+#define POINTERS_EXTEND_UNSIGNED TARGET_NB32
 
 /* Define if loading short immediate values into registers sign extends.  */
 #define SHORT_IMMEDIATES_SIGN_EXTEND
@@ -2430,7 +2444,8 @@ typedef struct mips_args {
    between pointers and any other objects of this machine mode.  */
 
 #ifndef Pmode
-#define Pmode (TARGET_64BIT && TARGET_LONG64 ? DImode : SImode)
+#define Pmode (TARGET_64BIT && TARGET_LONG64 ? DImode : \
+	       (TARGET_NB32 ? DImode : SImode))
 #endif
 
 /* Give call MEMs SImode since it is the "most permissive" mode
Index: gcc/config/mips/netbsd.h
===================================================================
--- gcc/config/mips/netbsd.h	(revision 170267)
+++ gcc/config/mips/netbsd.h	(working copy)
@@ -44,6 +44,8 @@ along with GCC; see the file COPYING3.  
 	builtin_define ("__mips_eabi");			\
       else if (mips_abi == ABI_N32)			\
 	builtin_define ("__mips_n32");			\
+      else if (mips_abi == ABI_NB32)			\
+	builtin_define ("__mips_nb32");			\
       else if (mips_abi == ABI_64)			\
 	builtin_define ("__mips_n64");			\
       else if (mips_abi == ABI_O64)			\
