On 23/08/16 15:10, Wilco Dijkstra wrote: > In aarch64_classify_symbol symbols are allowed full-range 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_char + 0xffffff00. > To avoid this, limit the offset to +/-1GB so that the symbol needs to be > within a > 3GB 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. > > Bootstrap OK, updated tests now pass rather than failing with symbol out of > range.
So isn't the real bug that we've permitted the user to create an object that is too large for the data model? Consider, for example: char fixed_regs[0x200000000ULL]; char fixed_regs2[100]; int main() { return fixed_regs[0] + fixed_regs2[0]; } $ gcc -o test -mcmodel=small test2.c /tmp/ccadJpSk.o: In function `main': test2.c:(.text+0x10): relocation truncated to fit: R_AARCH64_ADR_PREL_PG_HI21 against symbol `fixed_regs2' defined in COMMON section in /tmp/ccadJpSk.o collect2: error: ld returned 1 exit status Neither offset is too large, but we still generate relocation errors when trying to reference fixed_regs2. R. > > OK for commit? As this is a latent bug, OK to backport to GCC6.x? Not yet. And any back-port would need a PR first. > > ChangeLog: > 2016-08-23 Wilco Dijkstra <wdijk...@arm.com> > > gcc/ > * config/aarch64/aarch64.c (aarch64_classify_symbol): > Apply reasonable limit to symbol offsets. > > testsuite/ > * gcc.target/aarch64/symbol-range.c (foo): Set new limit. > * gcc.target/aarch64/symbol-range-tiny.c (foo): Likewise. > > -- > diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c > index > ab609223db7c54f467183db39c4f1ae8b789bfb5..60cc61a095bc144d602597a35b51b9a426c76c69 > 100644 > --- a/gcc/config/aarch64/aarch64.c > +++ b/gcc/config/aarch64/aarch64.c > @@ -9367,24 +9367,22 @@ aarch64_classify_symbol (rtx x, rtx offset) > 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. */ > + TINY code model. So we limit the maximum offset to +/-64KB and > + assume the offset to the symbol is not larger than +/-(1M - 64KB). > + 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)) > - || INTVAL (offset) < -1048575 || INTVAL (offset) > 1048575) > + || !IN_RANGE (INTVAL (offset), -0x10000, 0x10000)) > 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. */ > + 1G, allowing +/-3G for the offset to the symbol. */ > if ((SYMBOL_REF_WEAK (x) > && !aarch64_symbol_binds_local_p (x)) > - || !IN_RANGE (INTVAL (offset), HOST_WIDE_INT_C (-4294967263), > - HOST_WIDE_INT_C (4294967264))) > + || !IN_RANGE (INTVAL (offset), -0x40000000, 0x40000000)) > return SYMBOL_FORCE_TO_MEM; > return SYMBOL_SMALL_ABSOLUTE; > > diff --git a/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c > b/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c > index > d7e46b059e41f2672b3a1da5506fa8944e752e01..d399a3637ed834ddc4bb429594c4ec229b5c2ea8 > 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[0x00200000]; > +char fixed_regs[0x00200000]; > > int > -foo() > +main() > { > - return fixed_regs[0x00080000]; > + 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..4b4ec8dab9321026d1fae96d336565a7883c8203 > 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[0x200000000ULL]; > +char fixed_regs[0x200000000ULL]; > > int > -foo() > +main() > { > - return fixed_regs[0x100000000ULL]; > + return fixed_regs[0xfffff000ULL]; > } > > /* { dg-final { scan-assembler-not "adrp\tx\[0-9\]+, fixed_regs\\\+" } } */ >