[v2,1/5] gas: deal with the need for relocations from .cfi_{escape,fde_data}

Message ID 88a3782d-0cfd-46eb-8796-5081e70dadce@suse.com
State New
Headers
Series gas: CFI directive and listing adjustments |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed

Commit Message

Jan Beulich March 7, 2025, 2:22 p.m. UTC
  Ignoring return values often isn't a good idea. The Sparc assembler in
particular would report an internal error if an expression with
relocation specifier is used with .cfi_escape, when the same works fine
with .byte. Propagate the relocation indicator up from
do_parse_cons_expression(), and eventually into emit_expr_with_reloc().

dot_cfi_fde_data(), only retaining the expression's X_add_number, would
require further work. Simply report the lack of support there. While
there, also check that what we were dealt is actually a constant.
---
Really value truncation better would also be reported for .cfi_fde_data.
Question is whether dot_cfi_fde_data() wouldn't better share parsing
code with dot_cfi_escape(), for data to then be emitted for both via
emit_expr_with_reloc(). Problem is I know nothing about EH_COMPACT_*,
and hence I'd be at risk of breaking stuff if I blindly did such a
conversion.
---
v2: Re-base.
  

Patch

--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -947,7 +947,7 @@  dot_cfi_escape (int ignored ATTRIBUTE_UN
   do
     {
       e = notes_alloc (sizeof (*e));
-      do_parse_cons_expression (&e->exp, 1);
+      e->reloc = do_parse_cons_expression (&e->exp, 1);
       *tail = e;
       tail = &e->next;
     }
@@ -1419,7 +1419,10 @@  dot_cfi_fde_data (int ignored ATTRIBUTE_
 	  do
 	    {
 	      e = XNEW (struct cfi_escape_data);
-	      do_parse_cons_expression (&e->exp, 1);
+	      e->reloc = do_parse_cons_expression (&e->exp, 1);
+	      if (e->reloc != TC_PARSE_CONS_RETURN_NONE
+		  || e->exp.X_op != O_constant)
+		as_bad (_("only constants may be used with .cfi_fde_data"));
 	      *tail = e;
 	      tail = &e->next;
 	      num_ops++;
@@ -1761,7 +1764,7 @@  output_cfi_insn (struct cfi_insn_data *i
       {
 	struct cfi_escape_data *e;
 	for (e = insn->u.esc; e ; e = e->next)
-	  emit_expr (&e->exp, 1);
+	  emit_expr_with_reloc (&e->exp, 1, e->reloc);
 	break;
       }
 
--- a/gas/dw2gencfi.h
+++ b/gas/dw2gencfi.h
@@ -97,6 +97,7 @@  struct cfi_escape_data
 {
   struct cfi_escape_data *next;
   expressionS exp;
+  TC_PARSE_CONS_RETURN_TYPE reloc;
 };
 
 struct cfi_insn_data
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -1345,7 +1345,10 @@  sframe_xlate_do_escape_expr (const struc
       if ((i == 2 && (items[1] != 2)) /* Expected len of 2 in DWARF expr.  */
 	  /* We do not care for the exact values of items[2] and items[3],
 	     so an explicit check for O_constant isnt necessary either.  */
-	  || i >= CFI_ESC_NUM_EXP || (i < 2 && e->exp.X_op != O_constant))
+	  || i >= CFI_ESC_NUM_EXP
+	  || (i < 2
+	      && (e->exp.X_op != O_constant
+		  || e->reloc != TC_PARSE_CONS_RETURN_NONE)))
 	goto warn_and_exit;
       items[i] = e->exp.X_add_number;
       i++;
@@ -1408,7 +1411,8 @@  sframe_xlate_do_escape_val_offset (const
   while (e->next)
     {
       e = e->next;
-      if (i >= CFI_ESC_NUM_EXP || e->exp.X_op != O_constant)
+      if (i >= CFI_ESC_NUM_EXP || e->exp.X_op != O_constant
+	  || e->reloc != TC_PARSE_CONS_RETURN_NONE)
 	goto warn_and_exit;
       items[i] = e->exp.X_add_number;
       i++;
@@ -1482,7 +1486,7 @@  sframe_xlate_do_cfi_escape (const struct
   if (!e)
     return SFRAME_XLATE_ERR_INVAL;
 
-  if (e->exp.X_op != O_constant)
+  if (e->exp.X_op != O_constant || e->reloc != TC_PARSE_CONS_RETURN_NONE)
     return SFRAME_XLATE_ERR_NOTREPRESENTED;
 
   firstop = e->exp.X_add_number;
@@ -1493,7 +1497,8 @@  sframe_xlate_do_cfi_escape (const struct
       while (e->next)
 	{
 	  e = e->next;
-	  if (e->exp.X_op != O_constant || e->exp.X_add_number != DW_CFA_nop)
+	  if (e->exp.X_op != O_constant || e->exp.X_add_number != DW_CFA_nop
+	      || e->reloc != TC_PARSE_CONS_RETURN_NONE)
 	    {
 	      warn_p = true;
 	      break;
--- a/gas/read.c
+++ b/gas/read.c
@@ -4186,14 +4186,15 @@  parse_mri_cons (expressionS *exp, unsign
 /* This function is used by .cfi_* directive handling, and hence must not
    invoke parse_repeat_cons().  */
 
-void
+TC_PARSE_CONS_RETURN_TYPE
 do_parse_cons_expression (expressionS *exp,
 			  int nbytes ATTRIBUTE_UNUSED)
 {
 #ifdef TC_PARSE_CONS_EXPRESSION
-  (void) TC_PARSE_CONS_EXPRESSION (exp, nbytes);
+  return TC_PARSE_CONS_EXPRESSION (exp, nbytes);
 #else
   expression (exp);
+  return TC_PARSE_CONS_RETURN_NONE;
 #endif
 }
 
--- a/gas/read.h
+++ b/gas/read.h
@@ -159,7 +159,7 @@  extern void stabs_begin (void);
 extern void stabs_end (void);
 extern void do_repeat (size_t, const char *, const char *, const char *);
 extern void end_repeat (int);
-extern void do_parse_cons_expression (expressionS *, int);
+extern TC_PARSE_CONS_RETURN_TYPE do_parse_cons_expression (expressionS *, int);
 extern void generate_lineno_debug (void);
 extern void do_align (unsigned int align, char *fill, unsigned int length,
 		      unsigned int max);
--- a/gas/testsuite/gas/cfi/cfi.exp
+++ b/gas/testsuite/gas/cfi/cfi.exp
@@ -105,6 +105,7 @@  if  { [istarget "i*86-*-*"] || [istarget
 
     set nm_status [gas_host_run "$NM $NMFLAGS --help" ""]
     run_dump_test "cfi-sparc-1"
+    run_dump_test "cfi-sparc-2"
     if { [regexp "elf64\[_-\]sparc" [lindex $nm_status 1]] } then {
 	run_dump_test "cfi-sparc64-1"
     }
--- /dev/null
+++ b/gas/testsuite/gas/cfi/cfi-sparc-2.d
@@ -0,0 +1,12 @@ 
+#readelf: -r
+#name: .cfi_escape on SPARC w/ reloc specifier
+#as: -32
+
+Relocation section '.rela.data' at offset 0x[0-9a-f]+ contains 1 entry:
+ Offset     Info    Type            Sym\.Value  Sym\. Name \+ Addend
+[0-9a-f]+ +[0-9a-f]+ R_SPARC_DISP8 +[0-9a-f]+ +\.data \+ 1
+
+Relocation section '.rela.eh_frame' at offset 0x[0-9a-f]+ contains 2 entries:
+ Offset     Info    Type            Sym\.Value  Sym\. Name \+ Addend
+[0-9a-f]+ +[0-9a-f]+ R_SPARC_DISP32 +[0-9a-f]+ +\.text \+ 0
+[0-9a-f]+ +[0-9a-f]+ R_SPARC_DISP8 +[0-9a-f]+ +\.eh_frame \+ [0-9a-f]+
--- /dev/null
+++ b/gas/testsuite/gas/cfi/cfi-sparc-2.s
@@ -0,0 +1,16 @@ 
+	.data
+	.byte %r_disp8(1f-1)
+	.byte 0x50
+1:
+
+	.text
+func:
+	.cfi_startproc
+	nop
+	.cfi_escape 0x10	! DW_CFA_expression
+	.cfi_escape 0		! reg0
+	.cfi_escape %r_disp8(.Lend-1)
+	.cfi_escape 0x50	! DW_OP_reg0
+	.cfi_label .Lend
+	ret
+	.cfi_endproc