Raar gedrag compiler.


Wat blurp zegt, plus: wat als je de struct volatile maakt? Wat zie je als je er met de debugger in stapt?

Bizar is het wel.

Edit: maar als de compiler daar stopt, zou ik toch een unreachable code warning verwachten.

[Bericht gewijzigd door SparkyGSX op 9 augustus 2020 09:42:43 (27%)]

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
EricP

mét CE

Ik denk niet dat de compiler daar stopt. Ik denk dat de aanroep naar de init gewoon blijft. Ik gok erop (rew mag dat bevestigen of onderuit halen) dat die hele lwip code ook gecompileerd wordt. En dat daar ergens iets in zit wat zegt 'nou, als dit dus daarop staat, dan springen we hier overheen'. Waarop de compiler denkt: als je er toch overheen springt, dan hoeft het ook niet mee'.

Je zou eens in de code van die init moeten duiken. Of lwip compileren en in een library frotten en die mee linken.

Een andere poging zou kunnen zijn om dat mac address wat zinnigs mee te geven. En gewoon eens kijken wat de output dan is.

En ja, ik heb hier ook wel eens naar gezocht. Op een klein aantal dingetjes na, heeft de optimizer altijd gelijk gehad.

Over het algemeen is zo'n compiler niet slim genoeg om dergelijke run-time beslissingen te kunnen voorspellen. Echter, in dat geval zou de struct volatile maken ook verschil moeten maken, omdat je daarmee een dergelijke voorspelling verbiedt.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Ik heb de makefile verteld dat ie de commandlines van de compileerstappen moet laten zien. dan heb ik de ccompile main regel knip-plak genomen en de -o ... weggehaald en de -c veranderd in -S . Nu heb ik de gegenereerde assembly. Als ik nu ook nog -ggdb weghaal wordt het voor mij leesbare assembly. Hij stopt gewoon met code genereren net voor de memset als ik achter de memset nog dat macadres een waarde geef.

Ander sourcecode file: Dan komt ie er pas achter bij de LTO stap, anders al bij het compileren.

Als workaround zou ik misschien het hw adres in de structure kunnen veranderen waar ie hem heencopieert. Het enige is: tegen die tijd is de intiializatie misschien al een eind gevorderd en heeft ie hem in een hardware register gezet. (of dat het geval is weet ik niet: Ik heb de code een stuk gevolgd, maar niet zo heel diep...)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Dit is inderdaad wel erg ranzig van de compiler.
Wat gebeurd er als je de "lwipthread_opts_t opts;" globaal maakt?

Anders kun je ook nog een preprocessor file maken en kijken of daar iets raars in terecht komt.

Welke gcc versie gebruik je? Die lto-type-mismatch schijnt een bug in de compiler geweest te zijn.

Andere optie: gebruik 'clang' als dat je IDE oid toelaat?

P.S. Wat is lwipInit()? Is dat een echte functie of een of andere ranzige macro die van alles doet (en er misschien wel voor zorgt dat er dingen wegcompiled worden)?

Henri's Law 1: De wet van behoud van ellende. Law 2: Ellende komt nooit alleen.

Nogmaals, wat staat er in de map-file? Want de compiler doet wel van alles met de c-code, het is de linker die het wel of niet in de binary stopt.
En ik vermoed dat de linker heel veel weglaat als de binary zoveel kleiner wordt.

hennep

Golden Member

Dit is bijzonder, niet eerder meegemaakt.

Op zich doet memset niets anders dan bytes in de structure een waarde geven, alleen gebeurt dat in een aparte functie.
Wat als je het mac address ook in een andere functie verandert, dus in een zelfgemaakte functie.

code:

SetMac( &opts, 0x86 );

ipv.

code:

opts.macaddress[0] = 0x86;

Wordt het dan ook weggehaald door de optimiser?

Op 9 augustus 2020 15:00:15 schreef blurp:
Nogmaals, wat staat er in de map-file? Want de compiler doet wel van alles met de c-code, het is de linker die het wel of niet in de binary stopt.
En ik vermoed dat de linker heel veel weglaat als de binary zoveel kleiner wordt.

De ouderwetse manier om een compiler te maken is dat je de boel door een preprocessor haalt, dan een compiler die er assembly van maakt, dan assembler die er een binary (object) van maakt dan een linker die de boel tot een executable linkt.

Gcc houdt deze structuur aan. De rest van "main" wordt niet in de assembly gestopt. dus de boel is al fout gegaan voordat de linker aan de pas komt. Nu heb ik ook vastgesteld dat eea ook fout kan gaan met LTO in de linker, kennelijk komt die tot dezelfde conclusie als de compiler: de rest boeit niet.

De linker kan NOOIT code die de compiler niet gegenereerd heeft rechtbrijen. Hij kan niet het source bestand gaan openen en toch een stuk main-cde gaan compileren.

Op 9 augustus 2020 18:43:20 schreef hennep:

Op zich doet memset niets anders dan bytes in de structure een waarde geven, alleen gebeurt dat in een aparte functie.

Nee. Memset, kent de compiler die wordt ge-inlined.

Wat als je het mac address ook in een andere functie verandert, dus in een zelfgemaakte functie.

Had ik al getest: precies hetzelfde verhaal. commentarieer ik de assignment uit: gaat het goed, zet ik hem er in dan gaat het fout.

Ik heb het zowel m et een pointer naar "opts" als met een pointer naar het macadres geprobeerd. Zodra ik de assignment laat compileren beslist de boel dat het leven verder zinloos is en wordt er maar 14k aan executable gegenereerd.

Blurp: je mag kijken. Tegenwoordig vind ik de mapfiles onleesbaar
http://prive.bitwizard.nl/ch_fout.map http://prive.bitwizard.nl/ch_goed.map

Zeker met LTO aan.

Tussen deze twee in de code niets verander anders dan:

c code:

void set_mac2 (unsigned char *mac)
{
  mac[0] = 0;
}

commentaartekens voor die ene regel gezet.

@henri: Interessant om te proberen. Done: Static maar binnen main: gaat fout. static binnen main.c (dus file-only): gaat fout. echt global: gaat fout.

compiler:

arm-none-eabi-gcc (GNU Arm Embedded Toolchain 9-2020-q2-update) 9.3.1 20200408 (release)

P.S. Wat is lwipInit()? Is dat een echte functie of ee

Ja: echte functie.

Als het goed gaat zie je:

code:

        add     r0, sp, #12
        bl      lwipInit

de call ook echt in de assembly staan.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Dit is compleet bizar.

Hoe ziet de preprocessor file eruit? Die vraag was nog niet beantwoord.

PS: En ook nog of je clang oid kunt gebruiken.

[Bericht gewijzigd door henri62 op 10 augustus 2020 00:00:19 (20%)]

Henri's Law 1: De wet van behoud van ellende. Law 2: Ellende komt nooit alleen.

Op 9 augustus 2020 20:31:57 schreef rew:
De linker kan NOOIT code die de compiler niet gegenereerd heeft rechtbrijen. Hij kan niet het source bestand gaan openen en toch een stuk main-cde gaan compileren.

Ik weet wat een linker doet. Maar je had het erover dat de binary 60k kleiner is, en de compiler maakt geen binary.

Afijn, als je het kunt pinpointen tot een C file, en kunt aanwijzen in de assembly van die ene C-file is de volgende stap om zoveel mogelijk uit die C-file te gooien dat geen invloed heeft.

Want dit begint wel heel erg als een compiler-bug te klinken.

Op 9 augustus 2020 23:55:26 schreef henri62:
Hoe ziet de preprocessor file eruit?

Ik vind dat een lastige vraag. Enerzijds moet ik dan weer uitzoeken hoe ik die ook al weer moet maken, anderzijds verwacht ik geen spectaculaire dingen.

Mijn policy is bij dit soort dingen om ook de verzoeken te honoreren waar ik geen heil in zie: In m'n eentje heb ik die allemaal al niet gedaan en kwam ik er niet uit. 1 van de "rare, dat heeft geen zin" dingen geeft mogelijk een hint.

Mijn gevoel van "de bug" is nu dat de code voor opts->macaddress[0] = xxx; erg lijkt op iets wat intern gebruikt wordt voor "en hier stopt de executie".

PS: En ook nog of je clang oid kunt gebruiken.

Ik weet niet wat dat is. Ik gebruik geen IDE.

Ik heb alle LWIP shit uit main gehaald en een apart sourcefile voor gemaakt. Nu heb ik een my_ip_init () functie om de ip stuff te initializeren.

Ik heb in een poging een leesbare assembly te krijgen dat file gecompileerd zonder -ggdb ... Dat ziet er als volgt uit:

code:


        .section        .gnu.lto_.jmpfuncs.45ecf0a0896eca14,"e",%progbits
        .ascii  "x\234\225\223\313K\303@\020\306\347\313\246i\264V{o"
        .ascii  "\017={\360\320?P\323Z\037\024\321\233\342Az\250\005"
        .ascii  "Q\004\361Q\360\331\326\267\320\203\005O\005=\025\274"
        .ascii  "\010\036D\360 \306\231t\023C\212\025\027\206$\273\277"
        .ascii  "\371\276\331\331\215M\2407E\3010\011\300TY\221\245V"
        .ascii  "\024\352\356r\335\\Te\005\330\374\271\266\321r\207\212"

Niet leesbaar dus. Ik denk dat dit een soort van tussencode is die dan nog door LTO in de linker verder gecompileerd en geoptimaliseerd moet worden.

Ik heb LTO nu maar uitgezet: 1 complicatie minder.

Met de assignment naar een lwipopts->macaddress er in krijg ik nu 39k aan text-segment en zonder krijg ik 80k. Ik dacht dat ik 120k zou moeten krijken, maar daar doe ik even niet moeilijk over (Oh! ik denk dat ik het al weet: Dat was met -O0).

De my_ip_init geeft nu de volgende assembly:

code:


my_ip_init:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        push    {r3, r4, r5, lr}
        ldr     r5, .L11
        movs    r2, #0
        mov     r1, #2048
        ldr     r4, .L11+4
        mov     r0, r5
        bl      _pal_lld_setgroupmode
        mov     r0, r5
        movs    r2, #0
        mov     r1, #8192
        bl      _pal_lld_setgroupmode
        mov     r0, r5
        movs    r2, #0
        mov     r1, #16384
        bl      _pal_lld_setgroupmode
        mov     r0, r4
        movw    r2, #1410
        mov     r1, #2048
        bl      _pal_lld_setgroupmode
        mov     r0, r4
        movw    r2, #1410
        mov     r1, #4096
        bl      _pal_lld_setgroupmode
        mov     r0, r4
        movw    r2, #1410
        mov     r1, #8192
        bl      _pal_lld_setgroupmode
        movs    r0, #0
        pop     {r3, r4, r5, lr}
        b       lwipInit
.L12:
        .align  2

En dat is de gecompileerde versie van:

code:



void my_ip_init (void)
{
  lwipthread_opts_t opts;

  palSetPadMode (GPIOG, 11, PAL_MODE_INPUT);
  palSetPadMode (GPIOG, 13, PAL_MODE_INPUT);
  palSetPadMode (GPIOG, 14, PAL_MODE_INPUT);

  palSetPadMode (GPIOB, 11, PAL_MODE_ALTERNATE (11));
  palSetPadMode (GPIOB, 12, PAL_MODE_ALTERNATE (11));
  palSetPadMode (GPIOB, 13, PAL_MODE_ALTERNATE (11));

  memset (&opts, 0, sizeof (opts));
//  set_mac2 (opts.macaddress);

#if 0
  opts.macaddress[0] = UIDROM[0];
  opts.macaddress[1] = UIDROM[1];
  opts.macaddress[2] = UIDROM[2];
  opts.macaddress[3] = UIDROM[3];
  opts.macaddress[4] = UIDROM[4];
  opts.macaddress[5] = UIDROM[5];
#endif
  //opts.macaddress[1] = UIDROM[1];

  //lwipInit(&opts);
  lwipInit(NULL);
}

De palsetpadmode is dus wel een macro. Die maakt er kennelijk een pal_lld_setgroupmode call van.

Hey!!!! Dus nu met de assignment terug:

code:


my_ip_init:
        @ Volatile: function does not return.

De compiler denkt inderdaad dat alle code achter deze call "dood" is!

Volledige assembly van de functie:

code:


        .type   my_ip_init, %function
my_ip_init:
        @ Volatile: function does not return.
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        ldr     r5, .L11
        movs    r2, #0
        mov     r1, #2048
        ldr     r4, .L11+4
        mov     r0, r5
        push    {r3, lr}
        bl      _pal_lld_setgroupmode
        mov     r0, r5
        movs    r2, #0
        mov     r1, #8192
        bl      _pal_lld_setgroupmode
        mov     r0, r5
        movs    r2, #0
        mov     r1, #16384
        bl      _pal_lld_setgroupmode
        mov     r0, r4
        movw    r2, #1410
        mov     r1, #2048
        bl      _pal_lld_setgroupmode
        mov     r0, r4
        movw    r2, #1410
        mov     r1, #4096
        bl      _pal_lld_setgroupmode
        mov     r0, r4
        movw    r2, #1410
        mov     r1, #8192
        bl      _pal_lld_setgroupmode
        movs    r3, #0
        strb    r3, [r3, #1]
        .inst   0xdeff
.L12:
        .align  2
.L11:
        .word   1073879040
        .word   1073873920
        .size   my_ip_init, .-my_ip_init
        .section        .text.udp_artnet_init,"ax",%progbits
        .align  1

edit: Oh. Vergeten te zeggen: Ik roep lwipInit() nu aan met NULL zoals vroeger, dus al het gedoe met de lwip struct is nutteloos....

Hier is nog hoe de functie er uitziet na de preprocessor.

code:


void my_ip_init (void)
{
  lwipthread_opts_t opts;

  _pal_lld_setgroupmode(((stm32_gpio_t *)((0x40000000UL + 0x00020000UL) + 0x1800UL)), ((ioportmask_t)(1U << (11))) << 0U, (0U << 0U));
  _pal_lld_setgroupmode(((stm32_gpio_t *)((0x40000000UL + 0x00020000UL) + 0x1800UL)), ((ioportmask_t)(1U << (13))) << 0U, (0U << 0U));
  _pal_lld_setgroupmode(((stm32_gpio_t *)((0x40000000UL + 0x00020000UL) + 0x1800UL)), ((ioportmask_t)(1U << (14))) << 0U, (0U << 0U));

  _pal_lld_setgroupmode(((stm32_gpio_t *)((0x40000000UL + 0x00020000UL) + 0x0400UL)), ((ioportmask_t)(1U << (11))) << 0U, ((2U << 0U) | ((11) << 7U)));
  _pal_lld_setgroupmode(((stm32_gpio_t *)((0x40000000UL + 0x00020000UL) + 0x0400UL)), ((ioportmask_t)(1U << (12))) << 0U, ((2U << 0U) | ((11) << 7U)));
  _pal_lld_setgroupmode(((stm32_gpio_t *)((0x40000000UL + 0x00020000UL) + 0x0400UL)), ((ioportmask_t)(1U << (13))) << 0U, ((2U << 0U) | ((11) << 7U)));

  memset (&opts, 0, sizeof (opts));
# 61 "lwip.c"
  opts.macaddress[1] = ((uint8_t *)0x1FF0F420)[1];


  lwipInit(
# 64 "lwip.c" 3 4
          ((void *)0)
# 64 "lwip.c"
              );
}

[Bericht gewijzigd door rew op 10 augustus 2020 09:53:22 (11%)]

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

OPLOSSING:

Allemaal hartelijk dank voor het meedenken!

Het geheim zit hem in de declaratie van de lwipthread_opts structure. Het macadres is geen array-of-characters, maar een pointer.

code:

void my_ip_init (void)
{
  lwipthread_opts_t opts;
  char mac[8];
[... ]
  memset (&opts, 0, sizeof (opts));
  opts.macaddress = mac;
  opts.macaddress [0] = ... ; 
}

De compiler zag dus dat ik die pointer initialiseer op nul (met de memset) en dan derefereer. Dat kan niets anders doen dan crashen (null pointer dereference) dus daar stopt het programma Simpel!

Update: Nu weer bij de hardware in de buurt: Hij gebruikt nu z'n hardware uniq ID uit de UIDROM als macadres! (niet helemaal correct, maar dit zit alleen op "private networks". (tussen "broertjes" van dit ding. OK! Ook dat nu gefixed: ik gebruik nu locally administrered MAC adressen door bit 1 van het eerste byte op 1 te zetten.)

[Bericht gewijzigd door rew op 10 augustus 2020 13:28:44 (22%)]

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 10 augustus 2020 10:04:20 schreef rew:

De compiler zag dus dat ik die pointer initialiseer op nul (met de memset) en dan derefereer. Dat kan niets anders doen dan crashen (null pointer dereference) dus daar stopt het programma Simpel!

Dit vind ik zo'n bijzonder verhaal, dat ik het bijna niet kan geloven.
Maar wat spelen met de Compiler Explorer leert dat dit sinds GCC 4.9 al gebruikelijk is voor -O2.

Ook Clang doet dit.

En dus zonder foutmelding ofzo....
Leerzame case Rew, bedankt!

Update: Uiteraard staat het gewoon in de GCC Documentatie

fdelete-null-pointer-checks

Assume that programs cannot safely dereference null pointers, and that no code or data element resides at address zero. This option enables simple constant folding optimizations at all optimization levels. In addition, other optimization passes in GCC use this flag to control global dataflow analyses that eliminate useless checks for null pointers; these assume that a memory access to address zero always results in a trap, so that if a pointer is checked after it has already been dereferenced, it cannot be null.

Note however that in some environments this assumption is not true. Use -fno-delete-null-pointer-checks to disable this optimization for programs that depend on that behavior.

This option is enabled by default on most targets. On Nios II ELF, it defaults to off. On AVR, CR16, and MSP430, this option is completely disabled.

Passes that use the dataflow information are enabled independently at different optimization levels.

[Bericht gewijzigd door blurp op 10 augustus 2020 14:03:24 (26%)]

EricP

mét CE

Dus toch weer 'user error'... Die optimizers zijn zo dom nog niet. En we zijn er weer met z'n allen ingetrapt :)

Dank voor de leerzame episode, rew :)

hennep

Golden Member

De vraag is dan of je hier een warning had mogen verwachten.

opts.macaddress[0] = ...

Je verandert hier niet een enkel byte in een pointer, of in een array, maar de hele pointer. Als je werkelijk in een pointer wilt rommelen zou je dat binnen een union kunnen doen.

@hennep:

Nee, de syntax
opts.macaddress[0] = ...
refereert aan het eerste element (byte) van waar de pointer naar WIJST. Dat is de syntax, zo schrijf je dat.

Ik heb een bug ingestuurd voor gcc. Zoals altijd compleet nutteloze discussies die volgen...

Dit is de testcode die ik stuurde.

c code:


#include <string.h>

struct test {
  char *t;
} ; 

extern void somefunc (struct test *t);

void myfunc (void) 
{
  struct test mt;
  memset (&mt, 0, sizeof (mt));
  mt.t[0] = 1;
  somefunc (&mt);
}

Dit kan je met de -S optie tot een assembly file compileren. Kijk dan naar of "somefunc" nog aangeroepen wordt.

Blijkt dat er een optie -Wnull-dereference is die een warning genereert als ie dit detecteert. /dat/ is wat ik had willen zien.

Blijkt dat die NIET in -Wall zit die ik normaliter aan heb staan.

Ik heb nu een -Wall (*) -Wnull-dereference aan m'n compiler-vlaggen toegevoegd, en.... de foute code genereert nog steeds geen warning.
Edit: Dat blijkt door LTO te komen. Zoals hierboven te zien, genereert LTO niet normale assembly en moet er nog een hoop door de LTO optimizer gedaan worden. Kennelijk vinden ze het dan te laat om de warning nog te genereren....

(*)_ Ik vind dat die in m'n makefile had moeten staan, maar ik zag hem zo snel niet, Heb hem nu dus mogelijk dubbel/extra d'r in gezet.
Edit: Ja was dubbel.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Wat een achterlijke optimalisatie! Foei voor de gcc ontwikkelaars.
Dit is gewoon een bug in de code die de compiler als error moet melden als die het tegen komt. Niks wegoptimaliseren, sodemieter op!

Die ontwikkelaards bij gcc zijn echt helemaal de weg kwijt.

Daarom vroeg ik ook om de boel eens met clang te compileren. Clang is dus een C/C++ compiler. Die wordt door veel projecten gebruikt ipv gcc.

Henri's Law 1: De wet van behoud van ellende. Law 2: Ellende komt nooit alleen.

Edoch had een "volatile" het probleem waarschijnlijk ook verholpen, omdat de compiler daarmee weet dat de variabele mogelijk extern gewijzigd wordt. Daarmee was je programma waarschijnlijk onderuit gegaan vanwege de null pointer referentie, maar dat had je dan met de debugger kunnen zien.

Je hebt nooit verteld wat je zag met de debugger; komt je controller in een hardfault? Of ga je me nou vertellen dat je de debugger er niet aan gehad hebt?

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Op 10 augustus 2020 18:58:05 schreef henri62:
Wat een achterlijke optimalisatie! Foei voor de gcc ontwikkelaars.

Ze zeggen dat het een "real world" verbetering oplevert.

Ik denk dat het gaat om gevallen als:

code:


void somefunc (mytype *p)
{
  if (p == NULL) return; // of fout geven. 

  p->this = that;

  een_macro (p);
}

Die macro (of inline functie) kan je eventueel alleen voor als debugging aanstaat ook nog iets laten doen als:

code:


if (p == NULL) return;
// doe iets met p. 

(even als de body van een inline functie geschreven niet het gedoe om een meer-regelige-macro te schrijven d'r bij gehaald. )

Hier ziet de compiler dus als p null was geweest, de this/that regel zou zijn gecrashed, dus de volgende if (p == NULL) hoeft dan niet meer gemaakt te worden. Zo vervalt er wat code.

Ze zeggen ook dat het niet makkelijk te vermijden is dat de warning triggert in code die toch nooit uitgevoerd kan worden.

@sparkygsx: Het nut van de debugger is beperkt. :-(
Als ie de null dereference tegenkomt gooit ie een fault, en dan komt ie in "unhandled_fault_handler ()" terecht. Voor een paarhonderd bytes kan de maker van chibios daar wat nuttigs van maken, maar dat ding is waardeloos.

code:


void unhandled_fault_handler (void)
{
struct debug {
   void *where;
   void *arg;
   uint32_t type; 
} dbg;
  dbg.where = <waar de hardware de IP opslaat> 
  dbg.arg = <addres causing fault> 
  dbg.type = <fault_cause>
  while (1);
}

Dan kan je in de debugger met print dbg zien waar de boel gecrasht is en welk adres de fout heeft getriggerd. Deze functie zit in chibios, ik krijg het niet voor mekaar om hem te overrulen in mijn code. Als ik IN chibios ga zitten wijzigen heb ik straks problemen als ik chibios wil upgraden of zijn m'n wijzigingen weer ongedaan gemaakt als ik "schoon" begin.

Daarnaast kan je runnen tot een bepaald punt en dan met step en next kijken wanneer ie weer crasht.

Dat werkt niet want na de eerste step dan zit ie in de timer interrupt ipv op de volgende regel in je code. Dus, ja de debugger hangt er soms aan, maar door dit soort dingen werkt dat minder prettig als zou moeten.

Update: Binnen GCC lijkt er een productieve discussie ontstaan te zijn over deze warning. Er gaan stemmen op om te proberen hem aan te zetten: Er zijn nog "maar" 700 plekken in gcc waar de code iets aangepast moet worden om de warning niet te triggeren.....

Er wordt ook gesproken over may/must. Ik denk dat mijn code dan een MUST geval is: De code-flow MOET de null dereference tegenkomen. Terwijl in veel andere gevallen er een "may" is dat er een takje van de code toevallig iets raars doet waardoor de warning zou triggeren maar dat dan niet de hele code nooit meer verder kan.

[Bericht gewijzigd door rew op 11 augustus 2020 08:35:28 (12%)]

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Als ie in de hardfault zit kun je ook met je debugger de CPU registers lezen, dat staat precies de informatie die je zoekt. Als je de timer niet door laat lopen terwijl je in een breakpoint zit (dat is eigenlijk alleen nodig met live power electronics eraan), loopt die op dezelfde interval in cycles als normaal, dus hij zou niet constant in de interrupt moeten komen. Voor dit specifieke probleem had je die hele interrupt ook uit kunnen zetten.

Alsnog was het handig geweest als je een warning zit krijgen als de compiler zo'n substantieel stuk code weggooit; een enkele check zijn maar een paar instructies, zodra het meer wordt is een warning wel op zijn plaats, niemand schrijft zoveel code zonder een bedoeling.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Nouja, je hebt wel eens dat je om te testen een

code:


  while (1) {
     toggle_led (); 
     delay (100ms); 
  }

ergens in je main om zeker te weten dat ie daar aankomt. dat maakt alles wat er achter staat dode code en kan ie voor deze keer wegoptimaliseren. In het onderhavige geval merkte ik dus dat er wat fout ging doordat het programmeren veel sneller ging dan verwacht. Dat kan ook een voordeel zijn als je het WEL bedoeld had.

(in mijn huidige project zou ik bijvoorbeeld misschien de hele LWIP willen weglaten en alleen met i2c wat willen doen als ik een probleem in het i2c stuk aan het debuggen ben.)

Ja, ik heb het een keer uitgezocht waar die hardware registers zitten. Gewoon googlen en dan kom je ergens midden in een ARM architecture manual en daar staat het. Niet onthouden want met eenvoudige google kan je het vinden en 2e en derde keer kan ik het niet vinden. Register bestaat niet in mijn ARM, zit ik op een ARMv7 manual terwijl dit een ARMv6 is. En ik krijg die manuals niet genavigeerd naar dezelfde sectie voor de andere ARM. Paar keer geprobeerd. Opgegeven. Ik zal wel stom zijn.

Dat de clocks stil kunnen als de CPU stopt op een breakpunt weet ik ook. Hoe dat moet: nog niet uitgezocht.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Dat het moeilijk is komt doordat je zo eigenwijs bent om geen IDE te gebruiken; in Atollic voor STM32 bijvoorbeeld hoef je alleen het registers paneel te openen en daar staat alles wat je zoekt.

Als je dat vertikt, acht jij je tijd blijkbaar niet zoveel waard.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Aan dat voorbeeld van void somefunc (mytype *p) {...
valt niets aan te optimaliseren als je die in een externe file zet.
Het is een runtime check.

Alleen als de functie inlined wordt, zou je de regel "if (p == NULL) return;" in zijn geheel weg kunnen laten als de compiler ZEKER weet dat p geen NULL is. Dat gebeurd dan eigenlijk alleen als de p een const is oid.

Verder is het een totaal zinloze actie om daar optimalisaties op los te laten.
Zoals ik al zei, de ontwikkelaars bij de gcc community zijn volgens mij gewoon dingen aan het verzinnen om eh ... dingen te verzinnen ...
Compleet nutteloos en in veel gevallen puur om maar weer een nieuwe versie te kunnen releasen. Ik zou zegge tegen die gasten: Implementeer nu eens iets wat echt nuttig is of stop gewoon met die fratsen. Goed is goed, alleen compiler bugfixes, thats it.

Henri's Law 1: De wet van behoud van ellende. Law 2: Ellende komt nooit alleen.

Nou dat is ook wel kort door de bocht; optimalisaties zijn echt wel nuttig, en er zijn wel meer gevallen waar die check echt overbodig is.

In dit geval had de compiler ook gelijk; de code na de assignment was onbereikbaar (mits een null pointer dereference een trap geeft), en bij gevolg is de assignment zelf ook niet nuttig meer.

Stel je voor dat we bij emissienormen voor auto's in 1980 hadden gezegd: "is wel goed zo, niets meer aan doen".

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Ik heb het topic niet helemaal doorgelezen maar probeer misschien eens de memset weg te laten en de (struct/union/...) (verborgen achter de typedef) op de volgende manier op 0 te zetten:

c code:

int main (void)
{
  lwipthread_opts_t opts = { 0 };

  ... // wat initializatie dingen. 
  opts.macaddress[0] = 0x86;

  lwipInit(&opts);

 ... rest van m'n code. 

Ik vind dit persoonlijk leesbaarder en nu zal de compiler ook alles op 0 zetten en niet de implementatie van de standaard C bibliotheek. Misschien is het namelijk geen compiler bug maar een bug in de bibliotheek implementatie.

Update: ik heb net eens naar de chibios code gekeken wat die struct nu is:

c code:

/**
 * @brief   Runtime TCP/IP settings.
 */
typedef struct lwipthread_opts {
  /**
   * @brief   Pointer to MAC address as an array of 6 unsigned bytes.
   */
  uint8_t         *macaddress;
  /**
   * @brief   Network address as 32-bit unsigned integer.
   */
  uint32_t        address;
  /**
   * @brief   Network subnet mask as 32-bit unsigned integer.
   */
  uint32_t        netmask;
  /**
   * @brief   Network gateway as 32-bit unsigned integer.
   */
  uint32_t        gateway;
  /**
   * @brief   Startup network addressing mode - static, DHCP, auto.
   */
  net_addr_mode_t addrMode;
  /**
   * @brief   Host name. If NULL, a default string is used.
   * @note    Not checked for validity. In particular, spaces not allowed.
   */
#if LWIP_NETIF_HOSTNAME || defined(__DOXYGEN__)
  const char              *ourHostName;
#endif
  /**
   * @brief   Link up callback.
   *
   * @note    Called from the tcpip thread when the link goes up.
   *          Can be NULL to default to lwipDefaultLinkUpCB.
   */
  void (*link_up_cb)(void*);
  /**
   * @brief   Link down callback.
   *
   * @note    Called from the tcpip thread when the link goes down.
   *          Can be NULL to default to lwipDefaultLinkDownCB.
   */
  void (*link_down_cb)(void*);
} lwipthread_opts_t;

Dit verklaart dus ook meteen waarom wat je doet niet werkt. Je gaat daar een waarde zetten op een array die niet gealloceerd is. Je moet dus het volgende doen:

c code:


/* MAC address is 48 bits lang */
static uint8_t macaddr[] = { 0x86, 0x86, 0x86, 0x86, 0x86, 0x86 };

int main (void)
{
  lwipthread_opts_t opts = { 0 };


  ... // wat initializatie dingen. 
  opts.macaddress = macaddr;

  lwipInit(&opts);

 ... rest van m'n code. 

De compiler zal zich hierop stukgebeten hebben.

Mvg,
Daan