diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 77c5866..d4dde83 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -3387,6 +3387,7 @@ resolve_subexp (struct expression **expp, int *pos, int deprocedure_p,
     case OP_LONG:
     case OP_DOUBLE:
     case OP_VAR_VALUE:
+    case OP_VAR_MSYM_VALUE:
       *pos += 4;
       break;
 
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index fae2e2d..70e7980 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -742,6 +742,23 @@ gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax,
       break;
     }
 }
+
+/* Generate code for a minimal symbol variable reference to AX.  The
+   variable is the symbol MINSYM, of OBJFILE.  Set VALUE to describe
+   the result.  */
+
+static void
+gen_msym_var_ref (agent_expr *ax, axs_value *value,
+		  minimal_symbol *msymbol, objfile *objf)
+{
+  CORE_ADDR address;
+  type *t = find_minsym_type_and_address (msymbol, objf, &address);
+  value->type = t;
+  value->optimized_out = false;
+  ax_const_l (ax, address);
+  value->kind = axs_lvalue_memory;
+}
+
 
 
 
@@ -1987,6 +2004,11 @@ gen_expr (struct expression *exp, union exp_element **pc,
       (*pc) += 4;
       break;
 
+    case OP_VAR_MSYM_VALUE:
+      gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
+      (*pc) += 4;
+      break;
+
     case OP_REGISTER:
       {
 	const char *name = &(*pc)[2].string;
diff --git a/gdb/eval.c b/gdb/eval.c
index 1ec6751..457e280 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -676,6 +676,25 @@ make_params (int num_types, struct type **param_types)
   return type;
 }
 
+/* Helper for evaluating an OP_VAR_MSYM_VALUE.  */
+
+static value *
+evaluate_var_msym_value (enum noside noside,
+			 struct objfile *objfile, minimal_symbol *msymbol)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      type *the_type = find_minsym_type_and_address (msymbol, objfile, NULL);
+      return value_zero (the_type, not_lval);
+    }
+  else
+    {
+      CORE_ADDR address;
+      type *the_type = find_minsym_type_and_address (msymbol, objfile, &address);
+      return value_at_lazy (the_type, address);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -766,6 +785,11 @@ evaluate_subexp_standard (struct type *expect_type,
 
 	return ret;
       }
+    case OP_VAR_MSYM_VALUE:
+      (*pos) += 3;
+      return evaluate_var_msym_value (noside,
+				      exp->elts[pc + 1].objfile,
+				      exp->elts[pc + 2].msymbol);
 
     case OP_VAR_ENTRY_VALUE:
       (*pos) += 2;
diff --git a/gdb/expprint.c b/gdb/expprint.c
index 9b8ac4c..4939c01 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -134,6 +134,13 @@ print_subexp_standard (struct expression *exp, int *pos,
       }
       return;
 
+    case OP_VAR_MSYM_VALUE:
+      {
+	(*pos) += 3;
+	fputs_filtered (MSYMBOL_PRINT_NAME (exp->elts[pc + 2].msymbol), stream);
+      }
+      return;
+
     case OP_VAR_ENTRY_VALUE:
       {
 	(*pos) += 2;
@@ -876,6 +883,15 @@ dump_subexp_body_standard (struct expression *exp,
 			SYMBOL_PRINT_NAME (exp->elts[elt + 1].symbol));
       elt += 3;
       break;
+    case OP_VAR_MSYM_VALUE:
+      fprintf_filtered (stream, "Objfile @");
+      gdb_print_host_address (exp->elts[elt].objfile, stream);
+      fprintf_filtered (stream, ", msymbol @");
+      gdb_print_host_address (exp->elts[elt + 1].msymbol, stream);
+      fprintf_filtered (stream, " (%s)",
+			MSYMBOL_PRINT_NAME (exp->elts[elt + 1].msymbol));
+      elt += 3;
+      break;
     case OP_VAR_ENTRY_VALUE:
       fprintf_filtered (stream, "Entry value of symbol @");
       gdb_print_host_address (exp->elts[elt].symbol, stream);
diff --git a/gdb/expression.h b/gdb/expression.h
index 8fe6b07..9e4ddf5 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -64,6 +64,7 @@ union exp_element
   {
     enum exp_opcode opcode;
     struct symbol *symbol;
+    struct minimal_symbol *msymbol;
     LONGEST longconst;
     DOUBLEST doubleconst;
     gdb_byte decfloatconst[16];
diff --git a/gdb/minsyms.h b/gdb/minsyms.h
index e763f62..dc51725 100644
--- a/gdb/minsyms.h
+++ b/gdb/minsyms.h
@@ -20,6 +20,8 @@
 #ifndef MINSYMS_H
 #define MINSYMS_H
 
+struct type;
+
 /* Several lookup functions return both a minimal symbol and the
    objfile in which it is found.  This structure is used in these
    cases.  */
@@ -275,4 +277,11 @@ void iterate_over_minimal_symbols (struct objfile *objf,
 
 CORE_ADDR minimal_symbol_upper_bound (struct bound_minimal_symbol minsym);
 
+/* Return the type of MSYMBOL, a minimal symbol of OBJFILE.  If
+   ADDRESS_P is not NULL, set it to the MSYMBOL's resolved
+   address.  */
+
+type *find_minsym_type_and_address (minimal_symbol *msymbol, objfile *objf,
+				    CORE_ADDR *address_p);
+
 #endif /* MINSYMS_H */
diff --git a/gdb/parse.c b/gdb/parse.c
index 3dd7075..4889c1a 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -255,6 +255,16 @@ write_exp_elt_sym (struct parser_state *ps, struct symbol *expelt)
 }
 
 void
+write_exp_elt_msym (struct parser_state *ps, minimal_symbol *expelt)
+{
+  union exp_element tmp;
+
+  memset (&tmp, 0, sizeof (union exp_element));
+  tmp.msymbol = expelt;
+  write_exp_elt (ps, &tmp);
+}
+
+void
 write_exp_elt_block (struct parser_state *ps, const struct block *b)
 {
   union exp_element tmp;
@@ -469,17 +479,17 @@ write_exp_bitstring (struct parser_state *ps, struct stoken str)
   write_exp_elt_longcst (ps, (LONGEST) bits);
 }
 
-/* Add the appropriate elements for a minimal symbol to the end of
-   the expression.  */
+/* Return the type of MSYMBOL, a minimal symbol of OBJFILE.  If
+   ADDRESS_P is not NULL, set it to the MSYMBOL's resolved
+   address.  */
 
-void
-write_exp_msymbol (struct parser_state *ps,
-		   struct bound_minimal_symbol bound_msym)
+type *
+find_minsym_type_and_address (minimal_symbol *msymbol,
+			      struct objfile *objfile,
+			      CORE_ADDR *address_p)
 {
-  struct minimal_symbol *msymbol = bound_msym.minsym;
-  struct objfile *objfile = bound_msym.objfile;
+  bound_minimal_symbol bound_msym = {msymbol, objfile};
   struct gdbarch *gdbarch = get_objfile_arch (objfile);
-
   CORE_ADDR addr = BMSYMBOL_VALUE_ADDRESS (bound_msym);
   struct obj_section *section = MSYMBOL_OBJ_SECTION (objfile, msymbol);
   enum minimal_symbol_type type = MSYMBOL_TYPE (msymbol);
@@ -514,51 +524,54 @@ write_exp_msymbol (struct parser_state *ps,
   if (overlay_debugging)
     addr = symbol_overlayed_address (addr, section);
 
-  write_exp_elt_opcode (ps, OP_LONG);
-  /* Let's make the type big enough to hold a 64-bit address.  */
-  write_exp_elt_type (ps, objfile_type (objfile)->builtin_core_addr);
-  write_exp_elt_longcst (ps, (LONGEST) addr);
-  write_exp_elt_opcode (ps, OP_LONG);
-
   if (section && section->the_bfd_section->flags & SEC_THREAD_LOCAL)
     {
-      write_exp_elt_opcode (ps, UNOP_MEMVAL_TLS);
-      write_exp_elt_objfile (ps, objfile);
-      write_exp_elt_type (ps, objfile_type (objfile)->nodebug_tls_symbol);
-      write_exp_elt_opcode (ps, UNOP_MEMVAL_TLS);
-      return;
+      /* Skip translation if caller does not need the address.  */
+      if (address_p != NULL)
+	*address_p = target_translate_tls_address (objfile, addr);
+      return objfile_type (objfile)->nodebug_tls_symbol;
     }
 
-  write_exp_elt_opcode (ps, UNOP_MEMVAL);
+  if (address_p != NULL)
+    *address_p = addr;
+
+  struct type *the_type;
+
   switch (type)
     {
     case mst_text:
     case mst_file_text:
     case mst_solib_trampoline:
-      write_exp_elt_type (ps, objfile_type (objfile)->nodebug_text_symbol);
-      break;
+      return objfile_type (objfile)->nodebug_text_symbol;
 
     case mst_text_gnu_ifunc:
-      write_exp_elt_type (ps, objfile_type (objfile)
-			  ->nodebug_text_gnu_ifunc_symbol);
-      break;
+      return objfile_type (objfile)->nodebug_text_gnu_ifunc_symbol;
 
     case mst_data:
     case mst_file_data:
     case mst_bss:
     case mst_file_bss:
-      write_exp_elt_type (ps, objfile_type (objfile)->nodebug_data_symbol);
-      break;
+      return objfile_type (objfile)->nodebug_data_symbol;
 
     case mst_slot_got_plt:
-      write_exp_elt_type (ps, objfile_type (objfile)->nodebug_got_plt_symbol);
-      break;
+      return objfile_type (objfile)->nodebug_got_plt_symbol;
 
     default:
-      write_exp_elt_type (ps, objfile_type (objfile)->nodebug_unknown_symbol);
-      break;
+      return objfile_type (objfile)->nodebug_unknown_symbol;
     }
-  write_exp_elt_opcode (ps, UNOP_MEMVAL);
+}
+
+/* Add the appropriate elements for a minimal symbol to the end of
+   the expression.  */
+
+void
+write_exp_msymbol (struct parser_state *ps,
+		   struct bound_minimal_symbol bound_msym)
+{
+  write_exp_elt_opcode (ps, OP_VAR_MSYM_VALUE);
+  write_exp_elt_objfile (ps, bound_msym.objfile);
+  write_exp_elt_msym (ps, bound_msym.minsym);
+  write_exp_elt_opcode (ps, OP_VAR_MSYM_VALUE);
 }
 
 /* Mark the current index as the starting location of a structure
@@ -883,6 +896,7 @@ operator_length_standard (const struct expression *expr, int endpos,
     case OP_DOUBLE:
     case OP_DECFLOAT:
     case OP_VAR_VALUE:
+    case OP_VAR_MSYM_VALUE:
       oplen = 4;
       break;
 
@@ -1844,6 +1858,9 @@ operator_check_standard (struct expression *exp, int pos,
 	type = SYMBOL_TYPE (symbol);
       }
       break;
+    case OP_VAR_MSYM_VALUE:
+      objfile = elts[pos + 1].objfile;
+      break;
     }
 
   /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL.  */
diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index 4650726..9007dd4 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -132,6 +132,12 @@ OP (OP_VAR_VALUE)
    current function.  Implemented via DW_OP_entry_value.  */
 OP (OP_VAR_ENTRY_VALUE)
 
+/* OP_VAR_MSYM_VALUE takes one struct objfile * in the following
+   element, and one struct minimal_symbol * in the following
+   exp_element, followed by another OP_VAR_MSYM_VALUE, making four
+   exp_elements.  */
+OP (OP_VAR_MSYM_VALUE)
+
 /* OP_LAST is followed by an integer in the next exp_element.
    The integer is zero for the last value printed,
    or it is the absolute number of a history element.
