Wilco Dijkstra writes:
> In aarch64_classify_symbol symbols are allowed large offsets on relocations.
> This means the offset can use all of the +/-4GB offset, leaving no offset
> available for the symbol itself. This results in relocation overflow and
> link-time errors for simple expressions like &global_array + 0xff00.
>
> To avoid this, unless the offset_within_block_p is true, limit the offset
> to +/-1MB so that the symbol needs to be within a 3.9GB offset from its
> references. For the tiny code model use a 64KB offset, allowing most of
> the 1MB range for code/data between the symbol and its references.
>
> gcc/
> PR target/98618
> * config/aarch64/aarch64.c (aarch64_classify_symbol):
> Apply reasonable limit to symbol offsets.
>
> gcc/testsuite/
> PR target/98618
> * gcc.target/aarch64/symbol-range.c: Improve testcase.
> * gcc.target/aarch64/symbol-range-tiny.c: Likewise.
>
> (cherry picked from commit 7d3b27ff12610fde9d6c4b56abc70c6ee9b6b3db)
OK on the same basis as GCC9.
Thanks,
Richard
>
> ---
> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> index
> e8e73b8ea92b0dd3b9de661652c30c26c07bec86..7c4cf75b5a5e2394dc0b3f69b68d93df8f88111f
> 100644
> --- a/gcc/config/aarch64/aarch64.c
> +++ b/gcc/config/aarch64/aarch64.c
> @@ -12011,26 +12011,31 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT
> offset)
> the offset does not cause overflow of the final address. But
> we have no way of knowing the address of symbol at compile time
> so we can't accurately say if the distance between the PC and
> - symbol + offset is outside the addressible range of +/-1M in the
> - TINY code model. So we rely on images not being greater than
> - 1M and cap the offset at 1M and anything beyond 1M will have to
> - be loaded using an alternative mechanism. Furthermore if the
> - symbol is a weak reference to something that isn't known to
> - resolve to a symbol in this module, then force to memory. */
> - if ((SYMBOL_REF_WEAK (x)
> - && !aarch64_symbol_binds_local_p (x))
> - || !IN_RANGE (offset, -1048575, 1048575))
> + symbol + offset is outside the addressible range of +/-1MB in the
> + TINY code model. So we limit the maximum offset to +/-64KB and
> + assume the offset to the symbol is not larger than +/-(1MB - 64KB).
> + If offset_within_block_p is true we allow larger offsets.
> + Furthermore force to memory if the symbol is a weak reference to
> + something that doesn't resolve to a symbol in this module. */
> +
> + if (SYMBOL_REF_WEAK (x) && !aarch64_symbol_binds_local_p (x))
> return SYMBOL_FORCE_TO_MEM;
> + if (!(IN_RANGE (offset, -0x1, 0x1)
> +|| offset_within_block_p (x, offset)))
> +return SYMBOL_FORCE_TO_MEM;
> +
>return SYMBOL_TINY_ABSOLUTE;
>
> case AARCH64_CMODEL_SMALL:
>/* Same reasoning as the tiny code model, but the offset cap here is
> - 4G. */
> - if ((SYMBOL_REF_WEAK (x)
> - && !aarch64_symbol_binds_local_p (x))
> - || !IN_RANGE (offset, HOST_WIDE_INT_C (-4294967263),
> -HOST_WIDE_INT_C (4294967264)))
> + 1MB, allowing +/-3.9GB for the offset to the symbol. */
> +
> + if (SYMBOL_REF_WEAK (x) && !aarch64_symbol_binds_local_p (x))
> return SYMBOL_FORCE_TO_MEM;
> + if (!(IN_RANGE (offset, -0x10, 0x10)
> +|| offset_within_block_p (x, offset)))
> +return SYMBOL_FORCE_TO_MEM;
> +
>return SYMBOL_SMALL_ABSOLUTE;
>
> case AARCH64_CMODEL_TINY_PIC:
> diff --git a/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c
> b/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c
> index
> d7e46b059e41f2672b3a1da5506fa8944e752e01..fc6a4f3ec780d9fa86de1c8e1a42a55992ee8b2d
> 100644
> --- a/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c
> +++ b/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c
> @@ -1,12 +1,12 @@
> -/* { dg-do compile } */
> +/* { dg-do link } */
> /* { dg-options "-O3 -save-temps -mcmodel=tiny" } */
>
> -int fixed_regs[0x0020];
> +char fixed_regs[0x0008];
>
> int
> -foo()
> +main ()
> {
> - return fixed_regs[0x0008];
> + return fixed_regs[0x000ff000];
> }
>
> /* { dg-final { scan-assembler-not "adr\tx\[0-9\]+, fixed_regs\\\+" } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/symbol-range.c
> b/gcc/testsuite/gcc.target/aarch64/symbol-range.c
> index
> 6574cf4310430b847e77ea56bf8f20ef312d53e4..d8e82fa1b2829fd300b6ccf7f80241e5573e7e17
> 100644
> --- a/gcc/testsuite/gcc.target/aarch64/symbol-range.c
> +++ b/gcc/testsuite/gcc.target/aarch64/symbol-range.c
> @@ -1,12 +1,12 @@
> -/* { dg-do compile } */
> +/* { dg-do link } */
> /* { dg-options "-O3 -save-temps -mcmodel=small" } */
>
> -int fixed_regs[0x2ULL];
> +char fixed_regs[0x8000];
>
> int
> -foo()
> +main ()
> {
> - return fixed_regs[0x1ULL];
> + return fixed_regs[0xf000];
> }
>
> /* { dg-final { scan-assembler-not "adrp\tx\[0-9\]+, fixed_regs\\\+" } } */