diff --git a/gcc/config/vax/constraints.md b/gcc/config/vax/constraints.md
index b8262b6da6f..d4eddb82a66 100644
--- a/gcc/config/vax/constraints.md
+++ b/gcc/config/vax/constraints.md
@@ -112,6 +112,10 @@ (define_memory_constraint "R"
     (and (match_operand:DI 0 "memory_operand")
 	 (not (match_operand:DI 0 "illegal_addsub_di_memory_operand" ""))))
 
+(define_constraint "A"
+    "@internal An integer constant suitable for address load operations."
+  (match_test ("CONSTANT_P (op) && pic_symbolic_operand (op, mode)")))
+
 (define_constraint "T"
     "@internal satisfies CONSTANT_P and, if pic is enabled, is not a SYMBOL_REF, LABEL_REF, or CONST."
   (and (match_test ("CONSTANT_P (op)"))
diff --git a/gcc/config/vax/predicates.md b/gcc/config/vax/predicates.md
index 7eefc605e98..93e91e499a6 100644
--- a/gcc/config/vax/predicates.md
+++ b/gcc/config/vax/predicates.md
@@ -23,33 +23,17 @@
 (define_predicate "symbolic_operand"
   (match_code "const,symbol_ref,label_ref"))
 
-(define_predicate "local_symbolic_operand"
-  (match_code "const,symbol_ref,label_ref")
-{
-  if (GET_CODE (op) == LABEL_REF)
-    return 1;
-  if (GET_CODE (op) == SYMBOL_REF)
-    return !flag_pic || SYMBOL_REF_LOCAL_P (op);
-  if (GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF)
-    return 1;
-  return !flag_pic || SYMBOL_REF_LOCAL_P (XEXP (XEXP (op, 0), 0));
-})
-
-(define_predicate "external_symbolic_operand"
-  (and (match_code "symbol_ref")
-       (not (match_operand 0 "local_symbolic_operand" ""))))
-
-(define_predicate "external_const_operand"
-  (and (match_code "const")
-       (match_test "GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
-		    && !SYMBOL_REF_LOCAL_P (XEXP (XEXP (op, 0), 0))")))
+(define_predicate "pic_symbolic_operand"
+  (and (match_code "const,symbol_ref,label_ref")
+       (match_test "!flag_pic
+		    || vax_acceptable_pic_operand_p (op, false, true)")))
 
 (define_predicate "nonsymbolic_operand"
   (and (ior (match_test "!flag_pic")
 	    (not (match_operand 0 "symbolic_operand")))
        (match_operand 0 "general_operand" "")))
 
-(define_predicate "external_memory_operand"
+(define_predicate "non_pic_external_memory_operand"
    (match_code "mem")
 {
   rtx addr = XEXP (op, 0);
@@ -61,8 +45,8 @@ (define_predicate "external_memory_operand"
     addr = XEXP (addr, 0);
   if (GET_CODE (addr) == PLUS)
     addr = XEXP (addr, 1);
-  return external_symbolic_operand (addr, SImode)
-	 || external_const_operand (addr, SImode);
+  return (symbolic_operand (addr, SImode)
+	  && !vax_acceptable_pic_operand_p (addr, true, true));
 })
 
 (define_predicate "indirect_memory_operand"
@@ -87,7 +71,7 @@ (define_predicate "indexed_memory_operand"
 (define_predicate "illegal_blk_memory_operand"
    (and (match_code "mem")
 	(ior (and (match_test "flag_pic")
-		  (match_operand 0 "external_memory_operand" ""))
+		  (match_operand 0 "non_pic_external_memory_operand" ""))
 	     (ior (match_operand 0 "indexed_memory_operand" "")
 		  (ior (match_operand 0 "indirect_memory_operand" "")
 		       (match_test "GET_CODE (XEXP (op, 0)) == PRE_DEC"))))))
@@ -95,7 +79,7 @@ (define_predicate "illegal_blk_memory_operand"
 (define_predicate "illegal_addsub_di_memory_operand"
    (and (match_code "mem")
 	(ior (and (match_test "flag_pic")
-		  (match_operand 0 "external_memory_operand" ""))
+		  (match_operand 0 "non_pic_external_memory_operand" ""))
 	     (ior (match_operand 0 "indexed_memory_operand" "")
 		  (ior (match_operand 0 "indirect_memory_operand" "")
 		       (match_test "GET_CODE (XEXP (op, 0)) == PRE_DEC"))))))
diff --git a/gcc/config/vax/vax-protos.h b/gcc/config/vax/vax-protos.h
index cda2544f7d5..454d35e3383 100644
--- a/gcc/config/vax/vax-protos.h
+++ b/gcc/config/vax/vax-protos.h
@@ -21,6 +21,7 @@ extern bool legitimate_constant_address_p (rtx);
 extern void vax_expand_prologue (void);
 
 #ifdef RTX_CODE
+extern bool vax_acceptable_pic_operand_p (rtx, bool, bool);
 extern const char *cond_name (rtx);
 extern bool adjacent_operands_p (rtx, rtx, machine_mode);
 extern const char *rev_cond_name (rtx);
diff --git a/gcc/config/vax/vax.c b/gcc/config/vax/vax.c
index 0b3b76ed6da..37f5dadc74c 100644
--- a/gcc/config/vax/vax.c
+++ b/gcc/config/vax/vax.c
@@ -1033,6 +1033,39 @@ vax_rtx_costs (rtx x, machine_mode mode, int outer_code,
   return true;
 }
 
+/* With ELF we do not support GOT entries for external `symbol+offset'
+   references, so do not accept external symbol references if an offset
+   is to be added.  Do not accept external symbol references at all if
+   LOCAL_P is set.  This is for cases where making a reference indirect
+   would make it invalid.  Do not accept any kind of symbols if SYMBOL_P
+   is clear.  This is for situations where the a reference is used as an
+   immediate value for operations other than address loads (MOVA/PUSHA),
+   as those operations do not support PC-relative immediates.  */
+
+bool
+vax_acceptable_pic_operand_p (rtx x ATTRIBUTE_UNUSED,
+			      bool local_p ATTRIBUTE_UNUSED,
+			      bool symbol_p ATTRIBUTE_UNUSED)
+{
+#ifdef NO_EXTERNAL_INDIRECT_ADDRESS
+  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
+    {
+      x = XEXP (XEXP (x, 0), 0);
+      local_p = true;
+    }
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+      return symbol_p && !(local_p && !SYMBOL_REF_LOCAL_P (x));
+    case LABEL_REF:
+      return symbol_p && !(local_p && LABEL_REF_NONLOCAL_P (x));
+    default:
+      break;
+    }
+#endif
+  return true;
+}
+
 /* Output code to add DELTA to the first argument, and then jump to FUNCTION.
    Used for C++ multiple inheritance.
 	.mask	^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>  #conservative entry mask
@@ -1370,8 +1403,10 @@ vax_output_int_add (rtx_insn *insn, rtx *operands, machine_mode mode)
 	  {
 	    gcc_assert (rtx_equal_p (operands[0], operands[1]));
 #ifdef NO_EXTERNAL_INDIRECT_ADDRESS
-	    gcc_assert (!flag_pic || !external_memory_operand (low[2], SImode));
-	    gcc_assert (!flag_pic || !external_memory_operand (low[0], SImode));
+	    gcc_assert (!flag_pic
+			|| !non_pic_external_memory_operand (low[2], SImode));
+	    gcc_assert (!flag_pic
+			|| !non_pic_external_memory_operand (low[0], SImode));
 #endif
 
 	    /* No reason to add a 0 to the low part and thus no carry, so just
diff --git a/gcc/config/vax/vax.h b/gcc/config/vax/vax.h
index c1d0171d94d..146b0a6e2b2 100644
--- a/gcc/config/vax/vax.h
+++ b/gcc/config/vax/vax.h
@@ -442,6 +442,11 @@ enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES };
    of a shift count.  */
 /* #define SHIFT_COUNT_TRUNCATED */
 
+/* We need to reject symbol references in PIC code except for address
+   loads, handled elsewhere.  */
+#define LEGITIMATE_PIC_OPERAND_P(x)	\
+  vax_acceptable_pic_operand_p ((x), false, false)
+
 /* Specify the machine mode that pointers have.
    After generation of rtl, the compiler makes no further distinction
    between pointers and any other objects of this machine mode.  */
diff --git a/gcc/config/vax/vax.md b/gcc/config/vax/vax.md
index e3018a0ee06..e6b217fd0d7 100644
--- a/gcc/config/vax/vax.md
+++ b/gcc/config/vax/vax.md
@@ -338,34 +338,6 @@ (define_insn "add<mode>3"
    add<VAXfp:fsfx>2 %1,%0
    add<VAXfp:fsfx>3 %1,%2,%0")
 
-(define_insn "pushlclsymreg"
-  [(set (match_operand:SI 0 "push_operand" "=g")
-	(plus:SI (match_operand:SI 1 "register_operand" "%r")
-		 (match_operand:SI 2 "local_symbolic_operand" "i")))]
-  "flag_pic"
-  "pushab %a2[%1]")
-
-(define_insn "pushextsymreg"
-  [(set (match_operand:SI 0 "push_operand" "=g")
-	(plus:SI (match_operand:SI 1 "register_operand" "%r")
-		 (match_operand:SI 2 "external_symbolic_operand" "i")))]
-  "flag_pic"
-  "pushab %a2[%1]")
-
-(define_insn "movlclsymreg"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(plus:SI (match_operand:SI 1 "register_operand" "%r")
-		 (match_operand:SI 2 "local_symbolic_operand" "i")))]
-  "flag_pic"
-  "movab %a2[%1],%0")
-
-(define_insn "movextsymreg"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(plus:SI (match_operand:SI 1 "register_operand" "%r")
-		 (match_operand:SI 2 "external_symbolic_operand" "i")))]
-  "flag_pic"
-  "movab %a2[%1],%0")
-
 (define_insn "add<mode>3"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
 	(plus:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")
@@ -1525,29 +1497,31 @@ (define_insn "casesi1"
   ""
   "casel %0,$0,%1")
 
-(define_insn "pushextsym"
+(define_insn "*pushsym"
   [(set (match_operand:SI 0 "push_operand" "=g")
-	(match_operand:SI 1 "external_symbolic_operand" "i"))]
+	(match_operand:SI 1 "pic_symbolic_operand" "A"))]
   ""
   "pushab %a1")
 
-(define_insn "movextsym"
+(define_insn "*movsym"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:SI 1 "external_symbolic_operand" "i"))]
+	(match_operand:SI 1 "pic_symbolic_operand" "A"))]
   ""
   "movab %a1,%0")
 
-(define_insn "pushlclsym"
+(define_insn "*pushsymreg"
   [(set (match_operand:SI 0 "push_operand" "=g")
-	(match_operand:SI 1 "local_symbolic_operand" "i"))]
-  ""
-  "pushab %a1")
+	(plus:SI (match_operand:SI 1 "register_operand" "%r")
+		 (match_operand:SI 2 "pic_symbolic_operand" "A")))]
+  "flag_pic"
+  "pushab %a2[%1]")
 
-(define_insn "movlclsym"
+(define_insn "*movsymreg"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:SI 1 "local_symbolic_operand" "i"))]
-  ""
-  "movab %a1,%0")
+	(plus:SI (match_operand:SI 1 "register_operand" "%r")
+		 (match_operand:SI 2 "pic_symbolic_operand" "A")))]
+  "flag_pic"
+  "movab %a2[%1],%0")
 
 ;;- load or push effective address
 ;; These come after the move and add/sub patterns
