In the previous lesson Source Files (.c/.h/.s), Pi Ziheng systematically introduced source files to everyone. Source files are typical input files in embedded projects. So are there other types of input files? Since Pi Ziheng asked this question, the answer must be yes. The linker file that Pi Ziheng is going to talk about today is another type of input file.
As the name implies, the linker file is a file used in the linking stage of embedded engineering. After the source file is compiled (it is already machine-readable binary machine code data), it needs to go through the linker to organize the binary data in an orderly manner to form the final binary executable file, which will eventually be downloaded into the non-volatile memory inside the chip. The linker file is used to instruct the linker how to organize the compiled binary data.
Linker files are closely related to IDE. This article takes IAR EWARM as an example to introduce linker files. The linker files under other IDEs can be applied by analogy.
1. Section in embedded system
Before talking about linker files, Pi Ziheng must first clarify a very important concept in embedded systems - section. So what is a section? The C or assembly source files we write are all kinds of application codes. These codes can be divided into many categories according to their functions, such as constants, variables, functions, stacks, etc., and a collection of the same type of code is a section. The basic unit for the linker to organize data during linking is a section. So how many types of sections are there in a typical embedded system? The following lists all the default sections in IAR. Those common sections will be mentioned in the subsequent introduction of linker files.
//Common Section
.bss // Holds zero-initialized static and global variables.
CSTACK // Holds the stack used by C or C++ programs.
.data // Holds static and global initialized variables.
.data_init // Holds initial values for .data sections when the linker directive initialize is used.
HEAP // Holds the heap used for dynamically allocated data.
.intvec // Holds the reset vector table
.noinit // Holds __no_init static and global variables.
.rodata // Holds constant data.
.text // Holds the program code.
.textrw // Holds __ramfunc declared program code.
.textrw_init // Holds initializers for the .textrw declared section.
//Less popular Section
.exc.text // Holds exception-related code.
__iar_tls.$$DATA // Holds initial values for TLS variables.
.iar.dynexit // Holds the atexit table.
.init_array // Holds a table of dynamic initialization functions.
IRQ_STACK // Holds the stack for interrupt requests, IRQ, and exceptions.
.preinit_array // Holds a table of dynamic initialization functions.
.prepreinit_array // Holds a table of dynamic initialization functions.
Veneer$$CMSE // Holds secure gateway veneers.
//More secluded Section
.debug // Contains debug information in the DWARF format
.iar.debug // Contains supplemental debug information in an IAR format
.comment // Contains the tools and command lines used for building the file
.rel or .rela // Contains ELF relocation information
.symtab // Contains the symbol table for a file
.strtab // Contains the names of the symbol in the symbol table
.shstrtab // Contains the names of the sections.
Note: For a detailed explanation of the above section, please refer to the Section reference section in the IAR SystemsEmbedded Workbench xxxarmdocEWARM_DevelopmentGuide.ENU.pdf document in the IAR software installation directory.
2. Parsing linker files
Now that you know the concept of section, you can start to understand the linker file in depth. What is a linker file? The linker file is written in the syntax specified by the IDE and is used to instruct the linker to allocate the storage location of each section in the embedded system memory. As we all know, the embedded system memory is mainly divided into two categories: ROM (non-volatile) and RAM (volatile), so these corresponding sections are also divided into two types of attributes according to the different storage locations: readonly and readwrite. In fact, the work of the linker file is to put the readonly section into ROM and the readwrite section into RAM.
So how do you write a linker file for a project? As mentioned earlier, linker files also have syntax, and this syntax is specified by the IDE, so you must first master the syntax rules set by the IDE. The linker file syntax rules are relatively simple, and the most commonly used keywords are the following 8:
// Verb keywords
define // Define various spatial ranges and lengths
initialize // Set the section initialization method
place in // Place the section in a region (the specific address is assigned by the linker)
place at // Place the section at an absolute address
// Noun keywords
symbol // Various spatial ranges and lengths
memory // The identifier of the entire ARM memory space
region // Identify the region space in the entire ARM memory space
block // Identifier of the collection block of multiple sections
Note: For a detailed explanation of the above linker syntax, please refer to the The linker configuration file section in the IAR SystemsEmbedded Workbench xxxarmdocEWARM_DevelopmentGuide.ENU.pdf document in the IAR software installation directory.
Now we can happily start writing linker files. Can't wait? Come on, it only takes three steps. Let's do it.
Here we assume that the MCU physical space is: ROM (0x0 - 0x1ffff), RAM (0x10000000 - 0x1000ffff), and the linker requirements that Pi Ziheng wants to write are as follows:
The interrupt vector table must be placed at the ROM start address 0x0 and must be 256-byte aligned
The size of STACK is 8KB, the size of HEAP is 1KB, and must be 8-byte aligned.
SATCK must be placed at the RAM start address 0x10000000
The remaining sections are placed in the correct region, and the specific space is automatically allocated by the linker
2.1 Defining physical space
In the first step, we define three non-overlapping spaces: ROM_region, RAM_region, and STACK_region. ROM_region corresponds to the real ROM space, and RAM_region and STACK_region are combined into the real RAM space.
// Define the physical space boundaries
define symbol __ICFEDIT_region_ROM_start__ = 0x00000000;
define symbol __ICFEDIT_region_ROM_end__ = __ICFEDIT_region_ROM_start__ + (128*1024 - 1);
define symbol __ICFEDIT_region_RAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_RAM_end__ = __ICFEDIT_region_RAM_start__ + (64*1024 - 1);
define symbol __ICFEDIT_intvec_start__ = __ICFEDIT_region_ROM_start__;
// Define the stack length
define symbol __ICFEDIT_size_cstack__ = (8*1024);
define symbol __ICFEDIT_size_heap__ = (1*1024);
// Define the specific spatial range of each region
define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region STACK_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_start__ + __ICFEDIT_size_cstack__ - 1];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ + __ICFEDIT_size_cstack__ to __ICFEDIT_region_RAM_end__];
2.2 Define section collection
The second step is to customize the section collection block. Careful friends can see that the curly braces on the right contain the system default sections introduced in the previous section. We will group sections with the same attributes into a block to facilitate the next step of placement.
// Define the stack block and its properties
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
// Define the section collection block
define block Vectors with alignment=256 { readonly section .intvec };
define block CodeRelocate { section .textrw_init };
define block CodeRelocateRam { section .textrw };
define block ApplicationFlash { readonly, block CodeRelocate };
define block ApplicationRam { readwrite, block CodeRelocateRam, block HEAP };
Some friends may wonder why we need to define the two blocks CodeRelocate and CodeRelocateRam? Logically, the sections corresponding to these two blocks can be put into ApplicationFlash and ApplicationRam respectively, so why do we need to do this? Friends who have carefully read the source file of the previous class of Pi Ziheng will definitely know the answer. In the startup.c file introduced in that class, there is a function called init_data_bss(). This function will complete the function of initializing the CodeRelocateRam block. It looks for the name of the CodeRelocate segment, which looks clearer and easier to understand than the system default name textrw.
2.3 Placement of section collection
The third step is to place those section assembly blocks. There is an initialize manually statement before placing the assembly block. Why are there these statements? It still has to be combined with the init_data_bss() function in the startup.c file mentioned earlier. This function is the initialization of the data and bss segments implemented by the developer himself, so here you need to notify the IDE that you don’t need to do the initialization work for me anymore.
// Set the initialization method
initialize manually { readwrite };
initialize manually { section .data};
initialize manually { section .textrw };
do not initialize { section .noinit };
// Place the section collection block
place at start of ROM_region { block Vectors };
//place at address mem:__ICFEDIT_intvec_start__ { block Vectors };
place in ROM_region { block ApplicationFlash };
place in RAM_region { block ApplicationRam };
place in STACK_region { block CSTACK };
Of course, if you want the IDE to automatically initialize the data, bss, and textrw segments for you, you can replace the initialize manually statement with the following statement.
initialize by copy { readwrite, section .textrw };
After setting the initialization method, it is time to place the section collection block. There are two main placement methods, place in and place at. The former is used to specify the space block placement (without specifying the specific address), and the latter is to specify the specific address placement.
Previous article:Boost download, installation, compilation, configuration and usage guide (including Windows, Linux and ARM Linux)
Next article:Pi Ziheng Embedded: ARM Cortex-M Core (5) - Instruction Set
Recommended ReadingLatest update time:2024-11-16 11:52
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Download Ultra-Wideband (UWB) For Dummies
- Easy-to-use embedded operating system interface library——LittlevGL
- Photoelectric direct reading valve controlled water meter solution
- TMS320F2838x microcontroller with connection manager
- 17 MG6 smart key replaced with Maserati original shell (with keyless entry, one-button start)
- LSM6DSR iNEMO inertial module related information
- Qorvo Receives Samsung Mobile Quality Award
- PCI Bus
- A Field Guide to the Internet of Things
- Comparison of these two circuit structures