I've observed strange behaviour of the link-time optimization on GCC 7.2.1, exact version: gcc version 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204] (GNU Tools for Arm Embedded Processors 7-2017-q4-major) I have project that is compiled for the microcontroller. In startup file, that is written in assembler, there are weak definitions of the interrupt handlers. Some of those weak functions are defined in the project C files. Strange behaviour occurs when I set -flto flag on GCC 7.2.1: during optimization, the defined in C files interrupt functions are perceived as unused and removed(replaced by its weak definitions) - I've checked that in the .map file. This issue does not occur when startup file is first on the source files list, which is given as an argument to the linker. If I change order of source files, all interrupt handlers from C files, that are placed on the source files list before startup are removed and replaced by weak definitions from startup. For me it seems that linker is removing interrupt handler functions before noticing its usage in startup file. Or maybe weak function definitions from startup override definitions from C files. I've checked if this issue happens on the GCC 4.9.3 - it worked fine, so this is rather new behaviour. I've also confirmed this bug with other developer from Germany: https://www.mikrocontroller.net/topic/443262 Take a look at the latest posts, which are written in English. Is this a bug or should I place some extra pragmas/attributes to extort proper linker behaviour? Please let me know if you want me to prepare some basic examples of this issue.
If you have two weak definitions it is undefined which one takes precedence. If the C project variant (that gets removed?) is not weak the linker should have made it used. But this is only going to work if you build with a linker plugin - so can you double check that (for example pass -fuse-linker-plugin to the link step?). In any case we'd need something like a testcase to confirm/investigate. Please also specify the linker you are using. I assume you are cross compiling from x86_64-linux?
Also I was going to say the c function maybe should be marked as used as lto likes to remove unused functions in general.
On January 22, 2018 4:36:00 PM GMT+01:00, "pinskia at gcc dot gnu.org" <gcc-bugzilla@gcc.gnu.org> wrote: >https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83967 > >--- Comment #2 from Andrew Pinski <pinskia at gcc dot gnu.org> --- >Also I was going to say the c function maybe should be marked as used >as lto >likes to remove unused functions in general. If you don't use the linker plugin this is indeed required. But with the linker plugin it shouldn't.
Created attachment 43210 [details] Basic example of main funtion with LTO failure. This is simple example of observed LTO issue. RTC1_IRQHandler is removed despite it is used to change volatile variable. RTC1_IRQHandler is defined weak in the assembler startup file.
Created attachment 43211 [details] Makefile that causes failure.
Created attachment 43212 [details] Startup file for the nRF52 microcontroller. This is typical startup for nRF5x microcontrollers. The main thing that is important is the interrupts vector table. All interrupts used in table are declared as weak at the end of file.
Thanks for response. I've send some basic example of the failure. However, it needs some others file to compile and link, like linker, SystemInit function decalration and so on. I've just send you most important files, now I am working on removing sources that are not important, but this will take me a while, since i need to remove lot of dependencies between those files, makefile and linker. I've checked 'used' attribute, it doesn't solve the problem. Same with the suggested '-fuse-linker-plugin' flag.
(In reply to Rafał Mszal from comment #4) > Created attachment 43210 [details] > Basic example of main funtion with LTO failure. > > This is simple example of observed LTO issue. RTC1_IRQHandler is removed > despite it is used to change volatile variable. RTC1_IRQHandler is defined > weak in the assembler startup file. I don't see it being defined in the startup file. But I take it should be similar to .weak NMI_Handler .type NMI_Handler, %function NMI_Handler: b . .size NMI_Handler, . - NMI_Handler and the only use is in the startup file as well: .section .isr_vector .align 2 .globl __isr_vector __isr_vector: .long __StackTop /* Top of Stack */ .long Reset_Handler .long NMI_Handler and you'd define it in a C file as non-weak (what it does doesn't matter) void RTC1_IRQHandler(void) { } So a testcase is: t1.c: ----- int i; void Handler() { i = 1; } void *Dispatch; int main(){ ((void (*)(void))Dispatch)(); return i;} t2.s: ----- .file "t2.s" .text .weak Handler .type Handler, @function Handler: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size Handler, .-Handler .globl Dispatch .data .align 8 .type Dispatch, @object .size Dispatch, 8 Dispatch: .quad Handler .ident "GCC: (SUSE Linux) 7.2.1 20171020 [gcc-7-branch revision 253932]" .section .note.GNU-stack,"",@progbits and then I get > gcc-7 t2.s t1.c -flto /tmp/ccGhH7Cp.o:(.data+0x0): undefined reference to `Handler' collect2: error: ld returned 1 exit status > gcc-7 t1.c t2.s -flto in the working case: 1 t1.o 4 190 16b2980a71930688 PREEMPTED_REG Handler 198 16b2980a71930688 PREVAILING_DEF_IRONLY i 194 16b2980a71930688 PREVAILING_DEF main 202 16b2980a71930688 RESOLVED_EXEC Dispatch in the failing case (GNU ld): 1 t1.o 4 190 801577c96f9ccef3 PREVAILING_DEF_IRONLY Handler 198 801577c96f9ccef3 PREVAILING_DEF_IRONLY i 194 801577c96f9ccef3 PREVAILING_DEF main 202 801577c96f9ccef3 RESOLVED_EXEC Dispatch which works with gold: 1 t1.o 4 190 680bbd652c7cfe04 PREVAILING_DEF Handler 198 680bbd652c7cfe04 PREVAILING_DEF_IRONLY i 194 680bbd652c7cfe04 PREVAILING_DEF main 202 680bbd652c7cfe04 RESOLVED_EXEC Dispatch HJ? This is with binutils 2.29.1, thus confirmed but as a GNU ld issue.
Still not 100% sure which Handler should prevail in resolving the symbol for Dispatch. Currently it seems the non-weak one prevails which looks correct. I think in both cases the resolution from GNU ld is bogus. Take the working one: 190 16b2980a71930688 PREEMPTED_REG Handler that's clearly wrong -- Handler prevails! 190 801577c96f9ccef3 PREVAILING_DEF_IRONLY Handler that's wrong because in the assembler file Handler is used to resolve the symbol at Dispatch. gold seems to get it correct as PREVAILING_DEF (but not _IRONLY).
On Tue, 23 Jan 2018, hurwic8 at gmail dot com wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83967 > > --- Comment #7 from Rafał Mszal <hurwic8 at gmail dot com> --- > Thanks for response. > > I've send some basic example of the failure. However, it needs some others file > to compile and link, like linker, SystemInit function decalration and so on. > > I've just send you most important files, now I am working on removing sources > that are not important, but this will take me a while, since i need to remove > lot of dependencies between those files, makefile and linker. > > I've checked 'used' attribute, it doesn't solve the problem. Same with the > suggested '-fuse-linker-plugin' flag. From my analysis the issue is with GNU ld and you could avoid hitting it by using gold (you can say -fuse-ld=gold to GCC if you have gold installed)
Created attachment 43221 [details] self contained demo I have made a minimal self contained project that demonstrates the bug with arm-none-eabi-gcc compiling for a Cortex M0+ target (Kinetis MKL05), it is self contained and does not require anything but the installed toolchain itself. Extract the attached archive KL05_demo_gcc_weak_strong_bug.tar.gz. You will find a minimal makefile project, versioned in a git repository with only two commits on two branches, one shows the bug and the other doesn't. $ git checkout bad $ make clean $ make all look at the generated .lst file in the build folder and note that the Systick handler looks like this, it is the weak default implementation from the startup assembly: 000004f4 <SysTick_Handler>: 4f4: e7fe b.n 4f4 <SysTick_Handler> now checkout the good version $ git checkout good $ make clean $ make all The systick handler will look like this which is the strong C implementation: 0000044c <SysTick_Handler>: 44c: 4a02 ldr r2, [pc, #8] ; (458 <SysTick_Handler+0xc>) 44e: 6813 ldr r3, [r2, #0] 450: 3301 adds r3, #1 452: 6013 str r3, [r2, #0] 454: 4770 bx lr 456: 46c0 nop ; (mov r8, r8) 458: 1ffffc00 .word 0x1ffffc00 and the only difference between these two sources is one line in the makefile moved to a different position: $ git diff bad good diff --git a/Makefile b/Makefile index 35ff9c6..82e6d47 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,9 @@ NAME = example -SRCS += $(wildcard *.c) SRCS += $(wildcard cmsis/MKL05Z4/*.s) SRCS += $(wildcard cmsis/MKL05Z4/*.c) +SRCS += $(wildcard *.c) INCDIRS = cmsis/ INCDIRS += cmsis/MKL05Z4/
(In reply to Richard Biener from comment #8) > and then I get > > > gcc-7 t2.s t1.c -flto > /tmp/ccGhH7Cp.o:(.data+0x0): undefined reference to `Handler' > collect2: error: ld returned 1 exit status > > gcc-7 t1.c t2.s -flto > > in the working case: > > 1 > t1.o 4 > 190 16b2980a71930688 PREEMPTED_REG Handler > 198 16b2980a71930688 PREVAILING_DEF_IRONLY i > 194 16b2980a71930688 PREVAILING_DEF main > 202 16b2980a71930688 RESOLVED_EXEC Dispatch > > in the failing case (GNU ld): > > 1 > t1.o 4 > 190 801577c96f9ccef3 PREVAILING_DEF_IRONLY Handler > 198 801577c96f9ccef3 PREVAILING_DEF_IRONLY i > 194 801577c96f9ccef3 PREVAILING_DEF main > 202 801577c96f9ccef3 RESOLVED_EXEC Dispatch > > which works with gold: > > 1 > t1.o 4 > 190 680bbd652c7cfe04 PREVAILING_DEF Handler > 198 680bbd652c7cfe04 PREVAILING_DEF_IRONLY i > 194 680bbd652c7cfe04 PREVAILING_DEF main > 202 680bbd652c7cfe04 RESOLVED_EXEC Dispatch > > HJ? This is with binutils 2.29.1, thus confirmed but as a GNU ld issue. Yes, I can reproduce it with binutils 2.29.1. But it was fixed in 2.30.
(In reply to H.J. Lu from comment #12) > > Yes, I can reproduce it with binutils 2.29.1. But it was fixed in > 2.30. This is: https://sourceware.org/bugzilla/show_bug.cgi?id=22502
I actually think this is a different problem from the fixed https://sourceware.org/bugzilla/show_bug.cgi?id=22502. Using gcc 8.2.1 and binutils 2.31.51.20181213 from the STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32), I can still reproduce this problem using the example from comment 11 (and also in an actual implementation using stm32duino). I also tested the example from the linked bug, which *is* indeed fixed, leading me to believe this is a different problem (or the fix is not complete yet). The example from this bug is a lot bigger than the one from 22502, so there is probably something in here that triggers this. Maybe that the weak implementation is defined in assembly rather than C?
(In reply to Matthijs Kooijman from comment #14) > I actually think this is a different problem from the fixed > https://sourceware.org/bugzilla/show_bug.cgi?id=22502. Using gcc 8.2.1 and > binutils 2.31.51.20181213 from the STM32 Arduino core > (https://github.com/stm32duino/Arduino_Core_STM32), I can still reproduce > this problem using the example from comment 11 (and also in an actual > implementation using stm32duino). I also tested the example from the linked > bug, which *is* indeed fixed, leading me to believe this is a different > problem (or the fix is not complete yet). > > The example from this bug is a lot bigger than the one from 22502, so there > is probably something in here that triggers this. Maybe that the weak > implementation is defined in assembly rather than C? I am also still able to reproduce the problem in production code (http://github.com/solokeys/solo) using GNU ld (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 2.33.1.20191025.
Issue is not resolved, and the proposed "moved" fixed issue is a different issue. Accidentally reproduced in a project (demo files untested) with GCC 10.1.1 on Windows (Arm Embedded Toolchain 10 2020-q2-preview). Changing C and asm compile order works but is not a proper solution
Any chance you can try with a toolchain using binutils-2.35? As I indicated in https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 there's a related bug fix in binutils-2.35, but Arm's 2020-q2 toolchain still uses 2.34.50.20200226.
(In reply to Christophe Lyon from comment #17) > Any chance you can try with a toolchain using binutils-2.35? > > As I indicated in https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 > there's a related bug fix in binutils-2.35, but Arm's 2020-q2 toolchain > still uses 2.34.50.20200226. Issue in my project is not present anymore with 2020 Q4 release, which packs GNU ld (GNU Arm Embedded Toolchain 10-2020-q4-major) 2.35.1.20201028. Will test example from Comment #11. My apologies for not reading threads more carefully
(In reply to Emil Jiří Tywoniak from comment #18) > (In reply to Christophe Lyon from comment #17) > > Any chance you can try with a toolchain using binutils-2.35? > > > > As I indicated in https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 > > there's a related bug fix in binutils-2.35, but Arm's 2020-q2 toolchain > > still uses 2.34.50.20200226. > > Issue in my project is not present anymore with 2020 Q4 release, which packs > GNU ld (GNU Arm Embedded Toolchain 10-2020-q4-major) 2.35.1.20201028. Will > test example from Comment #11. My apologies for not reading threads more > carefully I have now tested the bad branch from Comment #11 and did not replicate the bug with the Q4 toolchain (specifically, the Systick handler in .lst is exactly the same as in the good branch excerpt in Comment #11)