When GCC is given an ABI parameter with `-mabi=<whatever>` it passes
that argument down to GAS. GAS does not need to know the Morello ABI
that is being used, since all decisions are based on the processor state
(whether +c64 is enabled or not).
GAS doesn't currently accept `purecap` or `hybrid` as arguments to the
`-mabi` option. Even though it does not need this information, I think
it should accept the arguments. This would mean GCC does not need
implement special handling to avoid passing the `-mabi` argument to GAS
only in these specific cases.
gas/ChangeLog:
2021-07-30 Matthew Malcomson <matthew.malcomson(a)arm.com>
* config/tc-aarch64.c (aarch64_abi_type): Introduce PURECAP and
HYBRID enum entries.
(aarch64_abis): Add "purecap" and "hybrid" parameters.
* testsuite/gas/aarch64/morello-abis-ignored.s: New.
* testsuite/gas/aarch64/morello-abis-ignored.d: New.
############### Attachment also inlined for ease of reply ###############
Inline version does not contain generated files
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 3d0436d538c856a418f6949fb47998f69558b6fc..5735d127848bdf22685b436b541424f4af0ae636 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -75,7 +75,9 @@ enum aarch64_abi_type
{
AARCH64_ABI_NONE = 0,
AARCH64_ABI_LP64 = 1,
- AARCH64_ABI_ILP32 = 2
+ AARCH64_ABI_ILP32 = 2,
+ AARCH64_ABI_PURECAP = 3,
+ AARCH64_ABI_HYBRID = 4,
};
#ifndef DEFAULT_ARCH
@@ -10048,6 +10050,10 @@ struct aarch64_option_abi_value_table
static const struct aarch64_option_abi_value_table aarch64_abis[] = {
{"ilp32", AARCH64_ABI_ILP32},
{"lp64", AARCH64_ABI_LP64},
+ /* Note that these values are accepted since they are valid parameters to
+ the -mabi argument for GCC. However we base no decision on them. */
+ {"purecap", AARCH64_ABI_PURECAP},
+ {"hybrid", AARCH64_ABI_HYBRID},
};
static int
diff --git a/gas/testsuite/gas/aarch64/morello-abis-ignored.d b/gas/testsuite/gas/aarch64/morello-abis-ignored.d
new file mode 100644
index 0000000000000000000000000000000000000000..37d7735ac674389be82547c7896d5dd950630bff
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-abis-ignored.d
@@ -0,0 +1,18 @@
+#name: Morello ABI arguments accepted but ignored.
+#as: -mabi=purecap
+#as: -mabi=lp64
+#as: -mabi=hybrid
+#readelf: --syms
+
+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 2
+ 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
+ 4: 0000000000000001 0 FUNC LOCAL DEFAULT 1 foo
+ 5: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 \$c
+ 6: 0000000000000008 0 FUNC LOCAL DEFAULT 1 bar
+ 7: 0000000000000008 0 NOTYPE LOCAL DEFAULT 1 \$x
+ 8: 0000000000000011 0 FUNC LOCAL DEFAULT 1 baz
+ 9: 0000000000000010 0 NOTYPE LOCAL DEFAULT 1 \$c
diff --git a/gas/testsuite/gas/aarch64/morello-abis-ignored.s b/gas/testsuite/gas/aarch64/morello-abis-ignored.s
new file mode 100644
index 0000000000000000000000000000000000000000..39590632b607d3a3f45da39c2d042b1d52ad1cf5
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-abis-ignored.s
@@ -0,0 +1,15 @@
+ .arch morello+c64
+ .type foo, @function
+foo:
+ mov x0, #0
+ ret c30
+ .arch morello
+ .type bar,@function
+bar:
+ mov x0, #0
+ ret c30
+ .arch morello+c64
+ .type baz, @function
+baz:
+ mov x0, #0
+ ret c30
Morello LLVM assumes that these directives should auto-align, it emits
assembly that does not explicitly align these directives.
Fix and testcases added.
############### Attachment also inlined for ease of reply ###############
Inline version does not contain generated files
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 89abdc62e4e97049856d6d22966b90ae147a52bf..3d0436d538c856a418f6949fb47998f69558b6fc 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -2170,6 +2170,9 @@ s_aarch64_capinit (int ignored ATTRIBUTE_UNUSED)
return;
}
+ /* align to 16 bytes. */
+ do_align (4, (char *) NULL, 0, 0);
+
frag_grow (16);
fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 16, &exp, 0,
BFD_RELOC_MORELLO_CAPINIT);
@@ -2193,6 +2196,9 @@ s_aarch64_chericap (int ignored ATTRIBUTE_UNUSED)
md_flush_pending_output ();
#endif
+ /* align to 16 bytes. */
+ do_align (4, (char *) NULL, 0, 0);
+
frag_grow (16);
fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 16, &exp, 0,
BFD_RELOC_MORELLO_CAPINIT);
diff --git a/gas/testsuite/gas/aarch64/morello-capinit-align.d b/gas/testsuite/gas/aarch64/morello-capinit-align.d
new file mode 100644
index 0000000000000000000000000000000000000000..0193bd9071d841e269a5e44168937176d13c61d2
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-capinit-align.d
@@ -0,0 +1,10 @@
+#name: capinit and chericap automatically align
+#as: -march=armv8-a+c64
+#readelf: --relocs
+
+Relocation section '\.rela\.data' at offset 0x138 contains 4 entries:
+ Offset Info Type Sym\. Value Sym\. Name \+ Addend
+000000000010 00040000e800 R_MORELLO_CAPINIT 0000000000000000 f \+ 0
+000000000030 00040000e800 R_MORELLO_CAPINIT 0000000000000000 f \+ 0
+000000000040 00040000e800 R_MORELLO_CAPINIT 0000000000000000 f \+ 0
+000000000050 00040000e800 R_MORELLO_CAPINIT 0000000000000000 f \+ 0
diff --git a/gas/testsuite/gas/aarch64/morello-capinit-align.s b/gas/testsuite/gas/aarch64/morello-capinit-align.s
new file mode 100644
index 0000000000000000000000000000000000000000..fce807b79103c9a2b16a8734a61582eb846b19ec
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-capinit-align.s
@@ -0,0 +1,16 @@
+.data
+f:
+// A few capability initialisation directives with a single byte to show the
+// padding gets introduced when needed.
+.byte 0
+.capinit f
+.xword 0
+.xword 0
+.byte 0
+.chericap f
+// A few directives without any bytes in between to show no extra padding gets
+// added when not needed.
+.chericap f
+.capinit f
+.xword 0
+.xword 0
The `capinit` directive does not allocate space for the relevant
relocation, rather it creates a CAPINIT relocation on the 16 bytes
immediately following it.
Our implementation works by ensuring we can grow the existing `frag` (an
internal structure that describes known contiguous bytes) by 8 bytes
and then recording that we have an 8 byte sized CAPINIT relocation.
It should be 16 bytes, since the relocation is on a 16 byte quantity.
One symptom this problem can cause is where the section that a given
CAPINIT relocation is recorded may not have enough space for the entire
capability the CAPINIT relocation requests.
The testcase we add demonstrated this problem before the current change.
Now it errors out. Unfortunately the error is an internal one with a
error message that references internal data structures, but I believe
that is better than creating a faulty binary without complaint.
############### Attachment also inlined for ease of reply ###############
Inline version does not contain generated files
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 77caba2f13996e541b1e5c216a980aa1b91e038e..89abdc62e4e97049856d6d22966b90ae147a52bf 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -2170,8 +2170,8 @@ s_aarch64_capinit (int ignored ATTRIBUTE_UNUSED)
return;
}
- frag_grow (8);
- fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 8, &exp, 0,
+ frag_grow (16);
+ fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 16, &exp, 0,
BFD_RELOC_MORELLO_CAPINIT);
demand_empty_rest_of_line ();
diff --git a/gas/testsuite/gas/aarch64/morello-capinit-require-size.d b/gas/testsuite/gas/aarch64/morello-capinit-require-size.d
new file mode 100644
index 0000000000000000000000000000000000000000..8a6370eccccc5ffe1300ef025029f8f81cee78cd
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-capinit-require-size.d
@@ -0,0 +1,3 @@
+#name: Capinit Requires 16 bytes
+#as: -march=armv8-a+c64
+#error_output: morello-capinit-require-size.l
diff --git a/gas/testsuite/gas/aarch64/morello-capinit-require-size.l b/gas/testsuite/gas/aarch64/morello-capinit-require-size.l
new file mode 100644
index 0000000000000000000000000000000000000000..614213d95e9fa53a99f0c4591a58e56349e37d04
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-capinit-require-size.l
@@ -0,0 +1,2 @@
+[^:]*: Assembler messages:
+[^:]*:7: Error: internal error: fixup not contained within frag
diff --git a/gas/testsuite/gas/aarch64/morello-capinit-require-size.s b/gas/testsuite/gas/aarch64/morello-capinit-require-size.s
new file mode 100644
index 0000000000000000000000000000000000000000..6931c4997da7d45da034c4ba6fafe5bfb0a6cef3
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-capinit-require-size.s
@@ -0,0 +1,17 @@
+.data
+.align 4
+a:
+ .8byte 0
+
+d:
+ .capinit a
+ .8byte 0
+ .size d, .-d
+
+// Need to switch section so that the capinit relocation does not have enough
+// space in the relevant chunk.
+.section .data.rel.ro
+.align 4
+e:
+ .8byte 0
+ .size e, .-e
Expressions involving function symbols should take into account the fact
that the LSB of C64 functions is set (while the LSB of labels is not
set).
The main motivating example of this is `capinit` expressions of the form
f+((.Ltmp0+1)-f)
where `f` is a function and `.Ltmp0` is a label.
These should result in a CAPINIT relocation of the form
`f + <constant multiple of 4>` since the `+1` on the `.Ltmp0` should
cancel out the LSB that is set on `f`.
This is slightly different to the handling of a set LSB for THUMB
functions, since in THUMB the LSB is not kept when computing relations.
For THUMB expressions using the function are emitted as relocations to
let the linker apply the adjustment.
To implement this, we have two options (we choose the second):
- Handle the LSB in the target hook `md_optimize_expr` (similar to how
the arm backend handles expressions involving THUMB functions).
- Set the LSB on the value assigned to the symbol in `tc_frob_label`.
The approach using the `md_optimize_expr` hook would involve adding one
to the expression that describes an operand, when that operand is a
C64 function symbol with no addend. Then returning `FALSE` from that
hook in order to let the generic code handle the expression from then
on.
We would only want to do this when there is no addend to avoid applying
this adjustment multiple times in an expression (e.g. when a
subexpression reduces to a function symbol plus addend).
This adjustment would also want to avoid doing this to any expression
that would end up as a relocation involving that function symbol, since
then the artificial adjustment would be propagated to the relocation
(resulting in an expression like `f - 63` where the addend has been
adjusted to account for the LSB in `f`, but the linker will account for
the LSB in `f` itself).
Such avoidance is simple enough for expressions like `O_add` since we
can always avoid them, but it is more awkward to tell for `O_subtract`
expressions where some expressions can be reduced to a constant while
others will end up as a relocation.
Another difficulty with this approach is that the value of an expression
can be different depending on the relative location of the `type`
directive to the expression in the assembly source. If the directive is
before an expression then the expression will account for the LSB but if
the directive is after the expression it will not.
While behaviour depending on the location of the `type` directive is a
tricky problem and has problems in the Morello LLVM compiler as well,
these behaviours do not match the behaviour of Morello LLVM.
The second approach is to adjust a symbols value in `tc_frob_label` if
it is a C64 function. This will automatically mean that all symbol
expressions use this LSB correctly.
This approach does still have difficulties with relative locations of
the `type` directive, but here the behaviour matches Morello LLVM. The
important factor in this case is whether the `type` directive is before
or after the function symbols label. If the function label is before
the `type` directive then *all* expressions using the function label
will not account for the LSB, otherwise all expressions will utilise it.
There are two known differences with the Morello LLVM behaviour when
taking this approach.
The first is around calculating an expression of the form `operand - f`.
If `operand` is known, then both GAS and LLVM will account for the LSB
of `f`, but if `operand` is not known at the time this expression is
found then GAS will account for the LSB in the final relocation put into
the binary while Morello LLVM will not. This is a Morello LLVM bug.
The second is that Morello LLVM does not allow expressions of the form
`f > altlabel` while GAS does. In this case we have chosen to account
for the LSB, so that even if `f` and `altlabel` are defined in the same
place, if `f` is a C64 function symbol and `altlabel` is not then `f >
altlabel` will evaluate to true.
############### Attachment also inlined for ease of reply ###############
Inline version does not contain generated files
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 72460349c8d986ba2bfecfb78aec2ca42368cbc5..684058b1da7200de00ecd9ea73653ba59422633d 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -7668,6 +7668,8 @@ aarch64_frob_label (symbolS * sym)
last_label_seen = sym;
AARCH64_SET_C64 (sym, IS_C64);
+ if (AARCH64_IS_C64 (sym) && S_IS_FUNCTION (sym))
+ *symbol_X_add_number (sym) += 1;
dwarf2_emit_label (sym);
}
diff --git a/gas/testsuite/gas/aarch64/morello-function-lsb.d b/gas/testsuite/gas/aarch64/morello-function-lsb.d
new file mode 100644
index 0000000000000000000000000000000000000000..919403b0f076c969ced07a2b1aec551204136485
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-function-lsb.d
@@ -0,0 +1,38 @@
+#as: -march=armv8-a+c64
+#objdump: -srt
+
+.*\.o: file format .*
+
+SYMBOL TABLE:
+0000000000000000 l d \.text 0000000000000000 \.text
+0000000000000000 l d \.data 0000000000000000 \.data
+0000000000000000 l d \.bss 0000000000000000 \.bss
+0000000000000000 l \.text 0000000000000000 altlabel
+0000000000000064 l \*ABS\* 0000000000000000 operand
+0000000000000000 l O \.data 0000000000000010 f\.p
+0000000000000000 g F \.text 0000000000000013 f
+
+
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET TYPE VALUE
+0000000000000014 R_AARCH64_ABS32 f-0x0000000000000064
+0000000000000018 R_AARCH64_PREL32 \*ABS\*\+0x000000000000007b
+
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET TYPE VALUE
+0000000000000000 R_MORELLO_CAPINIT f\+0x000000000000000c
+
+
+Contents of section \.text:
+ 0000 fd7bbf62 fdd3c1c2 01000014 fd7bc122 .*
+ 0010 c053c2c2 00000000 00000000 01000000 .*
+ 0020 ffffffff 00000000 ffffffff 00000000 .*
+ 0030 00000000 ffffffff ffffffff ffffffff .*
+ 0040 00000000 00000000 ffffffff 00000000 .*
+ 0050 00000000 ffffffff ffffffff ffffffff .*
+ 0060 00000000 00000000 00000000 ffffffff .*
+ 0070 ffffffff ffffffff 00000000 00000000 .*
+ 0080 01000000 .*
+Contents of section \.data:
+ 0000 00000000 00000000 00000000 00000000 .*
diff --git a/gas/testsuite/gas/aarch64/morello-function-lsb.s b/gas/testsuite/gas/aarch64/morello-function-lsb.s
new file mode 100644
index 0000000000000000000000000000000000000000..70ca354698b0fdeb1a2408fa7f505e9e0e07adf1
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-function-lsb.s
@@ -0,0 +1,67 @@
+ .text
+ .globl f
+ .p2align 2
+ .type f,@function
+f:
+altlabel: // This label does not have function type, so will not have the LSB set.
+ stp c29, c30, [csp, #-32]!
+ mov c29, csp
+ b .LBB0_1
+.Ltmp0:
+.LBB0_1:
+ ldp c29, c30, [csp], #32
+ ret c30
+.Lfunc_end0:
+ // Check that the LSB is not included in the offset when the symbol `f`
+ // ends up in the relocation. In that case it's the linkers
+ // responsibility to account for the LSB.
+ .word f - operand
+ // Check that if we emit a relocation that does not include the symbol
+ // `f` we account for the LSB.
+ .word operand - f
+ // Use `.word 1` markers so is easier to tell what's going on by a
+ // human.
+ .word 1
+ // Ensure we account for the LSB in other valid expressions.
+ // In the output test we require these to evaluate to true or false,
+ // and for true to be represented as 0xffffffff
+ .word altlabel != f
+ .word altlabel >= f
+ .word altlabel <= f
+ .word altlabel == f
+ .word altlabel > f
+ .word altlabel < f
+ .word f != altlabel
+ .word f >= altlabel
+ .word f <= altlabel
+ .word f == altlabel
+ .word f > altlabel
+ .word f < altlabel
+ .word f != f
+ .word f >= f
+ .word f <= f
+ .word f == f
+ .word f > f
+ .word f < f
+ .word altlabel != altlabel
+ .word altlabel >= altlabel
+ .word altlabel <= altlabel
+ .word altlabel == altlabel
+ .word altlabel > altlabel
+ .word altlabel < altlabel
+ .word 1
+ // Ensure we account for the LSB in the standard .size directive.
+ .size f, .Lfunc_end0-f
+
+ .type f.p,@object
+ .data
+ .p2align 4
+f.p:
+ // This is a standard directive form. We need to ensure accounts for
+ // the LSB in the subexpression ((.Ltmp0+1)-f), since otherwise the
+ // resulting relocation is invalid.
+ .capinit f+((.Ltmp0+1)-f)
+ .xword 0
+ .xword 0
+ .size f.p, 16
+.set operand, 100
This directive is the equivalent of the capinit directive except that it
allocates space as well as creating a CAPINIT relocation.
It is useful to be added to binutils since LLVM intend to transition
away from using capinit to chericap and this helps enable that
transition.
Here we just emit the required number of zeros into the output file with
md_number_to_chars. Since we don't have to worry about endianness for a
big zero this is not complicated.
############### Attachment also inlined for ease of reply ###############
Inline version does not contain generated files
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 684058b1da7200de00ecd9ea73653ba59422633d..77caba2f13996e541b1e5c216a980aa1b91e038e 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -2176,6 +2176,37 @@ s_aarch64_capinit (int ignored ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
+
+static void
+s_aarch64_chericap (int ignored ATTRIBUTE_UNUSED)
+{
+ expressionS exp;
+
+ expression (&exp);
+ if (exp.X_op != O_symbol)
+ {
+ as_bad (_(".chericap expects a target symbol as an argument"));
+ return;
+ }
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ frag_grow (16);
+ fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 16, &exp, 0,
+ BFD_RELOC_MORELLO_CAPINIT);
+
+ mapping_state (MAP_DATA);
+ for (int i = 0; i < 4; i++)
+ {
+ /* The documentation of our md_number_to_chars says the greatest value
+ size it can handle is 4 bytes. */
+ char *p = frag_more (4);
+ md_number_to_chars (p, 0, 4);
+ }
+ demand_empty_rest_of_line ();
+}
#endif /* OBJ_ELF */
static void s_aarch64_arch (int);
@@ -2211,6 +2242,7 @@ const pseudo_typeS md_pseudo_table[] = {
{"dword", s_aarch64_elf_cons, 8},
{"variant_pcs", s_variant_pcs, 0},
{"capinit", s_aarch64_capinit, 0},
+ {"chericap", s_aarch64_chericap, 0},
#endif
{"float16", float_cons, 'h'},
{"bfloat16", float_cons, 'b'},
diff --git a/gas/testsuite/gas/aarch64/morello-chericap.d b/gas/testsuite/gas/aarch64/morello-chericap.d
new file mode 100644
index 0000000000000000000000000000000000000000..2d855f283a37cd507954da6fdb2b6b7b74294a25
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-chericap.d
@@ -0,0 +1,61 @@
+#as: -march=armv8-a+c64
+#objdump: -srt
+
+.*: file format .*
+
+SYMBOL TABLE:
+0000000000000000 l d \.text 0000000000000000 \.text
+0000000000000000 l d \.data 0000000000000000 \.data
+0000000000000000 l d \.bss 0000000000000000 \.bss
+0000000000000000 l O \.data 0000000000000010 bar
+0000000000000010 l O \.data 0000000000000010 f\.p
+0000000000000000 l d \.rodata 0000000000000000 \.rodata
+0000000000000000 l \.rodata 000000000000000c str2
+0000000000000030 l \.data 0000000000000010 a
+0000000000000040 l \.data 0000000000000010 b
+0000000000000050 l \.data 0000000000000010 c
+0000000000000060 l \.data 0000000000000010 d
+0000000000000000 l d \.data\.rel\.ro 0000000000000000 \.data\.rel\.ro
+0000000000000000 l \.data\.rel\.ro 0000000000000010 e
+0000000000000000 g F \.text 0000000000000013 f
+0000000000000020 g \.data 000000000000000c str
+0000000000000000 \*UND\* 0000000000000000 foo
+0000000000000014 g F \.text 0000000000000000 _start
+
+
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET TYPE VALUE
+0000000000000014 R_AARCH64_LDST128_ABS_LO12_NC \.data\+0x0000000000000030
+
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET TYPE VALUE
+0000000000000000 R_MORELLO_CAPINIT f\+0x000000000000000c
+0000000000000010 R_MORELLO_CAPINIT f\+0x000000000000000c
+0000000000000030 R_MORELLO_CAPINIT str
+0000000000000040 R_MORELLO_CAPINIT str\+0x0000000000000008
+0000000000000050 R_MORELLO_CAPINIT foo\+0x0000000000000010
+0000000000000060 R_MORELLO_CAPINIT a
+
+
+RELOCATION RECORDS FOR \[\.data\.rel\.ro\]:
+OFFSET TYPE VALUE
+0000000000000000 R_MORELLO_CAPINIT str2
+
+
+Contents of section \.text:
+ 0000 fd7bbf62 fdd3c1c2 01000014 fd7bc122 .*
+ 0010 c053c2c2 420040c2 c053c2c2 .*
+Contents of section \.data:
+ 0000 00000000 00000000 00000000 00000000 .*
+ 0010 00000000 00000000 00000000 00000000 .*
+ 0020 48656c6c 6f20576f 726c6400 00000000 .*
+ 0030 00000000 00000000 00000000 00000000 .*
+ 0040 00000000 00000000 00000000 00000000 .*
+ 0050 00000000 00000000 00000000 00000000 .*
+ 0060 00000000 00000000 00000000 00000000 .*
+Contents of section \.rodata:
+ 0000 48656c6c 6f20576f 726c6400 .*
+Contents of section \.data\.rel\.ro:
+ 0000 00000000 00000000 00000000 00000000 .*
+
diff --git a/gas/testsuite/gas/aarch64/morello-chericap.s b/gas/testsuite/gas/aarch64/morello-chericap.s
new file mode 100644
index 0000000000000000000000000000000000000000..1d44a4ffbb952f13d9abaf4288278d3d06786083
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-chericap.s
@@ -0,0 +1,79 @@
+// Just using the same testcase as the capinit one, but with capinit switched
+// to chericap. chericap does not allocate space so we remove the data
+// directives.
+//
+// On top of that we add a testcase using a more complicated form that these
+// directives see in the real world. Just to ensure that works too.
+ .text
+ .globl f
+ .p2align 2
+ .type f,@function
+f:
+ stp c29, c30, [csp, #-32]!
+ mov c29, csp
+ b .LBB0_1
+.Ltmp0:
+.LBB0_1:
+ ldp c29, c30, [csp], #32
+ ret c30
+.Lfunc_end0:
+ .size f, .Lfunc_end0-f
+
+ .type bar,@object
+ .data
+ .p2align 4
+bar:
+ .chericap f+((.Ltmp0+1)-f)
+ .size bar, 16
+
+ .type f.p,@object
+ .data
+ .p2align 4
+f.p:
+ .capinit f+((.Ltmp0+1)-f)
+ .xword 0
+ .xword 0
+ .size f.p, 16
+
+
+.section .rodata
+str2:
+ .string "Hello World"
+ .size str2, .-str2
+
+.data
+.globl str
+str:
+ .string "Hello World"
+ .size str, .-str
+
+.align 4
+a:
+ .chericap str
+ .size a, .-a
+
+b:
+ .chericap str+8
+ .size b, .-b
+
+c:
+ .chericap foo+16
+ .size c, .-c
+
+d:
+ .chericap a
+ .size d, .-d
+
+.section .data.rel.ro
+.align 4
+e:
+ .chericap str2
+ .size e, .-e
+
+.align 4
+.text
+.globl _start
+.type _start STT_FUNC
+_start:
+ ldr c2, [c2, :lo12:a]
+ ret
Expressions involving function symbols should take into account the fact
that the LSB of C64 functions is set (while the LSB of labels is not
set).
The main motivating example of this is `capinit` expressions of the form
f+((.Ltmp0+1)-f)
where `f` is a function and `.Ltmp0` is a label.
These should result in a CAPINIT relocation of the form
`f + <constant multiple of 4>` since the `+1` on the `.Ltmp0` should
cancel out the LSB that is set on `f`.
This is slightly different to the handling of a set LSB for THUMB
functions, since in THUMB the LSB is not kept when computing relations.
For THUMB expressions using the function are emitted as relocations to
let the linker apply the adjustment.
To implement this, we have two options (we choose the second):
- Handle the LSB in the target hook `md_optimize_expr` (similar to how
the arm backend handles expressions involving THUMB functions).
- Set the LSB on the value assigned to the symbol in `tc_frob_label`.
The approach using the `md_optimize_expr` hook would involve adding one
to the expression that describes an operand, when that operand is a
C64 function symbol with no addend. Then returning `FALSE` from that
hook in order to let the generic code handle the expression from then
on.
We would only want to do this when there is no addend to avoid applying
this adjustment multiple times in an expression (e.g. when a
subexpression reduces to a function symbol plus addend).
This adjustment would also want to avoid doing this to any expression
that would end up as a relocation involving that function symbol, since
then the artificial adjustment would be propagated to the relocation
(resulting in an expression like `f - 63` where the addend has been
adjusted to account for the LSB in `f`, but the linker will account for
the LSB in `f` itself).
Such avoidance is simple enough for expressions like `O_add` since we
can always avoid them, but it is more awkward to tell for `O_subtract`
expressions where some expressions can be reduced to a constant while
others will end up as a relocation.
Another difficulty with this approach is that the value of an expression
can be different depending on the relative location of the `type`
directive to the expression in the assembly source. If the directive is
before an expression then the expression will account for the LSB but if
the directive is after the expression it will not.
While behaviour depending on the location of the `type` directive is a
tricky problem and has problems in the Morello LLVM compiler as well,
these behaviours do not match the behaviour of Morello LLVM.
The second approach is to adjust a symbols value in `tc_frob_label` if
it is a C64 function. This will automatically mean that all symbol
expressions use this LSB correctly.
This approach does still have difficulties with relative locations of
the `type` directive, but here the behaviour matches Morello LLVM. The
important factor in this case is whether the `type` directive is before
or after the function symbols label. If the function label is before
the `type` directive then *all* expressions using the function label
will not account for the LSB, otherwise all expressions will utilise it.
There are two known differences with the Morello LLVM behaviour when
taking this approach.
The first is around calculating an expression of the form `operand - f`.
If `operand` is known, then both GAS and LLVM will account for the LSB
of `f`, but if `operand` is not known at the time this expression is
found then GAS will account for the LSB in the final relocation put into
the binary while Morello LLVM will not. This is a Morello LLVM bug.
The second is that Morello LLVM does not allow expressions of the form
`f > altlabel` while GAS does. In this case we have chosen to account
for the LSB, so that even if `f` and `altlabel` are defined in the same
place, if `f` is a C64 function symbol and `altlabel` is not then `f >
altlabel` will evaluate to true.
############### Attachment also inlined for ease of reply ###############
Inline version does not contain generated files
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 72460349c8d986ba2bfecfb78aec2ca42368cbc5..684058b1da7200de00ecd9ea73653ba59422633d 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -7668,6 +7668,8 @@ aarch64_frob_label (symbolS * sym)
last_label_seen = sym;
AARCH64_SET_C64 (sym, IS_C64);
+ if (AARCH64_IS_C64 (sym) && S_IS_FUNCTION (sym))
+ *symbol_X_add_number (sym) += 1;
dwarf2_emit_label (sym);
}
diff --git a/gas/testsuite/gas/aarch64/morello-function-lsb.d b/gas/testsuite/gas/aarch64/morello-function-lsb.d
new file mode 100644
index 0000000000000000000000000000000000000000..919403b0f076c969ced07a2b1aec551204136485
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-function-lsb.d
@@ -0,0 +1,38 @@
+#as: -march=armv8-a+c64
+#objdump: -srt
+
+.*\.o: file format .*
+
+SYMBOL TABLE:
+0000000000000000 l d \.text 0000000000000000 \.text
+0000000000000000 l d \.data 0000000000000000 \.data
+0000000000000000 l d \.bss 0000000000000000 \.bss
+0000000000000000 l \.text 0000000000000000 altlabel
+0000000000000064 l \*ABS\* 0000000000000000 operand
+0000000000000000 l O \.data 0000000000000010 f\.p
+0000000000000000 g F \.text 0000000000000013 f
+
+
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET TYPE VALUE
+0000000000000014 R_AARCH64_ABS32 f-0x0000000000000064
+0000000000000018 R_AARCH64_PREL32 \*ABS\*\+0x000000000000007b
+
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET TYPE VALUE
+0000000000000000 R_MORELLO_CAPINIT f\+0x000000000000000c
+
+
+Contents of section \.text:
+ 0000 fd7bbf62 fdd3c1c2 01000014 fd7bc122 .*
+ 0010 c053c2c2 00000000 00000000 01000000 .*
+ 0020 ffffffff 00000000 ffffffff 00000000 .*
+ 0030 00000000 ffffffff ffffffff ffffffff .*
+ 0040 00000000 00000000 ffffffff 00000000 .*
+ 0050 00000000 ffffffff ffffffff ffffffff .*
+ 0060 00000000 00000000 00000000 ffffffff .*
+ 0070 ffffffff ffffffff 00000000 00000000 .*
+ 0080 01000000 .*
+Contents of section \.data:
+ 0000 00000000 00000000 00000000 00000000 .*
diff --git a/gas/testsuite/gas/aarch64/morello-function-lsb.s b/gas/testsuite/gas/aarch64/morello-function-lsb.s
new file mode 100644
index 0000000000000000000000000000000000000000..70ca354698b0fdeb1a2408fa7f505e9e0e07adf1
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/morello-function-lsb.s
@@ -0,0 +1,67 @@
+ .text
+ .globl f
+ .p2align 2
+ .type f,@function
+f:
+altlabel: // This label does not have function type, so will not have the LSB set.
+ stp c29, c30, [csp, #-32]!
+ mov c29, csp
+ b .LBB0_1
+.Ltmp0:
+.LBB0_1:
+ ldp c29, c30, [csp], #32
+ ret c30
+.Lfunc_end0:
+ // Check that the LSB is not included in the offset when the symbol `f`
+ // ends up in the relocation. In that case it's the linkers
+ // responsibility to account for the LSB.
+ .word f - operand
+ // Check that if we emit a relocation that does not include the symbol
+ // `f` we account for the LSB.
+ .word operand - f
+ // Use `.word 1` markers so is easier to tell what's going on by a
+ // human.
+ .word 1
+ // Ensure we account for the LSB in other valid expressions.
+ // In the output test we require these to evaluate to true or false,
+ // and for true to be represented as 0xffffffff
+ .word altlabel != f
+ .word altlabel >= f
+ .word altlabel <= f
+ .word altlabel == f
+ .word altlabel > f
+ .word altlabel < f
+ .word f != altlabel
+ .word f >= altlabel
+ .word f <= altlabel
+ .word f == altlabel
+ .word f > altlabel
+ .word f < altlabel
+ .word f != f
+ .word f >= f
+ .word f <= f
+ .word f == f
+ .word f > f
+ .word f < f
+ .word altlabel != altlabel
+ .word altlabel >= altlabel
+ .word altlabel <= altlabel
+ .word altlabel == altlabel
+ .word altlabel > altlabel
+ .word altlabel < altlabel
+ .word 1
+ // Ensure we account for the LSB in the standard .size directive.
+ .size f, .Lfunc_end0-f
+
+ .type f.p,@object
+ .data
+ .p2align 4
+f.p:
+ // This is a standard directive form. We need to ensure accounts for
+ // the LSB in the subexpression ((.Ltmp0+1)-f), since otherwise the
+ // resulting relocation is invalid.
+ .capinit f+((.Ltmp0+1)-f)
+ .xword 0
+ .xword 0
+ .size f.p, 16
+.set operand, 100
We're choosing the bfd_reloc_code_real_type value to set on
inst.reloc.type. Hence we should use the bfd_reloc_code_real_type type
for our temporaries.
This was not failing since the temporaries could hold the relevant
types, but was causing warnings that broke the build if running with
-Werror. I saw the warning on gcc version 10 and 11, I did not see the
warning on gcc version 7.5.
Testsuite as a cross-build for aarch64-none-elf and aarch64-linux native shows
no change.
OK for users/ARM/morello-binutils-gdb-master?
---
2021-07-20 Matthew Malcomson <matthew.malcomson(a)arm.com>
gas/ChangeLog:
* config/tc-aarch64.h (parse_operands): Use correct enum type for
temporaries.
############### Attachment also inlined for ease of reply ###############
Inline version does not contain generated files
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 648b182666aa558240fa02685247241be3852f23..72460349c8d986ba2bfecfb78aec2ca42368cbc5 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -6638,7 +6638,7 @@ bad_adrdp:
case branch_imm:
/* e.g. B or BL */
{
- enum aarch64_opnd jump, call;
+ bfd_reloc_code_real_type jump, call;
gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL26);
> -----Original Message-----
> From: Matthew Malcomson <Matthew.Malcomson(a)arm.com>
> Sent: 20 July 2021 11:50
> To: gnu-morello(a)op-lists.linaro.org
> Cc: Kyrylo Tkachov <Kyrylo.Tkachov(a)arm.com>
> Subject: gas: Use correct data type in parse_operands
>
> We're choosing the bfd_reloc_code_real_type value to set on
> inst.reloc.type. Hence we should use the bfd_reloc_code_real_type type
> for our temporaries.
>
> This was not failing since the temporaries could hold the relevant
> types, but was causing warnings that broke the build if running with
> -Werror. I saw the warning on gcc version 10 and 11, I did not see the
> warning on gcc version 7.5.
>
> Testsuite as a cross-build for aarch64-none-elf and aarch64-linux native
> shows
> no change.
>
> OK for users/ARM/morello-binutils-gdb-master?
Ok, but isn't this needed in the Binutils master?
Thanks,
Kyrill
>
> ############### Attachment also inlined for ease of reply
> ###############
> Inline version does not contain generated files
>
>
> diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
> index
> 648b182666aa558240fa02685247241be3852f23..72460349c8d986ba2bfecfb
> 78aec2ca42368cbc5 100644
> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -6638,7 +6638,7 @@ bad_adrdp:
> case branch_imm:
> /* e.g. B or BL */
> {
> - enum aarch64_opnd jump, call;
> + bfd_reloc_code_real_type jump, call;
>
> gas_assert (operands[i] ==
> AARCH64_OPND_ADDR_PCREL26);
>
Hi all,
The c64 flag in the aarch64_fix struct was missing an initialization.
This was causing Morello relocations to be spuriously inserted, even
when not targetting C64.
This patch fixes the issue by initializing the flag to false.
Regression tested on aarch64-linux-gnu, no regressions.
OK for users/ARM/morello-binutils-gdb-master?
Thanks,
Alex
---
2021-07-13 Alex Coplan <alex.coplan(a)arm.com>
gas/ChangeLog:
* config/tc-aarch64.h (TC_INIT_FIX_DATA): Initialize c64
member.