Where are _start() and rt_entry() functions implementations?

Hello everyone,
I try to understand how mbed os starts. First I launch a blinky example and in debug mode I found that one of the first function called is rt_entry() in mbed-os/cmsis/device/rtos/TOOLCHAIN_ARM_STD/mbed_boot_arm_std.c. I wasn’t able to get the implementation of the function. Where it is and what is it?

I looked the startup file (startup_stm32f411xe.S) and I saw following:

/* Call the clock system intitialization function.*/
  bl  SystemInit   
	bl _start
	bx lr
  bx  lr   

I see several calls to _start() function, but I don’t know how to get to the implementation of it. Can someone help?
Thank you very much


The _start symbol is defined in C runtime startup code.
You can find the symbol in ./BUILD/NUCLEO_F411RE/GCC_ARM/mbed-os-example-blinky.map file.

 .text          0x0000000008000198       0x40 /usr/local/bin/gcc-arm-none-eabi-10.3-2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/thumb/v7e-m+fp/softfp/crtbegin.o
 .text          0x00000000080001d8       0x7c /usr/local/bin/gcc-arm-none-eabi-10.3-2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/softfp/crt0.o
                0x00000000080001d8                _stack_init
                0x00000000080001e0                _mainCRTStartup
                0x00000000080001e0                _start
 *fill*         0x0000000008000254        0x4 

The _start symbol is located at the same address of _mainCRTStartup. You can the file crt0.o in your toolchain. In my case, I have the crt0.o here: /usr/local/bin/gcc-arm-none-eabi-10.3-2021.10/arm-none-eabi/lib/thumb/v7e-m+fp/softfp/crt0.o

You can get source code of this object like this.

$ arm-none-eabi-objdump -S  /usr/local/bin/gcc-arm-none-eabi-10.3-2021.10/arm-none-eabi/lib/thumb/v7e-m+fp/softfp/crt0.o 

For the __rt_entry call by Arm compiler, please see this:

I hope this helps.


Hi, thank you for answer.
How do you know it is the crt0.o found in v7e-m+fp/softfp/ ?
When I objdump it, I have following output:

00000000 <_stack_init>:
   0:	f5a3 3a80 	sub.w	sl, r3, #65536	; 0x10000
   4:	4770      	bx	lr
   6:	bf00      	nop

00000008 <_mainCRTStartup>:
   8:	4b17      	ldr	r3, [pc, #92]	; (68 <_mainCRTStartup+0x60>)
   a:	2b00      	cmp	r3, #0
   c:	bf08      	it	eq
   e:	4b13      	ldreq	r3, [pc, #76]	; (5c <_mainCRTStartup+0x54>)
  10:	469d      	mov	sp, r3
  12:	f7ff fffe 	bl	0 <_stack_init>
  16:	2100      	movs	r1, #0
  18:	468b      	mov	fp, r1
  1a:	460f      	mov	r7, r1
  1c:	4813      	ldr	r0, [pc, #76]	; (6c <_mainCRTStartup+0x64>)
  1e:	4a14      	ldr	r2, [pc, #80]	; (70 <_mainCRTStartup+0x68>)
  20:	1a12      	subs	r2, r2, r0
  22:	f7ff fffe 	bl	0 <memset>
  26:	4b0e      	ldr	r3, [pc, #56]	; (60 <_mainCRTStartup+0x58>)
  28:	2b00      	cmp	r3, #0
  2a:	d000      	beq.n	2e <_mainCRTStartup+0x26>
  2c:	4798      	blx	r3
  2e:	4b0d      	ldr	r3, [pc, #52]	; (64 <_mainCRTStartup+0x5c>)
  30:	2b00      	cmp	r3, #0
  32:	d000      	beq.n	36 <_mainCRTStartup+0x2e>
  34:	4798      	blx	r3
  36:	2000      	movs	r0, #0
  38:	2100      	movs	r1, #0
  3a:	0004      	movs	r4, r0
  3c:	000d      	movs	r5, r1
  3e:	480d      	ldr	r0, [pc, #52]	; (74 <_mainCRTStartup+0x6c>)
  40:	2800      	cmp	r0, #0
  42:	d002      	beq.n	4a <_mainCRTStartup+0x42>
  44:	480c      	ldr	r0, [pc, #48]	; (78 <_mainCRTStartup+0x70>)
  46:	f7ff fffe 	bl	0 <atexit>
  4a:	f7ff fffe 	bl	0 <__libc_init_array>
  4e:	0020      	movs	r0, r4
  50:	0029      	movs	r1, r5
  52:	f7ff fffe 	bl	0 <main>
  56:	f7ff fffe 	bl	0 <exit>
  5a:	bf00      	nop
  5c:	00080000 	.word	0x00080000

I am not used to assembly but I see _mainCRTStartup consists in eventually call main function (line 52). So OK, I understand the link between _start() in the startup file, and main function call

Regarding rt_entry(), I also found this page : Documentation – Arm Developer
From what I understand, it performs the same tasks as crt0 file. I am a little bit confused here.
Thank you for your help


How do you know it is the crt0.o found in v7e-m+fp/softfp/ ?

You can find all exported (and used) symbols in the map file.

And the map file shows location of the crt0.o file in this case.


This is equivalent to:


From what I understand, it performs the same tasks as crt0 file. I am a little bit confused here.

Both _start and rt_entry are runtime startup function in library, but different toolchain.

_start : gcc (gcc_arm toolchain)

rt_entry : armclang (arm toolchain)

If you are using MbedStudio or Keil Studio Cloud, you are using arm toolchain. If you are using command line tools (mbed or mbed-tools), you are probably using gcc_arm.

I am using Mbed Studio. I found that mbed override __rt_entry function in mbed_boot_arm_std.c.
By looking at the map file found under mbed-os-example-blinky/BUILD/NUCLEO_F411RE/ARMC6/, I don’t see any crt0.o. BUT, I found this:

Loading member /.config/Mbed Studio/mbed-studio-tools/ac6/bin/../lib/armlib/c_w.l(__main.o) from /home/bbousquet/.config/Mbed Studio/mbed-studio-tools/ac6/bin/../lib/armlib/c_w.l.
              definition:  __main
              reference :  __rt_entry
              weak ref  :  __scatterload

I also found I was looking to the wrong startup code, the one for gcc_arm toolchain. The one for arm toolchain ( /mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F411xE/TOOLCHAIN_ARM ) show these lines (around line 150):

                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0

Does it means it calls __main, whose reference is __rt_entry, so __rt_entry is eventually executed?
Thank you for your answer, it really helps me to understand :slight_smile:


Does it means it calls __main, whose reference is __rt_entry, so __rt_entry is eventually executed?

Yes. This is described in the Arm® Compiler for Embedded Arm® C and C++ Libraries and Floating-Point Support User Guide in developer site:


You can find the method how to call user-defined __rt_entry rather than default __rt_entry in runtime library.

2.10.1 Initialization of the execution environment and execution of the application

You can customize execution initialization by defining your own __main that branches to __rt_entry.

So, your own (defined in Mbed OS target startup) __main is able to call __rt_entry in mbed_boot_arm_std.c, because the __rt_entry in the runtime library is defined as weak function. i.e. linker tool resolve the __rt_entry symbol in user-defined (= mbed_boot_arm_std.c) function rather than weak __rt_entry in library (= c_w.l file you mentioned).

In the __rt_entry function, it calls mbed_rtos_start() in the end and the “main” symbol will be entry of new thread (see: cmsis/device/rtos/source/mbed_rtos_rtx.c). And finally, main function in your application will be called.

Happy hacking!

Got it! Thank you very much!