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