]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gas: Allow MORELLO branch relocations to addresses with LSB set
authorMatthew Malcomson <matthew.malcomson@arm.com>
Tue, 10 Aug 2021 11:05:42 +0000 (12:05 +0100)
committerMatthew Malcomson <matthew.malcomson@arm.com>
Tue, 10 Aug 2021 11:05:42 +0000 (12:05 +0100)
Now that we internally handle a set LSB as part of a C64 STT_FUNC value
throughout the assembler rather than as something that is just
introduced by the linker, relocations to code labels now may or may not
include that LSB.

GAS checks that the target of an AARCH64 BRANCH19, TSTBR14, CALL26, or
JUMP26 relocation is aligned, since all uses should point to an
instruction and all instructions should be aligned.
Now that we are including the LSB in the value of STT_FUNC C64 symbols,
the relevant MORELLO_* relocations do not also satisfy this alignment
behaviour.  When these relocations target a location generated from an
STT_FUNC C64 symbol, their value includes that LSB.

This behaviour is not relevant to the user since these relocations lose
the bottom 2 bits of the value they target.  It does however match the
specification of the relocations in the ABI document, which includes the
`C` bit.
This fix avoids requiring that this LSB is unset when in `md_apply_fix`.
For extra robustness we also assert that when setting this LSB on the
symbol in the first place it was not set to begin with.

A downside is that if the LSB is set on non-function symbols the user
will not be warned about that.  Any method to handle that would always
need to determine which expressions should include this LSB and which
shouldn't, which would be difficult to make perfect.  On top of that,
the relevant code would either have to duplicate the code in
`fixup_segment` that resolves an expression into a single value, or
record another bit in the `TC_FIX_TYPE` structure just for this warning.

This seems like more complexity than the extra warning is worth.

We add two tests since `objdump` shows the resulting disassembly but
`readelf` shows the LSB getting set on the relevant functions.

gas/config/tc-aarch64.c
gas/testsuite/gas/aarch64/morello-lsb-relocs.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/morello-lsb-relocs.s [new file with mode: 0644]
gas/testsuite/gas/aarch64/morello-lsb-relocs2.d [new file with mode: 0644]

index 4b66d542191263fbef4ff6f82957848c3fe2708f..765996c624f9b646317f33c7cc07d51ab359e6b4 100644 (file)
@@ -7710,7 +7710,10 @@ aarch64_frob_label (symbolS * sym)
 
   AARCH64_SET_C64 (sym, IS_C64);
   if (AARCH64_IS_C64 (sym) && S_IS_FUNCTION (sym))
-    *symbol_X_add_number (sym) += 1;
+    {
+      gas_assert ((*symbol_X_add_number (sym) & 1) == 0);
+      *symbol_X_add_number (sym) += 1;
+    }
 
   dwarf2_emit_label (sym);
 }
@@ -8500,6 +8503,15 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   int scale;
   unsigned flags = fixP->fx_addnumber;
+  /* We check alignment for relocations of this kind.  These relocations could
+     be applied on a C64 STT_FUNC symbol and hence may have the LSB set on
+     `*valP`, their AARCH64 counterparts can not be applied on such symbols and
+     hence should never have the LSB set on their value.  */
+  valueT alignment_mask = (fixP->fx_r_type == BFD_RELOC_MORELLO_BRANCH19
+                          || fixP->fx_r_type == BFD_RELOC_MORELLO_TSTBR14
+                          || fixP->fx_r_type == BFD_RELOC_MORELLO_CALL26
+                          || fixP->fx_r_type == BFD_RELOC_MORELLO_JUMP26)
+    ? 2 : 3;
 
   DEBUG_TRACE ("\n\n");
   DEBUG_TRACE ("~~~~~~~~~~~~~~~~~~~~~~~~~");
@@ -8609,7 +8621,7 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_MORELLO_BRANCH19:
       if (fixP->fx_done || !seg->use_rela_p)
        {
-         if (value & 3)
+         if (value & alignment_mask)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("conditional branch target not word aligned"));
          if (signed_overflow (value, 21))
@@ -8625,7 +8637,7 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_AARCH64_TSTBR14:
       if (fixP->fx_done || !seg->use_rela_p)
        {
-         if (value & 3)
+         if (value & alignment_mask)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("conditional branch target not word aligned"));
          if (signed_overflow (value, 16))
@@ -8643,7 +8655,7 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_AARCH64_JUMP26:
       if (fixP->fx_done || !seg->use_rela_p)
        {
-         if (value & 3)
+         if (value & alignment_mask)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("branch target not word aligned"));
          if (signed_overflow (value, 28))
diff --git a/gas/testsuite/gas/aarch64/morello-lsb-relocs.d b/gas/testsuite/gas/aarch64/morello-lsb-relocs.d
new file mode 100644 (file)
index 0000000..226801b
--- /dev/null
@@ -0,0 +1,46 @@
+#as: -march=armv8-a+c64
+#objdump: -drt
+
+.*\.o:     file format .*
+
+SYMBOL TABLE:
+0000000000000000 l    d  \.text        0000000000000000 \.text
+0000000000000000 l    d  \.data        0000000000000000 \.data
+0000000000000000 l    d  \.bss 0000000000000000 \.bss
+000000000000000c l     F \.text        0000000000000000 a
+000000000000000c l       \.text        0000000000000000 altlabel
+000000000000000c g     F \.text        0000000000000000 f
+0000000000000000         \*UND\*       0000000000000000 x
+
+
+
+Disassembly of section \.text:
+
+0000000000000000 <f-0xc>:
+       \.\.\.
+
+000000000000000c <f>:
+   c:  14000000        b       0 <x>
+                       c: R_MORELLO_JUMP26     x
+  10:  14000000        b       c <f>
+                       10: R_MORELLO_JUMP26    f
+  14:  17fffffe        b       c <f>
+  18:  17fffffd        b       c <f>
+  1c:  5400000d        b\.le   0 <x>
+                       1c: R_MORELLO_CONDBR19  x
+  20:  5400000d        b\.le   c <f>
+                       20: R_MORELLO_CONDBR19  f
+  24:  54ffff4d        b\.le   c <f>
+  28:  54ffff2d        b\.le   c <f>
+  2c:  36080001        tbz     w1, #1, 0 <x>
+                       2c: R_MORELLO_TSTBR14   x
+  30:  36080001        tbz     w1, #1, c <f>
+                       30: R_MORELLO_TSTBR14   f
+  34:  360ffec1        tbz     w1, #1, c <f>
+  38:  360ffea1        tbz     w1, #1, c <f>
+  3c:  94000000        bl      0 <x>
+                       3c: R_MORELLO_CALL26    x
+  40:  94000000        bl      c <f>
+                       40: R_MORELLO_CALL26    f
+  44:  97fffff2        bl      c <f>
+  48:  97fffff1        bl      c <f>
diff --git a/gas/testsuite/gas/aarch64/morello-lsb-relocs.s b/gas/testsuite/gas/aarch64/morello-lsb-relocs.s
new file mode 100644 (file)
index 0000000..227b023
--- /dev/null
@@ -0,0 +1,32 @@
+        .text
+       // Just to make it a bit clearer to humans reading the tests that we
+       // use the address of `f` and `altlabel` in some places.  Otherwise
+       // when reading the disassembly you just see `0` and it's not 100%
+       // clear that we're using the address vs using a dummy value for later.
+       .zero 12
+        .p2align        2
+        .globl  f
+        .type   f,@function
+        .type   a,@function
+f:             // This function is global, so relocations will remain in the
+               // object file.
+a:             // This function is local, so the relocation on the ADR
+               // instruction will be relaxed to a value.
+altlabel:      // This label does not have function type, so will not have the
+               // LSB set.
+       b       x
+       b       f
+       b       a
+       b       altlabel
+       b.le    x
+       b.le    f
+       b.le    a
+       b.le    altlabel
+       tbz     x1, 1, x
+       tbz     x1, 1, f
+       tbz     x1, 1, a
+       tbz     x1, 1, altlabel
+       bl      x
+       bl      f
+       bl      a
+       bl      altlabel
diff --git a/gas/testsuite/gas/aarch64/morello-lsb-relocs2.d b/gas/testsuite/gas/aarch64/morello-lsb-relocs2.d
new file mode 100644 (file)
index 0000000..aa99c58
--- /dev/null
@@ -0,0 +1,28 @@
+#as: -march=morello+c64
+#readelf: --relocs --syms
+#source: morello-lsb-relocs.s
+
+
+Relocation section '\.rela\.text' at offset 0x198 contains 8 entries:
+  Offset          Info           Type           Sym\. Value    Sym\. Name \+ Addend
+00000000000c  00090000e002 R_MORELLO_JUMP26  0000000000000000 x \+ 0
+000000000010  00080000e002 R_MORELLO_JUMP26  000000000000000d f \+ 0
+00000000001c  00090000e001 R_MORELLO_CONDBR1 0000000000000000 x \+ 0
+000000000020  00080000e001 R_MORELLO_CONDBR1 000000000000000d f \+ 0
+00000000002c  00090000e000 R_MORELLO_TSTBR14 0000000000000000 x \+ 0
+000000000030  00080000e000 R_MORELLO_TSTBR14 000000000000000d f \+ 0
+00000000003c  00090000e003 R_MORELLO_CALL26  0000000000000000 x \+ 0
+000000000040  00080000e003 R_MORELLO_CALL26  000000000000000d f \+ 0
+
+Symbol table '\.symtab' contains 10 entries:
+   Num:    Value          Size Type    Bind   Vis      Ndx Name
+     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
+     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
+     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
+     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
+     4: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    1 \$d
+     5: 000000000000000c     0 NOTYPE  LOCAL  DEFAULT    1 \$c
+     6: 000000000000000d     0 FUNC    LOCAL  DEFAULT    1 a
+     7: 000000000000000c     0 NOTYPE  LOCAL  DEFAULT    1 altlabel
+     8: 000000000000000d     0 FUNC    GLOBAL DEFAULT    1 f
+     9: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND x