|
|||||||||||
Technical Support Support Resources
Product Information |
ARMCLANG: Using armclang without the ARM C libraryInformation in this knowledgebase article applies to:
QUESTIONSome safety qualifications require access to the entire source code of a project, including the programming language library. DO-178 Level A has this requirement. May I have access to the ARM C language library to qualify? ANSWERThe ARM C/C++ library is proprietary. Contact an ARM sales team, for a quote, if you want access to the source code. The ARM C library may be offered as a standalone product, under certain circumstances. armclang already has several safety certifications. As of this writing (April 2018), the armclang v6.6 LTM maintenance was qualified for the certifications. MDK-Professional edition comes with a qualification kit, that aids in the approval process. Without the C library source code, a user can only see the header files. Interestingly, armclang can be used without the ARM C library, by substituting the C library dependencies with code from another C language library. A basic procedure and discussion for C library startup is discussed below. Advantages
Disadvantages
PROCEDUREA crucial library initialization step is to initialize any RW data to their starting values. armlink stores the initial values for RW data, after the normal readonly code and data, usually in internal flash. Then the values are loaded into RAM, during program execution, using a C library function called __main. This function is documented in ARM Compiler C Library Startup and Initialization Application Note 241. Many applications will reference __main in startup assembly, like the following: ;/*********************************************************************** ; * $Id: startup_LPC18xx.s 6471 2011-02-16 17:13:35Z nxp27266 $ ; * ; * Project: LPC18xx CMSIS Package ; * ; * Description: Cortex-M3 Core Device Startup File for the NXP LPC18xx ; * Device Series. ; * ; * Copyright(C) 2011, NXP Semiconductor ; * All rights reserved. ; * ; * modified by KEIL ; *********************************************************************** ;... Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP Add a new file to the project. We will add a new, simplified definition for __main(). Paste in the following code: #include <stdint.h> #include "cmsis_armclang.h" typedef uint32_t size_t; void memcpy( void * dest, void * source, volatile size_t numBytes) ; void memcpy( void * dest, void * source, volatile size_t numBytes) { volatile size_t r; volatile char *csrc = source; volatile char *cdest = dest; for( r = 0; r < numBytes; r++ ) { cdest[r] = csrc[r]; } } extern uint32_t Image$$RW_IRAM1$$Base; extern uint32_t Image$$RW_IRAM1$$Length; extern uint32_t Image$$ER_IROM1$$Base; extern uint32_t Image$$ER_IROM1$$Limit; extern uint32_t Image$$ER_IROM1$$Length; extern uint32_t Load$$LR$$LR_IROM1$$Length; void __main(void) __attribute((noinline)); void __main(void) __attribute((noinline)){ //*Size calculation for copy (i.e. length of RW-init data //that was added onto the end of flash image) //Initial values for RW-data must be stored as read-only //to allow device to startup correctly after a reset volatile size_t length = ((uint32_t)&Load$$LR$$LR_IROM1$$Length) - ((uint32_t)(&Image$$ER_IROM1$$Length)); if( length > ((uint32_t)&Image$$RW_IRAM1$$Length) ) #error "Multiple regions of RAM are used. \ This exampe is a blind copy, designed to initialize a *single* RAM region. \ Modify this function if you are using multiple RAM regions." memcpy( &Image$$RW_IRAM1$$Base, &Image$$ER_IROM1$$Limit , length); //* Start of RAM //* End of normal RO // (i.e. beginning of RW-init data ROM) //Some code to replace part of the __rt_entry function, //to initialize stack pointer, and jump to main() //Some applications may need to update SCB->VTOR __set_MSP( ((uint32_t *) &Image$$ER_IROM1$$Base)[0] ); //Go to the more familiar main()... __asm ( "LDR R0, =main;" "BX R0"); } Note that depending on different applications, when compiling calls to memcpy(), Arm C compiler might generate calls to specialized, optimized, library functions __aeabi* instead. When you get the following linker error, L6218E: Undefined symbol __aeabi_memcpy4 you need to also provide your own implementations of these __aeabi* functions. The above code will use one CMSIS function, __set_MSP(). You have access to the source code of __set_MSP(). It will also steal a header file from the ARM C library, "stdint.h". The example tries to use linker symbols as much as possible, to automate the source address and calculation of the length of the copy. As your code base grows in size, the starting address for the copy will also increase, because the RW data is always added at the end. So the symbols save you from an extra build. However, be careful of optimization levels with this memcpy(). The volatile keyword and the noinline attribute are used, to handle this for most optimization levels. Add the following to armclang command line, using the Misc. Controls field: -nostdlib -nostdlibinc -fno-builtin -fno-inline-functions //The first three options are required //Optional. If you want to //guarantee that the above //implementation of memcpy() //will behave correctly at the //highest performance optimization //levels (-Ofast), add //"-fno-inline-functions" or use //another implementation of //memcpy() Add the following to armlink command line, using the Misc. Controls field: --no_scanlib --datacompressor=off --entry=Reset_Handler --verbose //The first three options are required //Optional Go to Options for Target => Target tab, and check if the Microlib option is enabled. If enabled, disable the option. This is a special version of the ARM C library, so we don't have access to it, anymore. In your startup file, there may be a line, like the following: IMPORT __use_two_region_memory EXPORT __user_initial_stackheap __user_initial_stackheap ; ==>> ; Comment out the following line of code ;IMPORT __use_two_region_memory EXPORT __user_initial_stackheap __user_initial_stackheap This symbol is also specific to the ARM C library (the two region memory model). Now, we want to check that it works. Go to the source file, where main() is defined: //... static int i = 1; //... int main(void) { i++; //... If you place breakpoints at the line where main() and __main() are defined, and place variable "&i" in a memory window, you should be able to see the value change from 0 to 1, during the memcpy(), and see the value update from 1 to 2, after program execution enters main(). MORE INFORMATIONSEE ALSOLast Reviewed: Thursday, January 14, 2021 | ||||||||||
|
Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.