Effect of ENTRY directive in Linker Script on Cortex-M4 binary

My initial understanding of ARM Cortex-M4 bootstraping sequence was that when MCU was started, it loaded pointer from Reset_Handler IVT and then jumped to that address to start configuring the processor.
Later on when I started doing some stuff on Linker Script, I noted something called ENTRY keyword which by GNU Linker documentation specified that it defined starting point of binary. So which one is it, IVR or ENTRY? That’s what we are going to tackle in this post.

Used tools

For this test I’m going to use STMCubeIDE and Ghidra compiler.

Starting point

By default, when project is created in STM32CubeIDE, a corresponding linker script is created with following entry value:

ENTRY(Reset_Handler)

When the binary is compiled we can see that there second address in IVT is actually the Reset_Handler (after stack pointer value).

Contents of IVT

This outcome is expected and I would assume that when running the code, the MCU would jump to Reset_Handler symbol address.

Reset_Handler assembly

Here we can see that MCU jumped to Reset_handler with ENTRY(Reset_Handler) and IVT also having the same address.

Same test with different ENTRY

Now we will change the Entry to MemManage_Handler for the sake of the test:

ENTRY(MemManage_Handler)

After compiling binary we get the following NIVT:

NIVT for ENTRY(MemManage_Handler)

We can see here that the IVT is still the same and that Reset_Handler is still present as entry-point address.
But when we run the code from IDE, we no longer reach Reset_Handler symbol (instruction).

MemManage_Handler breakpoint

How can this be? At this point I got hunch that the image loaded to MCU is not the same as ELF file produced by the compiler/linker. Let’s check what does the flash export from MCU gives us.

Unfortunately, it’s not it. We can see that two first addresses are the same in Elf and in Flash. How did we get to the MemManage_Handler then? Could it be that after firmware download, the debugger set the starting position? We can test this by doing a reset withing the MemManage_Handler and see if the system would land back to the Reset_Handler.

Adding SystemReest to MemManage_Handler

After I downloaded the image to MCU, after NVIC_SystemReset() call, the controller started from the … Reset_Handler.

Recap

The effect of ENTRY does not have effect if the binary is not started from IDE (in this case STMCubeIDE). If code is started with Debug session, the debugger will force-set the starting address to value of ENTRY symbol.

Why is IDE doing this?

One reason may be that when writing custom bootloaders, we do not want to start from the IVT address starting at address 0x0000 0000, but rather we want to only test the our application without starting through bootloader code.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *