mikrocontroller.net

Forum: Compiler & IDEs arm gcc 7.2.1 -flto broken?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
$ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 
7-2017-q4-major) 7.2.1 20170904 (release) [ARM/embedded-7-branch 
revision 255204]
Copyright (C) 2017 Free Software Foundation, Inc.


Ich hab in meinem Linkerscript sowas stehen:
SECTIONS
{
    .isr_vector :
    {
        __vector_table = .;
        KEEP(*(.vector_table))
        *(.text.Reset_Handler)
        *(.text.Default_Handler)
        *(.text.System_Init)
        *(.text.SystemCoreClockUpdate)
        . = ALIGN(4);
    } > VECTORS

    .flash_protect :
    {
        KEEP(*(.kinetis_flash_config_field))
        . = ALIGN(4);
    } > FLASH_PROTECTION

    .text :
    {
        *(.text*)

        und so weiter


Insbesondere gehts mir hier um .vector_table und 
.kinetis_flash_config_field

Seit Jahren funktioniert das problemlos mit -Os und -flto. Heute hab ich 
mal einen neuen Rechner aufgesetzt und den aktuellen arm gcc aus dem 
offiziellen repository installiert (siehe oben) und plötzlich schmeißt 
mir der Linker alle KEEP() Sections ersatzlos raus.

Gibts irgend nen Trick wie ich um dieses überraschende neue Verhalten 
(Bug?) herum arbeiten könnte um die betroffenen sektionen zu behalten 
ohne auf LTO verzichten zu müssen?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist es denn wirklich der Linker der die raussschmeisst?

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Hab den Fehler gefunden.

Der Name der Konstante die bei mir rausoptimiert wurde entsprach 
zufällig genau dem Namen eines Symbols das im Linkerscript definiert 
war.

Konkret hieß das const struct für meine Tabelle in meinem Quelltext 
zufällig __vector_table und wie es der Zufall will definiert mein oben 
gepostetes Linkerscript ebenfalls ein (vollkommen unnötiges) Symbol des 
selben Namens. Dieses Relikt habe ich nun aus meinem Linkerscript 
entfernt und jetzt verhält sich wieder alles wie es soll.

Mal wieder typischer Fall von selbst in den eigenen Fuß geschossen (die 
Kugel war über 1 Jahr lang unterwegs) und nach erfolgtem Treffer 
reflexartig die Toolchain beschuldigt.

: Bearbeitet durch User
Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Der Name der Konstante die bei mir rausoptimiert wurde entsprach
> zufällig genau dem Namen eines Symbols das im Linkerscript definiert
> war.
>
> Konkret hieß das const struct für meine Tabelle in meinem Quelltext
> zufällig __vector_table

"Zufällig" sollte man niemals reservierte Namen verwenden, also bei 
allem, das mit "__" oder mit "_<Großbuchstabe>" beginnt genau wissen was 
man tut.

Oft scheit ja die naming convention zu sein:

_xxx // irgendwas systemnahes

__xxx // irgendwas noch viiiiel systemnäheres oder etwas, wo man sich 
unsicher ist

___xxx // etwas, das super-duper systemnah ist oder etwas das man nicht 
wirklich blickt

...

Im speziellen Fall sollte also die Anwendung wohl keinen reservierten 
Identifier verwenden, ansonsten stehst du nächsten monat hier mit "woher 
kommt das "undefined reference to __vector_table" und wo muss ich das 
definieren :-/

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gefahr erkannt, Gefahr gebannt.

Aber jetzt gehts weiter: Eben nen noch älteren Quelltext rausgekramt, 
basierend auf dem Startupcode dieser Sammlung:

https://github.com/0xc0170/kinetis_klxx_gcc/

Insbesondere in meinem Beispiel diesen Startup-Code hier:
https://github.com/0xc0170/kinetis_klxx_gcc/blob/master/cmsis/MKL05Z4/startup_MKL05Z4.s

mit -Os -flto werden jetzt alle meine Interruptvektoren wegoptimiert, es 
bleiben die eigentlich als weak deklarierten leeren Schleifen aus dem 
default-handler Makro stehen.

Wahrscheinlich ist mit diesem Startup code auch irgendwas faul und gcc 
hat recht aber ich sehe es nicht.

Autor: Arno (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast doch gerade an dem Symbol __vector_table herumgebastelt - könnte 
da ein Zusammenhang bestehen? Die Vektortabelle sorgt ja meistens dafür, 
dass die richtigen Interrupt-Vektoren in der richtigen Reihenfolge an 
der richtigen Stelle stehen...

MfG, Arno

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Und wenn ich die Reihenfolge im Linkeraufruf so ändere daß der 
Startupcode zuerst genannt wird dann funktioniert der weak-Mechanismus 
wieder.

Also:

Ohne LTO: überschreiben von WEAK geht immer, egal in welcher Reihenfolge 
die Module beim Linken angegeben werden und egal ob C oder Assembler 
oder gemischt.

Mit LTO: Assembler-Module mit WEAK müssen vor den Modulen die sie 
überschreiben auf der Kommandozeile auftauchen. C-Module mit WEAK 
anscheinend nicht, muss ich aber nochmal testen.

Wenn das kein Bug ist dann bedeutet das daß Module mit WEAK 
grundsätzlich immer weiter links stehen müssen und daß es bisher (oder 
ohne LTO auch heute noch) auch mit beliebiger Reihenfolge funktioniert 
hat war ein reiner Zufall. Ich geh jetzt mal nach der Doku suchen.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arno schrieb:
> Du hast doch gerade an dem Symbol __vector_table herumgebastelt

Nein, jetzt hab ich ein noch älteres Projekt unter der Fuchtel mit ganz 
anderem Startup code. Das aus Post #1 funktioniert wieder nachdem ich 
den ein Jahr lang unbemerkt gebliebenen Namenskonflikt beseitigt habe.

Allerdings hab ich plötzlich kein gutes Gefühl mit der LTO mehr jetzt 
nachdem mir bei dem anderen Projekt plötzlich das Verhalten von WEAK um 
die Ohren fliegt (eigentlich ein komplett anders Problem, hätte 
vielleicht nen neuen Thread aufmachen sollen, aber Problem 1 war ja 
gelöst)

: Bearbeitet durch User
Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Allerdings hab ich plötzlich kein gutes Gefühl mit der LTO mehr

Evtl. fehlen Attribute an den C-Deklarationen, was sich erst bei 
(globaler) Optimierung bemerkbar macht; insbesondere "used" und 
"externally_visible".

Wenn du LTO im Verdacht hast, dann schau ins vom Compiler beim LTO-Lauf 
generierten Assembler-Code in *.ltrans*.s.  Dieser Code steht nicht in 
modul.s bzw. der dortige asm-Code ist Makulatur.

Damit hast du schon mal eine Abgrenzung ob's auf Binutils / 
Linker-Skrip-Ebene hakt oder C-seitig.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Wenn du LTO im Verdacht hast, dann schau ins vom Compiler beim LTO-Lauf
> generierten Assembler-Code in *.ltrans*.s.

Wie schalt ich die Generierung derselben ein?

Beitrag #5282418 wurde von einem Moderator gelöscht.
Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Johann L. schrieb:
>> Wenn du LTO im Verdacht hast, dann schau ins vom Compiler beim LTO-Lauf
>> generierten Assembler-Code in *.ltrans*.s.
>
> Wie schalt ich die Generierung derselben ein?

Bei
$ gcc -flto -save-temps -o a.elf ...

in a.elf.ltrans*.[os]

: Bearbeitet durch User
Beitrag #5282596 wurde von einem Moderator gelöscht.
Autor: RMszal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

I've found this topic trying to resolve my issues with -flto that 
occured in GCC 7.2.1.

I don't understand everything you've written[google translator still has 
a lot to do with translating technical language]. I assume you have some 
problems with link time optimization, which removes your sections from 
output binary.

Here is what I've observed in my example:
Looks like LTO flag used in GCC 7.2.1 removes IRQ_Handlers and replaces 
them with weak definitions from assembler statup file. What's more weird 
is that this issue depends on order of object files in linking. If 
startup file is placed first on object list, then LTO works fine. When I 
change file order, every IRQ_Handler that is placed before statup file 
on a linking list will be removed and replaced with weak definition from 
statup. I've tried to use additional attributes(keep) and GCC flags but 
it didn't help.

I am not sure if we are observing the same issue. Please let me know 
what you think about that.

I would be grateful if you could respond in english.

Best Regards

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
RMszal schrieb:
> What's more weird
> is that this issue depends on order of object files in linking. If
> startup file is placed first on object list, then LTO works fine. When I
> change file order, every IRQ_Handler that is placed before statup file
> on a linking list will be removed and replaced with weak definition from
> statup.

This is exactly the issue I am observing too.

Actually in this thread the first post was a different error, I had a 
duplicate symbol in my linker script and in my startup, this made LTO 
discard the entire output of that variable (the old one did not do this, 
so I never noticed my error). This problem is resolved because it was my 
own fault.

--

The remaining problem I am now facing is the exact same what you are 
describing, I now have to put the object file with the weak symbols 
earlier on the command line than the ones containing the strong symbol. 
This behavior is new.

I have another project with startup code written in C, the weak default 
handlers are normal c functions with __attribute((weak)) and these can 
be linked in any position and the weak/strong overriding mechanism still 
works here even with the new gcc. I am observing the problematic 
behavior only with startup code written in assembly! So something 
about the treatment of objects generated from assembly seems different 
from those generated from c sources during the LTO pass.

When I disable LTO everything works as expected again.

Currently I am fixing my makefiles to make sure the startup code object 
files are always mentioned in the first position during linking. I have 
made another thread in this forum where I asked for help finding 
detailed documentation about the usage of weak with regard to the 
linkage order, whether gcc makes any guarantees or assumptions, I 
suspect it is a bug but before I report it I need to know what the 
documentation actually has to say about this topic but I have not yet 
found it.

: Bearbeitet durch User
Autor: RMszal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Good to hear that we have same problem.

I am also preparing to report this bug, here is the simplest example 
that is not linked correctly:
volatile int flag;

void RTC1_IRQHandler(void)
{
    flag = 0;
}

int main(void)
{
    while (1)
    {
        flag++;
    }
}
I am making sure if this can not be resolved by adding some compiler 
flags/attributes to the weak declaration inside startup, but I haven't 
found any clue so far. I'll try to compare weak declarations inside C 
compiled objects.

I've also found your second thread. Please let me know if you find any 
solution[better than reordering files].

Best Regards

Beitrag #5284136 wurde von einem Moderator gelöscht.
Beitrag #5284305 wurde von einem Moderator gelöscht.
Autor: RMszal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
I've reported this issue to gcc-bugzilla, here's the link: 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83967

Autor: Bernd K. (prof7bit)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
I have made a minimal self contained project that demonstrates the bug.

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/

Autor: Nico W. (nico_w)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Da ich grad nicht viel zu tun hab, habe ich dein Beispiel mal durch den 
7.2.0 vom bleeding-edge gehauen und kann jetzt nichts ungewöhnliches 
finden.

arm-none-eabi-gcc (bleeding-edge-toolchain) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is 
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 
PURPOSE.

: Bearbeitet durch User
Autor: Nico W. (nico_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah Mist. Richtig lesen... 7.2.1 ist das Thema.

Ich bin wohl gestern in die Falle mit dem 7.3.0 getappt. Andauernd bin 
ich in einen nicht implementierten Interrupt gesprungen. Hat dann drei 
Stunden gedauert bis ich Mal den alten 6er genommen habe. Und dann viel 
mir auch der Thread wieder ein.

Autor: Nico W. (nico_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Über ein Jahr später wieder damit auf die Fresse gefallen.

Geht
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors 6-2017-q2-update) 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437]
Copyright (C) 2016 Free Software Foundation, Inc.

Geht nicht:
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 8.2.1 20181213 (release) [gcc-8-branch revision 267074]
Copyright (C) 2018 Free Software Foundation, Inc.

Sobald ich das Startup-File nach vorne beim Linker packe, läuft es auch 
im 8er.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, hab auch heute morgen nach langer Zeit auch grad wieder ein altes 
Makefile passend ändern müssen nachdem ich mich erstmal 10 Minuten am 
Kopf kratzen mußte warum das aus heiterem Himmel plötzlich nicht mehr 
funktioniert, zum Glück kam die Erinnerung an diesen Sachverhalt dann 
doch recht schnell zurück.

Ich hoffe das dauert nicht mehr allzulange oder gar noch ein paar Jahre 
bis das endlich gefixt ist und man das final abhaken und zu den Akten 
legen kann.

Autor: Nico W. (nico_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meine Erinnerung kam leider erst nach zwei Tagen und Google:"systick 
lto". :(

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.