Well SOFTengCOMPelec, I finally found the error why the code would randomly crash while changing the optimization flags of GCC.
This happened when i recompiled my application, uploaded my application by use of my bootloader and then it would not run. It would hang. Only by adding some random code it would work.
This code had nothing to do with the real problem, it just solved the memory alignment and sometimes it would break it.
I compiled with optimization switch Os and i dissasembled the code.
I compiled again with optimization switch O1 and i dissasembled the code.
I used winmerge to compare the files and i knew from this that the startup.s code is not modified. So it had to be something else. Of course, the c code was heavily modified, so i was not sure about this either but at least , i could check and verify that the assembly code in startup.s is running.
I have made a small routine in my bootloader and my application that when a Program abort, data abort, undefined instruction abort or an SWI/SVC abort happens, that it traps the instruction, the memory location and dump the status from the memory controller. But unfortunately, this only works while all the code is running properly so i could never find out what happenend this way.
However, when it works :
But it is fun to see a 32 bit pointer loaded with an address where bit0 and bit1 are not 0, get trapped with a "guru meditation" error. I took that from the good ol Amiga. :awe:
What is going on
I will explain :
When the mcu starts, it runs a small assembly file called startup.s.
The mcu starts, it copies interrupt vectors and some interrupt routines to ram. Ram has no waitstates while flash has 1 waitstate, so execution is faster when run from ram. After the interrupt vectors and interrupt routines are copied to ram, the data section, the bss section, all the different stacks are copied from flash to ram and are initialized to 0 or another fill value. What i had done, to speed up execution, i do it 32 bits at once. I take full advantage of the 32bit wide architecture of the ARM. I use the LDR instructions and STR instruction that do 4 bytes (32 bits) at once.
But in my linker file there are flaws. When i change the optimization level, sometimes the load addresses for the data or the bss are not always aligned to a 4 byte boundary. Meaning bit0 and bit 1 are not both 0. Or when loading up the stack with a fill value, bit 0 and bit 1 of the start address or end address are not 0. What then will happen is that the Dabort exception will happen.
and i will have a hard crash.
I figured it out by constantly moving a bit of assembly code to turn on a led through my startup.s and see when the led is no longer turned on.
I then compared it with the map file and found out these addresses to align to 32bit boundaries.
As well as the Led method of debugging, I also like (on Arms), sending information serially to a terminal window or small Lcd display.
The Led method is good to see if it gets to a particular place in the code (without crashing). The Terminal or Lcd method is better, when the program basically works, but is NOT quite right. So you can look at individual variable(s), to see what is going on.
You might need BOTH methods, if it is a real time embedded system. The Led signal (probably watched for on a scope), to see that the timings are correct, and the terminal/Lcd to check that the value is correct.
See my previous post : Well, it works. I can now use any kind of optimization.
I modified my W-ARM program manager to produce a proper linker file where the alignment on a 32bit boundary is enforced. So all addresses end with 0, 4, 8 or C. I loose a bit of bytes because of the padding but it works. Finally i got that solved.
I'm glad that you managed to properly solve this problem. Making it so that the 4 byte (32 bit) alignment is guaranteed, sounds like exactly what you should be doing.
On the (x86, I know you are using Arm), usually if the optimization setting (with GCC) changes the program, from working to NOT working. E.g. -O3 causes bugs. I initially think that it might be a bug in the GCC compiler.
But usually after an extensive investigation, find out that I had made a mistake in the C (or C++) code, which happened to NOT matter too much, at lower levels of optimization.
E.g. Forgetting to initialize a variable. Highest levels of optimization may make this LESS forgiving, as it is more likely to share memory with something else (and then be a funny value, which messes up your program).
On the Arm (and other microcontrollers, for that matter). I often find that setting up the built in peripherals, to be the most problematic/fiddly/annoying part of the programming.
There can be so many fiddly little control bits, all over the place, and it is so easy to miss one or two, which will then usually completely mess up its correct operation.
E.g. Some peripheral devices (on chip), insist that you read a particular flag, in order for it to process the next byte. If you forget to do this (even though you don't really care about that flag). It may "jam up", and refuse to process any more bytes.