logo elektroda
logo elektroda
X
logo elektroda

Basic use of the arm-none-eabi toolchain or what happens before main

_lazor_ 11706 31
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
📢 Listen (AI):
  • #31 17613293
    _jta_
    Electronics specialist
    A Klonano (Arduino Nano clone) on Nettigo PLN 15.9. "Blue Pill", a module with STM32F103C8T6 on Allegro from PLN 13.9, but you have to combine to connect.
  • ADVERTISEMENT
  • #32 17744022
    _lazor_
    VIP Meritorious for electroda.pl
    _jta_ wrote:
    Of course, in the code above, this is redundant

    This is not redundant, on the contrary, it is necessary if the name is to be used to generate the 32-bit address of the function - the fact that the processor has only Thumb instructions does not mean that you can load an even address into the PC with impunity - it freezes the processor, I checked.

    I used this construction, and it worked:
    Code: ARM assembler
    Log in, to see the code

    - all functions defined by _func had odd addresses.

    However, the problem with (non)parity of the address only manifests itself when the instruction uses a 32-bit address - instructions containing a relative address do not encode the lowest bit of the address and preserve the lowest PC bit.


    I finally got to the source of the problem. The address in the PC must be aligned to a half word or word, i.e. it must be even, but there is one reason why you need to set 1 for the least significant bit - legacy reason. Although the architecture does not support the ARM instruction, you still need to denote the one on the least significant bit that we have thumb instruction set.

    https://www.embedded.com/electronics-blogs/be...er-s-corner/4024632/Introduction-to-ARM-thumb

    "Since all ARM instructions will align on either a 32- or 16-bit boundary, the LSB of the address is not used in the branch directly. However, if the LSB is 1 when branching from ARM state, the processor switches to Thumb state before it begins executing from the new address; if 0 when branching from Thumb state, back to ARM state it goes."
📢 Listen (AI):

Topic summary

✨ The discussion revolves around the use of the arm-none-eabi toolchain for programming microcontrollers, specifically focusing on the startup code that executes before the main function. Participants share insights on development environments, with suggestions for using Eclipse with the GNU MCU Eclipse plugin for easier project setup. The conversation highlights the advantages of STM32 microcontrollers, such as mature development environments, cost-effective boards, and code portability. There are debates on the ease of programming 8-bit versus 32-bit microcontrollers, with some arguing that modern 32-bit systems offer more intuitive programming experiences despite their complexity. The topic also touches on debugging options, reset types in Cortex-M, and the importance of understanding the boot procedure. Additionally, there are discussions about the availability and pricing of various STM32 boards compared to Arduino clones.

FAQ

TL;DR: Enabling -O3 without -ffreestanding on bare-metal STM32 almost doubles code size (+100 %) and breaks builds, while “The -g option produces debugging information GDB can use” [Elektroda, lazor, #17571595; #17571519].

Why it matters: Correct startup, flags, and linker settings decide whether your Cortex-M even reaches main().

Quick Facts

• Reset vector lives at 0x00000004; initial SP at 0x00000000 [Elektroda, lazor, post #17568319] • Example flash region: 0x0800 0000, length 0x1000 (4 KB) [Elektroda, lazor, post #17568319] • Example SRAM region: 0x2000 0000, length 12 KB [Elektroda, lazor, post #17568319] • -ffreestanding stops GCC auto-calling memset/memcpy under -O3 [Elektroda, lazor, post #17571595] • NUCLEO-L432KC with on-board ST-Link ≈ PLN 49 [Elektroda, lazor, post #17612659]

What exactly runs before main() on a Cortex-M?

Execution starts at address 0x00000000, reading the initial stack pointer, then jumps to the Reset_Handler entry at 0x00000004. Reset_Handler calls _cstartup, which zeroes .bss, copies .data from flash to SRAM, sets up clocks if needed, and finally calls main() [Elektroda, lazor, post #17568319]

Why do I need my own startup.S file?

Startup.S defines the vector table, initial SP value, and Reset_Handler. Without it, the linker has no entry point, and the MCU boots into an undefined state. Writing it yourself lets you keep binaries small and free of vendor libraries [Elektroda, lazor, post #17568319]

What does .thumb_func really do?

.thumb_func marks following symbols as Thumb functions. The assembler stores an odd address so branches load PC with bit0=1, forcing Thumb mode. Using an even address on Cortex-M freezes execution at the first ISR fetch [Elektroda, jta, post #17597051]

How does the linker script map sections?

The sample script places .text and .rodata in flash, .bss and .data in SRAM. .data uses “AT (__rodata_end__)” so its initial values reside in flash but get copied to RAM during _cstartup [Elektroda, lazor, post #17568319]

How do I copy .data and clear .bss in C?

Use pointers provided by the linker:
  1. while(bss<bss_end) *bss++ = 0;
  2. while(data<data_end) data++ = rodata_end++;
  3. main(); This three-step loop runs in _cstartup before main [Elektroda, lazor, post #17568319]

Why add -ffreestanding when I raise optimisation to -O3?

-O3 makes GCC replace loops with memset/memcpy. In bare-metal projects these library calls are missing, so linking fails or the MCU jumps to HardFault. -ffreestanding tells GCC not to assume the standard library exists [Elektroda, lazor, post #17571595]

How can I issue a software reset on STM32 and where does execution resume?

Write 0x05FA0004 to SCB->AIRCR. After reset, the core always restarts from 0x00000000 regardless of previous VTOR settings; RCC registers retain their values [Elektroda, lazor, #17572569; RM0364, 2021].

What’s an edge case that bricks the boot?

If any vector entry holds an even address, the core attempts ARM mode (unsupported on Cortex-M) and locks up before main—no error message, just a stalled PC [Elektroda, jta, post #17597051]

How do I flash and debug without a full IDE?

3-step how-to:
  1. openocd -f board/st_nucleo_f3.cfg
  2. arm-none-eabi-gdb build.elf
  3. In GDB: target extended-remote :3333 ➜ monitor reset halt ➜ load ➜ continue Works with any ST-Link board [OpenOCD manual; Elektroda, lazor, #17568319].

Are 32-bit MCUs really harder than 8-bit AVRs?

No. Modern STM32 tools generate Makefiles, startup code and linker scripts automatically. Quote: “The plugin will generate makefiles, startups, and linker scripts” [Elektroda, chudybyk, post #17570228] Larger datasheets exist, but higher-level libraries and debuggers speed learning.

What low-cost boards include a ready programmer/debugger?

ST STM32L100C-Discovery (≈ PLN 39), Infineon XMC 2Go (≈ PLN 40), and NUCLEO-L432KC (≈ PLN 49) ship with on-board ST-Link or Segger probes [Elektroda, lazor, post #17612659]
ADVERTISEMENT