dwarf2asm: Fix up -gdwarf-64 for 32-bit targets
authorJakub Jelinek <jakub@redhat.com>
Tue, 26 Jan 2021 08:20:23 +0000 (09:20 +0100)
committerJakub Jelinek <jakub@redhat.com>
Tue, 26 Jan 2021 08:20:23 +0000 (09:20 +0100)
For the 32-bit targets the limitations of the object
file format (e.g. 32-bit ELF) will not allow > 2GiB debug info anyway,
and as I've just tested, e.g. on x86_64 with -m32 -gdwarf64 will not work
even on tiny testcases:
as: pr64716.o: unsupported relocation type: 0x1
pr64716.s: Assembler messages:
pr64716.s:6013: Error: cannot represent relocation type BFD_RELOC_64
as: pr64716.o: unsupported relocation type: 0x1
pr64716.s:6015: Error: cannot represent relocation type BFD_RELOC_64
as: pr64716.o: unsupported relocation type: 0x1
pr64716.s:6017: Error: cannot represent relocation type BFD_RELOC_64
So yes, we can either do a sorry, error, or could just avoid 64-bit
relocations (depending on endianity instead of emitting
.quad expression_that_needs_relocation
emit
.long expression_that_needs_relocation, 0
or
.long 0, expression_that_needs_relocation

This patch implements that last option, dunno if we need also configure tests
for that or not, maybe some 32-bit targets use 64-bit ELF and can handle such
relocations.

> 64bit relocs are not required here?  That is, can one with
> dwarf64 choose 32bit forms for select offsets (like could
> dwz exploit this?)?

I guess it depends on whether for 32-bit target and -gdwarf64, when
calling dw2_assemble_integer with non-CONST_INT argument we only
need positive values or might need negative ones too.
Because positive ones can be easily emulated through that
.long expression, 0
or
.long 0, expression
depending on endianity, but I'm afraid there is no way to emit
0 or -1 depending on the sign of expression, when it needs relocations.
Looking through dw2_asm_output_delta calls, at least the vast majority
of the calls seem to guarantee being positive, not 100% sure about
one case in .debug_line views, but I'd hope it is ok too.
In most cases, the deltas are between two labels where the first one
in the arguments is later in the same section than the other one,
or where the second argument is the start of a section or another section
base.

2021-01-26  Jakub Jelinek  <jakub@redhat.com>

* dwarf2asm.c (dw2_assemble_integer): Handle size twice as large
as DWARF2_ADDR_SIZE if x is not a scalar int by emitting it as
two halves, one with x and the other with const0_rtx, ordered
depending on endianity.

gcc/dwarf2asm.c

index ecc33d957c442d77eaab675726d1b88379f3b5b5..8e08d4d24d80c397b23f8bcf9af4c08aee8f254b 100644 (file)
@@ -46,6 +46,52 @@ along with GCC; see the file COPYING3.  If not see
 void
 dw2_assemble_integer (int size, rtx x)
 {
+  if (size == 2 * DWARF2_ADDR_SIZE && !CONST_SCALAR_INT_P (x))
+    {
+      /* On 32-bit targets with -gdwarf64, DImode values with
+        relocations usually result in assembler errors.  Assume
+        all such values are positive and emit the relocation only
+        in the least significant half.  */
+      const char *op = integer_asm_op (DWARF2_ADDR_SIZE, FALSE);
+      if (BYTES_BIG_ENDIAN)
+       {
+         if (op)
+           {
+             fputs (op, asm_out_file);
+             fprint_whex (asm_out_file, 0);
+             fputs (", ", asm_out_file);
+             output_addr_const (asm_out_file, x);
+           }
+         else
+           {
+             assemble_integer (const0_rtx, DWARF2_ADDR_SIZE,
+                               BITS_PER_UNIT, 1);
+             putc ('\n', asm_out_file);
+             assemble_integer (x, DWARF2_ADDR_SIZE,
+                               BITS_PER_UNIT, 1);
+           }
+       }
+      else
+       {
+         if (op)
+           {
+             fputs (op, asm_out_file);
+             output_addr_const (asm_out_file, x);
+             fputs (", ", asm_out_file);
+             fprint_whex (asm_out_file, 0);
+           }
+         else
+           {
+             assemble_integer (x, DWARF2_ADDR_SIZE,
+                               BITS_PER_UNIT, 1);
+             putc ('\n', asm_out_file);
+             assemble_integer (const0_rtx, DWARF2_ADDR_SIZE,
+                               BITS_PER_UNIT, 1);
+           }
+       }
+      return;
+    }
+
   const char *op = integer_asm_op (size, FALSE);
 
   if (op)