Forum: Compiler & IDEs Linker entfernt Symbole?!


von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

Hallo Kollegen

ich programmiere etwas für einen STM32F407.
Ich habe mir dazu ein Makefile und Linkerscript zusammengeschustert. Des 
Weiteren verwende ich FreeRTOS.
Compilieren usw. geht alles, aber ich habe festgestellt, dass der Linker 
ein paar Symbole aus FreeRTOS weg"optimiert" hat, und ich möchte gern 
verstehen, warum.

Ich habe in der Beilage mein Linkerscript und die crt0.s hinzugefügt. 
Wie iht seht, beinhaltet die Vektortabelle den Programmstart sowie den 
Stackpointer, und die Vektortabelle liegt in der Section ".vectors". Mit 
"KEEP" wird dafür gesorgt, dass der Linker die Vektortabelle auf keinen 
Fall wegoptimieren kann. Da die Vektortabelle damm im Endeffekt auf den 
Programmstart, und dieser auf "main" verweist, müsste das meiner Meinung 
nach dafür sorgen, dass absolut alle verwendeten Symbole vom Linker auch 
übernommen werden.
Nun habe ich aber mit einer FreeRTOS Datei Probleme. In der Beilage ist 
die "port.c" beigefügt, welche ich direkt so aus FreeRTOS übernommen 
habe. Die Variable "pcInterruptPriorityRegisters" ist als "static const 
volatile uint8_t * const" und liegt damit im rodata Bereich, und es wird 
auch aus dem Programmcode auf die Variable zugegriffen 
(configASSERT_DEFINED ist definiert). Damit müsste der Linker meiner 
Meinung nach dazu verpflichtet sein, diese Variable auch im 
entsprechenden rodata Bereich zu inkludieren. Macht er aber nicht: das 
Mapfile gibt die folgenden Auskünfte
1
...
2
 .data          0x0000000000000000        0x0 src/freertos/portable/GCC/ARM_CM4F/port.c.o
3
 .bss           0x0000000000000000        0x0 src/freertos/portable/GCC/ARM_CM4F/port.c.o
4
 .rodata.pcInterruptPriorityRegisters
5
                0x0000000000000000        0x4 src/freertos/portable/GCC/ARM_CM4F/port.c.o
6
 .text.vPortEndScheduler
7
                0x0000000000000000       0x38 src/freertos/portable/GCC/ARM_CM4F/port.c.o
8
 .debug_macro   0x0000000000000000      0xa78 src/freertos/portable/GCC/ARM_CM4F/port.c.o
9
 .debug_macro   0x0000000000000000      0x174 src/freertos/portable/GCC/ARM_CM4F/port.c.o
10
...

und in der Tat, wenn ich den Code debugge und an diese Stelle gerate, 
sieht man, dass diese Variable mit 0 initialisiert ist und damit an eine 
ungültige Position verweist!

Jetzt verstehe ich nicht, warum der Linker die weg optimiert. Und wenn 
das bei dieser Variable passiert, was denn sonst ist auch noch weg 
optimiert worden, von dem ich nichts weiss?

Ich habe mein Linkerscript darauf hin derart angepasst, dass ich alle 
Sections (rodata, text, rodata*) mit dem KEEP versehen habe. Und siehe 
da, mein Binary wächst von ursprünglich 63kB auf jetzt 77kB. Warum wird 
da ohne das KEEP so viel Zeug weg gelassen?
einfach KEEP hinschreiben ist keine richtige Lösung des Problems, weil 
ich damit ja auch möglicherweise Zeug in mein Binary hinein nehme, das 
ich in der Tat nicht benötige, aber andererseits scheint das Weglassen 
des KEEP dem Linker Tür und Tor zu öffnen, Zeug zu entfernen, und ich 
wüsste gern, weshalb.
Das Mapfile besagt ja; der Linker ist sich über die Existenz dieser 
"pcInterruptPriorityRegisters" Variable im Klaren, und auf diese wird ja 
in der port.c auch zugegriffen, trotzdem wird sie weg optimiert.

Kann das jemand erklären?

(Edit: [pre]-Tags eingefügt. Mod.)

: Bearbeitet durch Moderator
von MaWin (Gast)


Lesenswert?

Die Variable ist static und wird nie beschrieben.
Deshalb kann der Optimizer bei der Zuweisung ucCurrentPriority = 
pcInterruptPriorityRegisters ... direkt den Wert nehmen, mit dem 
pcInterruptPriorityRegisters statisch initialisiert wird.
Und damit entfällt die Notwendigkeit für die globale Variable komplett. 
Der Linker entfernt sie.

von Tobias P. (hubertus)


Lesenswert?

ah ja, sie wird nicht beschrieben und damit hat sie quasi den Wert 0. 
Leuchtet ein! kann ich auf irgend eine Weise prüfen, ob es noch andere 
solche Fälle im Code von FreeRTOS hat, oder muss ich, um sicher zu sein, 
im Linkerscript wirklich KEEP() einfügen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias P. schrieb:
> ah ja, sie wird nicht beschrieben und damit hat sie quasi den Wert 0.

Nein, sie wird initialisiert, damit hat sie einen Wert.

Das ist allerdings alles ziemlich wortreich, und den Beweis, dass da 
wirklich der Linker was wegnimmt, bist du irgendwie schuldig geblieben, 
also bspw. das Stück disassemblierte Funktion.

Wenn du das auf ein minimales compilierbares Beispiel runterbrechen 
kannst, kann man darüber auch diskutieren, aber durch diesen Klumpen 
blickt man nicht einfach so vom Draufschauen durch – und die mehr oder 
weniger wild *) benutzte "ungarische Notation" macht das Lesen auch 
nicht einfacher.

*) Eine uint32_t Variable wird mit "ul" gepräfixt, eine andere mit "x".

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Achso, die Variable pcInterruptPriorityRegisters kann der Compiler 
natürlich sehr wohl weg optimieren (aber nicht der Linker!), denn sie 
ist nur ein Typ-Alias für portNVIC_IP_REGISTERS_OFFSET_16 welches den 
konstanten Wert 0xE000E3F0 hat. Damit kann er den kompletten Zugriff 
gleich von vornherein auf diese Adresse beziehen.

von Rolf M. (rmagnus)


Lesenswert?

Tobias P. schrieb:
> ah ja, sie wird nicht beschrieben und damit hat sie quasi den Wert 0.
> Leuchtet ein!

Sie wird gar nicht erst benötigt. Die einzige Verwendung ist:
1
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];

Und wie MaWin schon sagt, kann dort einfach direkt der Wert eingesetzt 
werden. Aber da sie static ist, soll sie sowieso gar nicht erst ein 
Linkersymbol bekommen. Damit sagt man ja schließlich ausdrücklich, dass 
nur in dieser einen Übersetzungseinheit der Name überhaupt sichtbar sein 
soll.

> kann ich auf irgend eine Weise prüfen, ob es noch andere solche Fälle im
> Code von FreeRTOS hat, oder muss ich, um sicher zu sein, im Linkerscript
> wirklich KEEP() einfügen?

Welches Problem versuchst du denn eigentlich zu lösen? Wenn der Compiler 
die Variable hier wegoptimiert, tut er das, weil er sie nicht braucht.

: Bearbeitet durch User
Beitrag #6694054 wurde vom Autor gelöscht.
von Tobias P. (hubertus)


Lesenswert?

Rolf M. schrieb:
> Welches Problem versuchst du denn eigentlich zu lösen? Wenn der Compiler
> die Variable hier wegoptimiert, tut er das, weil er sie nicht braucht.

offenbar braucht er sie. Ich hatte das Problem, dass, sobald die 
Funktion vPortValidateInterruptPriority aufgerufen wurde, der Code 
versucht, auf pcInterruptPriorityRegisters[ulCurrentInterrupt] 
zuzugreifen - und da diese pcInterruptPriorityRegisters Variable mit 0 
initialisiert ist, kracht es da (Pointer mit Wert 0 - Zugriff auf 
falsche Adresse).

Aber ich sehe ein, dass die Frage so nicht gut gestellt ist. Ich werde 
morgen ein Minimalbeispiel erstellen, wo nur FreeRTOS drin ist und sonst 
nichts. Dann sieht man im Mapfile, dass die Variable wegoptimiert wurde.

Jörg W. schrieb:
> und die mehr oder weniger wild *) benutzte "ungarische Notation" macht
> das Lesen auch nicht einfacher.
> *) Eine uint32_t Variable wird mit "ul" gepräfixt, eine andere mit "x".

ja ich finde die ungarische Notation auch sehr wüst. Aber FreeRTOS nutzt 
die halt 😞

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias P. schrieb:
> Dann sieht man im Mapfile, dass die Variable wegoptimiert wurde.

Im Mapfile siehst du davon gar nichts, weil sie statisch ist. Die taucht 
nie als globales Symbol auf.

von Tobias P. (hubertus)


Lesenswert?

Jörg W. schrieb:
> Im Mapfile siehst du davon gar nichts, weil sie statisch ist. Die taucht
> nie als globales Symbol auf.

doch, klar findet man diese Variable im Mapfile. Ich habe sie ja schon 
mal gefunden.
Ich bin grad am falschen PC und habe die Projektfiles grade nicht zur 
Hand, aber wollen wir eine Wette abschliessen? ;-)

von MaWin (Gast)


Lesenswert?

Tobias P. schrieb:
> kracht es da (Pointer mit Wert 0 - Zugriff auf
> falsche Adresse).

Das fände ich allerdings komisch.
Das wäre ein separater Fehler im Optimizer. Mit dem Verschwinden des 
Symbols hat das nichts zu tun.
Der Compiler darf, wie gesagt, den Zugriff auf die Variable 
wegoptimieren und der Linker darf dann in Folge die ganze Variable 
wegoptimieren.
Aber Die Zuweisung im Code muss dann immer noch den Konstantwert von 
pcInterruptPriorityRegisters bekommen und der Code muss korrekt 
funktionieren.

von Tobias P. (hubertus)


Lesenswert?

MaWin schrieb:
> Aber Die Zuweisung im Code muss dann immer noch den Konstantwert von
> pcInterruptPriorityRegisters bekommen und der Code muss korrekt
> funktionieren.

Jein - das gilt natürlich nur unter der Voraussetzung, dass mein selber 
gebasteltes Linkerscript auch korrekt ist. Was ich nicht weiss.

von MaWin (Gast)


Lesenswert?

Tobias P. schrieb:
> Jein - das gilt natürlich nur unter der Voraussetzung, dass mein selber
> gebasteltes Linkerscript auch korrekt ist. Was ich nicht weiss.

Ich glaube nicht, dass das vom Linkerscript abhängt, da die Variable 
static ist.
Der Zugriff wird bereits vor dem Linken optimiert.

Oder verwendest du LTO? Da weiß ich es jetzt nicht.

von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

So, ich habe jetzt ein Testprojekt zusammengenagelt. Damit kann man das 
Problem nachvollziehen.
Wenn man das Projekt mit "make" so erstellt, wie es gegenwärtig ist, 
dann wird unter "lst" die "test.map" erstellt. Dort findet man die Info
1
 .rodata.pcInterruptPriorityRegisters
2
                0x00000000        0x4 src/freertos/portable/GCC/ARM_CM4F/port.c.o

und die Binary Size ist 11120.
Wenn man im Linkerscript stm32f407ve_ram.ld die paar Zeilen
1
  .text :
2
  {
3
    . = ALIGN(4);
4
    KEEP(*(.vectors*))
5
    *(.text*)
6
    *(.rodata)
7
    *(.rodata*)
8
    . = ALIGN(4);
9
  } > ram

zu
1
  .text :
2
  {
3
    . = ALIGN(4);
4
    KEEP(*(.vectors*))
5
    KEEP(*(.text*))
6
    KEEP(*(.rodata))
7
    KEEP(*(.rodata*))
8
    . = ALIGN(4);
9
  } > ram

ändert, ist die Binary Size 26420 und im Mapfile findet man die Info
1
 .rodata.pcInterruptPriorityRegisters
2
                0x2000672c        0x4 src/freertos/portable/GCC/ARM_CM4F/port.c.o

die Variable liegt also, abhängig davon ob eine Sektion im Linerscript 
als KEEP deklariert wird oder nicht, am unterschiedlichen Orten und im 
einen Fall ist sie sogar komplett falsch.

LTO wird nicht verwendet. (und die Wette mit Jörg habe ich gewonnen 
;-)).

Ich würde gerne verstehen, warum es das KEEP im Linkerscript braucht, 
damit die Variable am rechten Ort liegt. Ich möchte das KEEP lieber 
nicht verwenden, da so möglicherweise massenhaft Zeug in meinem Binary 
landet, das wirklich nicht gebraucht wird.

von Johannes S. (Gast)


Lesenswert?

Wird eventuell das ganze rodata rausgeworfen weil der Linker die 
Verwendung nicht erkennen kann?

Beitrag #6694268 wurde von einem Moderator gelöscht.
von Johannes S. (Gast)


Lesenswert?

mit
1
  .text :
2
  {
3
    . = ALIGN(4);
4
    KEEP(*(.vectors*))
5
    *(.text*)
6
    KEEP(*(.rodata*))
7
    . = ALIGN(4);
8
  } > ram

bleibt pcInterruptPriorityRegisters auch im mapfile an addr 
0x0000000020002b74 und .text wird nur 8 Byte größer (11128).

von Bauform B. (bauformb)


Lesenswert?

Also, jetzt mal rein statistisch. Der Compiler, der Linker und FreeRTOS 
sind millionenfach getestet und wer hat da jemals ein KEEP gebraucht? 
Wenn ich wetten würde, dann eher auf eine falsche config in der Nähe von 
MAX_SYSCALL_INTERRUPT_PRIORITY oder verschobene priority-Bits oder eine 
falsch interpretierte Debugger-Ausgabe oder...

von Rolf M. (rmagnus)


Lesenswert?

Tobias P. schrieb:
> Jörg W. schrieb:
>> Im Mapfile siehst du davon gar nichts, weil sie statisch ist. Die taucht
>> nie als globales Symbol auf.
>
> doch, klar findet man diese Variable im Mapfile. Ich habe sie ja schon
> mal gefunden.

Ok, bei dir sind soweit ich sehen kann alle Optimierungen abgeschaltet. 
Es scheint, dass der Compiler dann die Variable nicht rauswirft, aber 
der Linker sie dann ignoriert. Mit Optimierungen verschwindet die 
Variable bei mir ganz aus dem Mapfile.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Mit Optimierungen verschwindet die Variable bei mir ganz aus dem
> Mapfile.

Was ja auch Sinn hat, denn keiner braucht sie.

Sorry, auf die Idee, dass jemand ohne Optimierungen compiliert, war ich 
gar nicht erst gekommen. ;-)

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hier ist übrigens die entsprechende Stelle im generierten Code:
1
    void vPortValidateInterruptPriority( void )
2
    {
3
200024c0:       b480            push    {r7}
4
200024c2:       b085            sub     sp, #20
5
200024c4:       af00            add     r7, sp, #0
6
        uint32_t ulCurrentInterrupt;
7
        uint8_t ucCurrentPriority;
8
9
        /* Obtain the number of the currently executing interrupt. */
10
        __asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" );
11
200024c6:       f3ef 8305       mrs     r3, IPSR
12
200024ca:       60fb            str     r3, [r7, #12]
13
14
        /* Is the interrupt number a user defined interrupt? */
15
        if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
16
200024cc:       68fb            ldr     r3, [r7, #12]
17
200024ce:       2b0f            cmp     r3, #15
18
200024d0:       d913            bls.n   200024fa <vPortValidateInterruptPriority+0x3a>
19
        {
20
            /* Look up the interrupt's priority. */
21
            ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
22
200024d2:       4a16            ldr     r2, [pc, #88]   ; (2000252c <vPortValidateInterruptPriority+0x6c>)
23
200024d4:       68fb            ldr     r3, [r7, #12]
24
200024d6:       4413            add     r3, r2
25
200024d8:       781b            ldrb    r3, [r3, #0]
26
200024da:       72fb            strb    r3, [r7, #11]
27
28
29
30
2000252c:       e000e3f0        .word   0xe000e3f0

Da siehst du, dass er selbst bei -O0 den konstanten Wert 0xe000e3f0 
benutzt. Deine ganze schöne "const volatile static"-Variable 
pcInterruptPriorityRegisters interessiert den Compiler nicht die Bohne.

von Tobias P. (hubertus)


Lesenswert?

Jörg W. schrieb:
> Was ja auch Sinn hat, denn keiner braucht sie.

doch, wenn aus einer ISR heraus auf einen Semaphor oder Mutex 
zugegriffen wird, dann wird diese vPortValidateInterruptPriority 
aufgerufen, und dann findet auch ein Zugriff auf diese Variable statt. 
Diese Variable sollte eigentlich ein Pointer auf die Tabelle des NVIC 
sein, wo die Interruptprioritäten eingetragen werden.

Der Code ist allerdings vom FreeRTOS Projekt und nicht von mir, ich find 
den auch nicht so schön, aber umschreiben möchte ich ihn auch nur 
ungern, weil man dann nicht mehr so einfach eine neue Version von 
FreeRTOS benutzen kann.

> Sorry, auf die Idee, dass jemand ohne Optimierungen compiliert, war ich
> gar nicht erst gekommen. ;-)

ohne Optimierungen compilieren will man doch, wenn man noch debuggen 
will?!

Johannes S. schrieb:
> mit  .text :
>   {
>     . = ALIGN(4);
>     KEEP(*(.vectors*))
>     *(.text*)
>     KEEP(*(.rodata*))
>     . = ALIGN(4);
>   } > ram
>
> bleibt pcInterruptPriorityRegisters auch im mapfile an addr
> 0x0000000020002b74 und .text wird nur 8 Byte größer (11128).

das ist durchaus spannend. Ist das eine saubere Lösung?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias P. schrieb:
> Jörg W. schrieb:
>> Was ja auch Sinn hat, denn keiner braucht sie.
>
> doch, wenn aus einer ISR heraus auf einen Semaphor oder Mutex
> zugegriffen wird, dann wird diese vPortValidateInterruptPriority
> aufgerufen, und dann findet auch ein Zugriff auf diese Variable statt.

Nein, findet nicht, siehe obige Erklärung. Das ist keine "Variable", 
alles da drin ist konstant und die entsprechende Adresse kann zur 
Compilezeit ermittelt werden (und wird auch).

>> Sorry, auf die Idee, dass jemand ohne Optimierungen compiliert, war ich
>> gar nicht erst gekommen. ;-)
>
> ohne Optimierungen compilieren will man doch, wenn man noch debuggen
> will?!

Also ob man das will, weiß ich nicht :), ich will das nie.

Man debuggt ja dann etwas komplett anderes als das, was man später 
laufen lassen möchte. Im Endeffekt debuggt man daher zweimal. Da kann 
ich auch auf das erste Mal gleich verzichten.

Ja, optimierter Code lässt sich natürlich schwieriger debuggen, gar 
keine Frage, und man muss hie und da auch mal in die Trickkiste greifen, 
um das eine oder andere weg optimierte Detail dann doch noch im Debugger 
sehen zu können. Mein Standardspruch dafür: Wenn es so einfach wäre, 
dass es jeder (aus dem Stegreif) könnte, würde mein Chef mich nicht 
dafür bezahlen. ;-) (Das heißt aber natürlich nicht, dass man das nicht 
lernen kann oder sollte.)

> das ist durchaus spannend. Ist das eine saubere Lösung?

Nein.

Du hast bislang noch gar kein Problem zeigen können, außer dass es dich 
stört, dass eine absolut nichtsnutzige Variable nicht mehr in der 
Symboltabelle auftaucht.

Die Stelle, an der die entsprechende Berechnung völlig korrekt jedoch 
ohne diese Variable ausgeführt wird, habe ich dir ein Posting über 
deinem gezeigt.

von MaWin (Gast)


Lesenswert?

Tobias P. schrieb:
> und dann findet auch ein Zugriff auf diese Variable statt.

Nein.
Es wurde ja schon mehrfach erklärt, dass der Zugriff wegoptimiert wird 
und durch einen äquivalenten Direktzugriff auf den Speicherbereich 
ersetzt wird.
Die Variable wird also nicht mehr gebraucht und damit fliegt sie raus.
Der Code funktioniert trotzdem. Die Variable wird durch eine Konstante 
in .text ersetzt.

von Bauform B. (bauformb)


Lesenswert?

Sieh es vielleicht mal so: Der ganze "Fehler" ist, dass diese Variable 
im Flash statt im RAM angelegt wird. Dadurch sind die Bytes in rodata 
wirklich überflüssig.

Tobias P. schrieb:
> Jörg W. schrieb:
>> Was ja auch Sinn hat, denn keiner braucht sie.
>
> doch, wenn aus einer ISR heraus auf einen Semaphor oder Mutex
> zugegriffen wird, dann wird diese vPortValidateInterruptPriority
> aufgerufen, und dann findet auch ein Zugriff auf diese Variable statt.\

der Zugriff steht auf 2000290e:
1
/* Look up the interrupt's priority. */
2
   ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
3
2000290e:       4a17            ldr     r2, [pc, #92]   ; (2000296c <vPortValidateInterruptPriority+0x70>)

> Diese Variable sollte eigentlich ein Pointer auf die Tabelle des NVIC
> sein, wo die Interruptprioritäten eingetragen werden.

Ist es ja auch, auf 2000296c steht e000e3f0. Ja, die Tabelle fängt 
genaugenommen erst auf e000e3400 an, aber in der stehen nur die normalen 
Interrupts und "mrs  r3, IPSR" liefert die um 16 größere Vektornummer.

von Bauform B. (bauformb)


Lesenswert?

Tobias P. schrieb:
> Jörg W. schrieb:
>> Im Mapfile siehst du davon gar nichts, weil sie statisch ist. Die taucht
>> nie als globales Symbol auf.
>
> doch, klar findet man diese Variable im Mapfile. Ich habe sie ja schon
> mal gefunden.
> Ich bin grad am falschen PC und habe die Projektfiles grade nicht zur
> Hand, aber wollen wir eine Wette abschliessen? ;-)

Ihr habt beide Recht, die taucht zwar auf, aber im Abschnitt "Discarded 
input sections", Nomen est Omen oder so.

Tobias P. schrieb:
> Und wenn das bei dieser Variable passiert, was denn sonst ist
> auch noch weg optimiert worden, von dem ich nichts weiss?

Wenn du es wirklich wissen willst: alles, was unter "Discarded input 
sections" auftaucht. Aber das sollte dich nicht beunruhigen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bauform B. schrieb:
> Der ganze "Fehler" ist, dass diese Variable im Flash statt im RAM
> angelegt wird.

Hmm, naja. Das Ablegen größerer Werte, die nicht als Direktoperanden 
einbettbar sind, hinter den jeweiligen Codeblöcken ist bei ARM gängige 
Praxis. Das würde ich jetzt noch nicht als "Anlegen einer Variablen" 
bezeichnen. ;-)

Hintergrund: bei RISC hat man nur begrenzt Platz im Befehl selbst zu 
Ablegen von Direktoperanden. Erste RISC-Architekturen haben dann oft 
low- und high-Teil eines Operanden in zwei Schritten geladen (2 
32-Bit-Befehle mit je 16-Bit Operanden), bei ARM dagegen werden die 
Operanden in den Code eingebettet und dann PC-relativ adressiert, weil 
man dafür nur relativ wenige Bits im Opcode für den PC-Offset braucht.

von Bauform B. (bauformb)


Lesenswert?

Jörg W. schrieb:
> Bauform B. schrieb:
>> Der ganze "Fehler" ist, dass diese Variable im Flash statt im RAM
>> angelegt wird.
>
> Hmm, naja. Das Ablegen größerer Werte, die nicht als Direktoperanden
> einbettbar sind, hinter den jeweiligen Codeblöcken ist bei ARM gängige
> Praxis. Das würde ich jetzt noch nicht als "Anlegen einer Variablen"
> bezeichnen. ;-)

Irgendwie muss man doch die Realität mit Tobias' Wünschen(?) in Einklang 
bringen können...
Der Begriff "Variable" ist in diesem Faden nicht so eng zu sehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bauform B. schrieb:
> Irgendwie muss man doch die Realität mit Tobias' Wünschen(?) in Einklang
> bringen können...

:-)

von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

Hallo zusammen

OK ich habe mich da vom Debugger täuschen lassen!
Ich verwende niemals Eclipse, sondern OZONE von Segger. Das funktioniert 
eigentlich sehr sehr gut.
Wenn man sich die Disassembly (oben rechts) genau anschaut, sieht man, 
dass in der Tat der Zugriff auf die korrekte Adresse erfolgt - 
lustigerweise ist aber im "Watch Window" unten rechts der Wert der 
pcInterruptPriorityRegisters offenbar 0. Das ist nicht sehr logisch.
Ich dachte dann erst, dass mein Code nicht lief, weil diese Variable 
(oder meinetwegen Konstante...) den falschen Wert hat, der wahre Grund 
war aber, dass die Interruptprioritäten tatsächlich falsch gesetzt waren 
- die Funktion vPortValidateInterruptPriority ist im assert (Zeile 764) 
stecken geblieben.

Ich bin noch nicht 100% sicher, ob der Code jetzt richtig funktioniert, 
aber zumindest hat diese Variable in der Tat den falschen Wert, der 
Zugriff funktioniert aber trotzdem. Sehr mysteriös.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias P. schrieb:
> aber zumindest hat diese Variable in der Tat den falschen Wert

Naja, die Variable gibt es halt nicht, da der Compiler sie ja nie 
benutzt hat. Dass er dir mit -O0 dennoch ein Symbol hinterlässt, nun ja, 
Segger schnallt dann wohl nicht, dass das Symbol gar keinen Wert hat und 
gibt stattdessen 0 aus.

Eigentlich noch ein Punkt mehr, nicht ohne eingeschaltete Optimierung zu 
debuggen. ;-)

von Tobias P. (hubertus)


Lesenswert?

Jörg W. schrieb:
> Naja, die Variable gibt es halt nicht, da der Compiler sie ja nie
> benutzt hat. Dass er dir mit -O0 dennoch ein Symbol hinterlässt, nun ja,
> Segger schnallt dann wohl nicht, dass das Symbol gar keinen Wert hat und
> gibt stattdessen 0 aus.

naja ich verstehe noch nicht ganz, wie dann der Zugriff auf dieses 
Interruptregister funktioniert.
Spasseshalber werde ich jetzt mal mit -O3 debuggen. Ich mach das aber 
immer nicht so gern, weil da der Debugger zum Teil wild zwischen den 
Zeilen herumspringt, weil eben gewisse Optimierungen vorgenommen werden.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Tobias P. schrieb:
> wie dann der Zugriff auf dieses
> Interruptregister funktioniert.

Der asm-Code wurde doch bereits gepostet.
Dort steht alles drin.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias P. schrieb:
> naja ich verstehe noch nicht ganz, wie dann der Zugriff auf dieses
> Interruptregister funktioniert

Das Disassembler-Listing habe ich dir doch oben gezeigt.

Deine "Variable" ist letztlich weiter nichts als ein Hilfskonstrukt, um 
aus der puren Adresse (portNVIC_IP_REGISTERS_OFFSET_16) via Typecast 
einen für dich sinnvoll benutzbaren C-Konstrukt zu machen. Aber den 
brauchst du nur, damit du mit den Mitteln der Hochsprache angenehm drauf 
zugreifen kannst. In der Realität ist da drunter ja trotzdem noch 
einfach nur ein bisschen Adressrechnung und ein Buszugriff (auf ein 
MMIO-Register).

Edit: von -O3 würde ich dir stark abraten. Das ist eine so aggressive 
Laufzeitoptimierung, dass dabei u.a. Schleifen entrollt werden, was das 
Zeug hält. Der Code wird halt größer aber schneller. Such dir irgendwas 
zwischen -O1, -Os oder -Og aus.

: Bearbeitet durch Moderator
von Rolf M. (rmagnus)


Lesenswert?

Stell dir mal folgendes vor:
1
static const int x = 5;
2
3
int function(void)
4
{
5
    int a = x + 3;
6
    
7
    // … mach was mit a
8
}

Der Compiler wird hier für die 5. Zeile nicht Code generieren, der x 
einliest, 3 dazu adiiert und das Ergebnis nach a schreibt, sondern Code, 
der einfach direkt 8 nach a schreibt. Er weiß ja, dass das das Ergebnis 
der Berechnung sein wird, also kann er sich diese Addition zur Laufzeit 
sparen. Dann wird aber x gar nicht mehr benutzt, denn es war ja nur der 
Input für die nicht mehr statt findende Addition. Damit kann es also 
auch weg.
Genau das gleiche passiert bei dir auch, nur mit einen Pointer statt 
einem int.

: Bearbeitet durch User
von Kochstudio (Gast)


Lesenswert?

Rolf M. schrieb:
> Stell dir mal folgendes vor:

Damit kann man auch immer mal den Godbolt Compiler Explorer befragen

https://godbolt.org/

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.