Crt0 _start causes hardfault

Asked by Andrea Merello

I use have a STM32F407 cortex M4, with the linker script and startup file suggested in "readme.txt".
I have adapted memory map in linker script and Interrupt vector in startup.
I compile and link my application, but the processor jumps in the hard fault handler before reaching main.
The processor calls "atexit" function and then the problem happen when in _register_exitproc it executes
pop {r4-r8,pc}

The PC is loaded with a wrong value and the execution jumps in the wrong location.

Surprisingly if in the startup I do not call the crt _start and I make directly a jump to my main function (I have to zero the BSS by myself) then all works (including the few NewLib functions I use in my application).

Any suggestion?

Thank you

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Andrea Merello
Solved:
Last query:
Last reply:
Revision history for this message
chengbin (can-finner) said :
#1

Hi Andrea Merello,
I will look into this issue.

One thing I need to know is which crt0.o are you linking in your project.
In our release, there are crt0.o/rdimon-crt0.o/rdpmon-crt0.o, etc. in each multilib directory.

Also, could you provide your command line options in your project?

Thanks very much.

Revision history for this message
Andrea Merello (andrea-merello) said :
#2

Thank you for your answer.

It should link to arm-none-eabi/lib/armv7e-m/fpu/crt0.o

Do you have any suggestion about how to check if it is really hitting the right one?

I checked by comparing the disassemly output of my final elf and the various crt0 files and looking at the first instructions of the start function it seems to be the right one...
 I can tell for sure it is NOT linking with the rdi/rdp version and it is NOT linking with the default arm-none-eabi/lib/crt0.o because I found those file different in the first instruction of the start function..

In my makefile the GCC is invoked with the following options:

CFLAGS = -I./ -c -fno-common -O0 -g -lnosys -mcpu=cortex-m4 -mthumb -nostdlib -I../lwip-1.3.2/src/include -I../lwip-1.3.2/src/include/ipv4 $(FPUFLAGS)

The linker (gcc is called as a ld frontend) options are:
LFLAGS = -Tems.ld -mcpu=cortex-m4 -mthumb -lnosys $(FPUFLAGS)

where FPUFLAGS is set to -mfloat-abi=hard -mfpu=fpv4-sp-d16

Thanks a lot
Andrea

Revision history for this message
Andrea Merello (andrea-merello) said :
#3

Please forget the -lnosys.
It was added afterin the makefile to do a test but I always compiled without that option..
Thanks

Revision history for this message
chengbin (can-finner) said :
#4

Hi Andrea Merello,

I had difficulty in re-producing the issue at my side. Here is what I have done:

STEP1, scratch a simple main.c program:

double d1=1.01, d2 = 10.23;
int main(void)
{
  d1 = d2 - d1;
  return (int)d1;
}

STEP2, extract the link script from readme.txt, with FLASH/RAM changed according to the board layout:

MEMORY
{
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x20000
  RAM (rx) : ORIGIN = 0x20000000, LENGTH = 0x4000
}

STEP3, extract the startup.S from readme.txt

STEP4, compile the program with:

$ arm-none-eabi-gcc -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 main.c startup.S -Wl,-T,ld.script -fno-common -D__NO_SYSTEM_INIT -O0 -gdwarf-2 -o main.out

The generated works on target board and I can debug the double add operation in main.

The example also works if I separated the compile/link processes using your command line options.

So there must be some in-consistence between us, which I have no clue.

As for checking which version crt0.o got linked, you can specify -v at gcc command link. For example,

$ arm-none-eabi-gcc -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 main.c startup.S -Wl,-T,ld.script -fno-common -D__NO_SYSTEM_INIT -O0 -gdwarf-2 -o main.out -v

The output will show you the information.

The one linked into my program is arm-none-eabi/lib/armv7e-m/fpu/crt0.o

Revision history for this message
chengbin (can-finner) said :
#5

Hi Andrea Merello,
Could you please try the work that I have done at your side and maybe can find something.
Also I can try your project, if it is ok for you to abstract an example and let me practise with it.

Thanks very much.

Revision history for this message
Andrea Merello (andrea-merello) said :
#6

Hello
Thank you for your help!

I tried your example and it works.
I find out what is the difference that caused the problem (so I can say I solved it) even if I can't understand why it was causing this problem.

In my int vector table the first element (the stack address) was initialized with the variable "_stack".
Instead of changing it in "__stack" in the vector table, I stupidly changed its name In the linker script:
I changed

PROVIDE(__stack = __StackTop);
in
PROVIDE(_stack = __StackTop);

and this caused the problem.

I suppose the symbol "__stack" was used somewhere other than in my vector table and thus modifying it's in the linker script caused the malfunction, but honestly I can't understand why the compiler/linker had not issued any error about "__stack" not defined anymore..
And I couldn't even find any other reference to "__stack": I run a "grep" for "__stack" and I found no occurrence other than the one in vector table and linker script..

Despite this doubt, Indeed it was my fault, and now it is working.

Thank you a lot!
Andrea

Revision history for this message
chengbin (can-finner) said :
#7

Hi Andrea,

I am glad to hear that.

Well, in my example, __stack should be referred only once in int vector.
I guess the problem could be triggered by some kind of symbol disruption.
For example, If your program defines _stack somewhere else, linker script
won't define it any more, the stack entry would be wrong in this case.
Anyway, this is just an assumption.

Thanks.