When compiling with -mlong-calls and -pg, calls to the __gnu_mcount_nc function are not generated as long calls.
This is encountered when building an allyesconfig Linux kernel because the Linux build system generates very large sections by partial linking a large number of object files. This causes link failures, which don't go away with -mlong-calls due to this bug. (However, with this patch linking still fails due to calls in inline asm) For example: extern void g(void); int f() { g(); return 0; } compiles to: push {r4, lr} push {lr} bl __gnu_mcount_nc ;// not a long call ldr r3, .L2 blx r3 ;// a long call to g() mov r0, #0 pop {r4, pc} The call to __gnu_mcount_nc is generated from ARM_FUNCTION_PROFILER in config/arm/bpabi.h. For targets without MOVW/MOVT, the long call sequence requires a load from the literal pool, and it is too late to set up a literal pool entry from within ARM_FUNCTION_PROFILER. My approach to fix this is to modify the prologue generation to load the address of __gnu_mcount_nc into ip, so that it is ready when the call is generated. This patch only implements the fix for ARM and Thumb-2. A similar fix is possible for Thumb-1, but requires more slightly complex changes to the prologue generation to make sure there is a low register available. This feels like a bit of a hack to me, so ideas for a cleaner solution are welcome, if none, is this acceptable for trunk now, or should it wait until GCC 7?
From 34993396a43fcfc263db5b02b2d1837c490f52ad Mon Sep 17 00:00:00 2001 From: Charles Baylis <charles.bay...@linaro.org> Date: Thu, 11 Feb 2016 18:07:00 +0000 Subject: [PATCH] [ARM] PR69770 fix -mlong-calls with -pg gcc/ChangeLog: 2016-02-12 Charles Baylis <charles.bay...@linaro.org> * config/arm/arm.c (arm_expand_prologue): Load address of __gnu_mcount_nc in r12 if profiling and long calls are enabled. * config/arm/bpabi.h (ARM_FUNCTION_PROFILER): Emit long call to __gnu_mcount_nc long calls are enabled. (ARM_FUNCTION_PROFILER_SUPPORTS_LONG_CALLS): New define. gcc/testsuite/ChangeLog: 2016-02-12 Charles Baylis <charles.bay...@linaro.org> * gcc.target/arm/pr69770.c: New test. Change-Id: I4c639a5edf32fa8c67324d37faee1cb4ddd57a5c diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 27aecf7..9ce9a58 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -21739,6 +21739,15 @@ arm_expand_prologue (void) arm_load_pic_register (mask); } + if (crtl->profile && TARGET_LONG_CALLS + && ARM_FUNCTION_PROFILER_SUPPORTS_LONG_CALLS) + { + rtx tmp = gen_rtx_SET (gen_rtx_REG (SImode, IP_REGNUM), + gen_rtx_SYMBOL_REF (Pmode, "__gnu_mcount_nc")); + emit_insn (tmp); + emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, IP_REGNUM))); + } + /* If we are profiling, make sure no instructions are scheduled before the call to mcount. Similarly if the user has requested no scheduling in the prolog. Similarly if we want non-call exceptions diff --git a/gcc/config/arm/bpabi.h b/gcc/config/arm/bpabi.h index 82128ef..b734a24 100644 --- a/gcc/config/arm/bpabi.h +++ b/gcc/config/arm/bpabi.h @@ -173,11 +173,21 @@ #undef NO_PROFILE_COUNTERS #define NO_PROFILE_COUNTERS 1 +#undef ARM_FUNCTION_PROFILER_SUPPORTS_LONG_CALLS +#define ARM_FUNCTION_PROFILER_SUPPORTS_LONG_CALLS 1 #undef ARM_FUNCTION_PROFILER #define ARM_FUNCTION_PROFILER(STREAM, LABELNO) \ { \ - fprintf (STREAM, "\tpush\t{lr}\n"); \ - fprintf (STREAM, "\tbl\t__gnu_mcount_nc\n"); \ + if (TARGET_LONG_CALLS && TARGET_32BIT) \ + { \ + fprintf (STREAM, "\tpush\t{lr}\n"); \ + /* arm_expand_prolog() has already set up ip to contain the */ \ + /* address of __gnu_mcount_nc. */ \ + fprintf (STREAM, "\tblx\tip\n"); \ + } else { \ + fprintf (STREAM, "\tpush\t{lr}\n"); \ + fprintf (STREAM, "\tbl\t__gnu_mcount_nc\n"); \ + } \ } #undef SUBTARGET_FRAME_POINTER_REQUIRED diff --git a/gcc/testsuite/gcc.target/arm/pr69770.c b/gcc/testsuite/gcc.target/arm/pr69770.c new file mode 100644 index 0000000..61e5c6d --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr69770.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-pg -mlong-calls" } */ + +extern void g(void); + +int f() { g(); return 0; } + +/* { dg-final { scan-assembler-not "bl\[ \t\]+__gnu_mcount_nc" } } */ +/* { dg-final { scan-assembler "__gnu_mcount_nc" } } */ -- 1.9.1