]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gas: deal with the need for relocations from .cfi_{escape,fde_data}
authorJan Beulich <jbeulich@suse.com>
Fri, 14 Mar 2025 09:29:33 +0000 (10:29 +0100)
committerJan Beulich <jbeulich@suse.com>
Fri, 14 Mar 2025 09:29:33 +0000 (10:29 +0100)
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.

gas/dw2gencfi.c
gas/dw2gencfi.h
gas/gen-sframe.c
gas/read.c
gas/read.h
gas/testsuite/gas/cfi/cfi-sparc-2.d [new file with mode: 0644]
gas/testsuite/gas/cfi/cfi-sparc-2.s [new file with mode: 0644]
gas/testsuite/gas/cfi/cfi.exp

index 41e15cd1463b65ef5a3f40cb77821cf05a1c2475..4f5622d6d8756718ee19eba207f2dda84f81823e 100644 (file)
@@ -947,7 +947,7 @@ dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
   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_UNUSED)
          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 *insn)
       {
        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;
       }
 
index 9b0e5979c0d452a85a064f49b13277fbea625cf2..a9bd7b8f289315368c91f3c8e8297962322a1629 100644 (file)
@@ -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
index dd5fb25e367ff93779a01a804d9b5ca59b31bfc3..15133cb698e57026e360236f33cba470bc0e5359 100644 (file)
@@ -1342,7 +1342,10 @@ sframe_xlate_do_escape_expr (const struct sframe_xlate_ctx *xlate_ctx,
       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++;
@@ -1405,7 +1408,8 @@ sframe_xlate_do_escape_val_offset (const struct sframe_xlate_ctx *xlate_ctx,
   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++;
@@ -1479,7 +1483,7 @@ sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
   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;
@@ -1490,7 +1494,8 @@ sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
       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;
index 12b6d3029a6a33c5612f190be64d335d3c6af239..31b89b7cbc8b92f8e06818154b870eb9a2f4cdf0 100644 (file)
@@ -4182,14 +4182,15 @@ parse_mri_cons (expressionS *exp, unsigned int nbytes);
 /* 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
 }
 
index f6d016707d830d5d77f40c4df4f0d1dfb107a8cf..b723f4a7c5fb5425c886494ffcc51e7e6bb34a3f 100644 (file)
@@ -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);
diff --git a/gas/testsuite/gas/cfi/cfi-sparc-2.d b/gas/testsuite/gas/cfi/cfi-sparc-2.d
new file mode 100644 (file)
index 0000000..3a425d7
--- /dev/null
@@ -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]+
diff --git a/gas/testsuite/gas/cfi/cfi-sparc-2.s b/gas/testsuite/gas/cfi/cfi-sparc-2.s
new file mode 100644 (file)
index 0000000..9df6da2
--- /dev/null
@@ -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
index 8d730a2cc24bb1984a51ee4948240bcb77112790..d8bbf0df6e80beeb218c3319f2213e359b455ad1 100644 (file)
@@ -105,6 +105,7 @@ if  { [istarget "i*86-*-*"] || [istarget "x86_64-*-*"] } then {
 
     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"
     }