{"id":75,"date":"2025-08-31T05:11:40","date_gmt":"2025-08-31T05:11:40","guid":{"rendered":"https:\/\/xtronix.in\/?p=75"},"modified":"2025-08-31T05:11:40","modified_gmt":"2025-08-31T05:11:40","slug":"start-up-and-linker-comparison","status":"publish","type":"post","link":"https:\/\/xtronix.in\/?p=75","title":{"rendered":"Start-up and linker Comparison"},"content":{"rendered":"\n<p>Comparing the startup and linker files across these architectures reveals a lot about their core design philosophies, from the simple, linear memory models of older architectures to the complex, vendor-specific ecosystems of modern ones.<\/p>\n\n\n\n<p>Here is a detailed comparison, breaking down the purpose, key components, and architectural implications for each family.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Executive Summary<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Microcontroller<\/th><th>Startup File Purpose<\/th><th>Linker File Purpose<\/th><th>Key Characteristics &amp; Philosophy<\/th><\/tr><\/thead><tbody><tr><td><strong>8051<\/strong><\/td><td>Minimal. Copies initialized data from CODE to DATA memory.<\/td><td>Simple. Manages segments in overlapping physical memory.<\/td><td><strong>Classic Harvard.<\/strong>&nbsp;Complex memory banking. Manual segment placement is common.<\/td><\/tr><tr><td><strong>PIC (8-bit)<\/strong><\/td><td>Minimal. Clears RAM, copies initialized data. Often in assembly.<\/td><td>Defines memory regions and sections. Manages paging\/banking.<\/td><td><strong>Harvard Architecture.<\/strong>&nbsp;Banked memory. Simple and explicit, but can be cumbersome.<\/td><\/tr><tr><td><strong>AVR (8-bit)<\/strong><\/td><td>Initializes stack, copies .data, clears .bss, jumps to main().<\/td><td>Defines FLASH, RAM, EEPROM regions and places sections.<\/td><td><strong>Clean, Modern Harvard.<\/strong>&nbsp;Linear memory spaces. Very straightforward and predictable.<\/td><\/tr><tr><td><strong>MSP430<\/strong><\/td><td>Initializes stack, copies .data, clears .bss, calls constructors, jumps to main().<\/td><td>Defines FLASH and RAM regions. Manages low-power info and interrupt vectors.<\/td><td><strong>Von Neumann.<\/strong>&nbsp;Unified memory space. Simple and efficient 16-bit RISC design.<\/td><\/tr><tr><td><strong>ARM (Cortex-M)<\/strong><\/td><td><strong>Highly Complex.<\/strong>&nbsp;Sets up stacks, vectors, clocks, RAM, calls C++ constructors.<\/td><td><strong>Highly Complex.<\/strong>&nbsp;Manages multiple memory regions, defines entry point, heap\/stack.<\/td><td><strong>Core Agnostic.<\/strong>&nbsp;The core provides standard (CMSIS), vendors provide complex implementations for their specific chips.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Detailed Breakdown<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">1. 8051<\/h4>\n\n\n\n<p><strong>Architecture:<\/strong>&nbsp;Harvard, with separate address spaces for code and data. Memory is highly banked.<\/p>\n\n\n\n<ul>\n<li><strong>Startup File:<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;Primarily to copy initialized variables from program memory (CODE\/ROM) into the default data memory bank (DATA\/RAM). On power-up, RAM is uninitialized.<\/li>\n\n\n\n<li><strong>Key Actions:<\/strong>\n<ol start=\"1\">\n<li><strong>Initialize Stack:<\/strong>&nbsp;The stack is usually located in the IDATA (internal RAM) region.<\/li>\n\n\n\n<li><strong>Data Initialization:<\/strong>&nbsp;A loop that copies the initial values of variables from the&nbsp;<code>?C_INITSEG<\/code>&nbsp;(or similar) code segment to the&nbsp;<code>?DT?*<\/code>&nbsp;data segments.<\/li>\n\n\n\n<li><strong>Jump to main():<\/strong>&nbsp;Transfers control to the C program&#8217;s entry point.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><strong>Complexity:<\/strong>&nbsp;Low to Medium. The logic is simple, but understanding the banked memory model is crucial.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Linker File (.l51, .lx51):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;To manage the complex, overlapping memory spaces (CODE, XDATA, PDATA, DATA, IDATA, BIT) and assign segments to the correct physical addresses and banks.<\/li>\n\n\n\n<li><strong>Key Components:<\/strong>\n<ul>\n<li><code>MEMORY<\/code>: Defines the physical memory ranges (e.g.,&nbsp;<code>CODE(0x0000, 0x7FFF)<\/code>,&nbsp;<code>XDATA(0x0000, 0xFFFF)<\/code>).<\/li>\n\n\n\n<li><code>SECTIONS<\/code>: Tells the linker which programmer-defined segments (like&nbsp;<code>?PR?main?MAIN<\/code>&nbsp;for the code of&nbsp;<code>main()<\/code>&nbsp;in file&nbsp;<code>MAIN.C<\/code>) to place in which memory region.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Philosophy:<\/strong>&nbsp;<strong>Explicit and Manual.<\/strong>&nbsp;The developer often needs to be deeply aware of memory banking and manually place critical functions (<code>using n<\/code>) or variables in specific banks for efficiency.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">2. PIC (8-bit)<\/h4>\n\n\n\n<p><strong>Architecture:<\/strong>&nbsp;Harvard. Heavily banked memory (both RAM and ROM).<\/p>\n\n\n\n<ul>\n<li><strong>Startup File (crt0.s \/ startup.as):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;Performs very basic initialization before&nbsp;<code>main()<\/code>.<\/li>\n\n\n\n<li><strong>Key Actions:<\/strong>\n<ol start=\"1\">\n<li><strong>Initialize Stack:<\/strong>&nbsp;Sets up the hardware stack (which is often separate and limited in depth).<\/li>\n\n\n\n<li><strong>Clear RAM:<\/strong>&nbsp;Zeros out the general-purpose RAM.<\/li>\n\n\n\n<li><strong>Copy Data:<\/strong>&nbsp;Copies initialized variables from program memory to data memory.<\/li>\n\n\n\n<li><strong>Jump to main()<\/strong>.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><strong>Complexity:<\/strong>&nbsp;Low. Often written in assembly and provided by the compiler toolchain (MPLAB XC8).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Linker File (.lkr):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;To describe the memory layout of the&nbsp;<em>specific<\/em>&nbsp;target PIC microcontroller and assign code and data sections to the appropriate program and data memory banks.<\/li>\n\n\n\n<li><strong>Key Components:<\/strong>\n<ul>\n<li><code>CODEPAGE<\/code>: Defines blocks of program memory (ROM).<\/li>\n\n\n\n<li><code>DATABANK<\/code>: Defines blocks of data memory (RAM banks).<\/li>\n\n\n\n<li><code>SECTION<\/code>: Directs standard sections (e.g.,&nbsp;<code>.text<\/code>,&nbsp;<code>.data<\/code>) to the defined memory areas.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Philosophy:<\/strong>&nbsp;<strong>Bank-Centric.<\/strong>&nbsp;The linker script is crucial for managing bank switching. If a section spans multiple banks, the linker must generate the appropriate &#8220;bank selection&#8221; instructions.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">3. AVR (e.g., ATmega328P)<\/h4>\n\n\n\n<p><strong>Architecture:<\/strong>&nbsp;Modified Harvard. Has separate, linear address spaces for Flash (program) and RAM (data).<\/p>\n\n\n\n<ul>\n<li><strong>Startup File (crt0.o \/ gcrt0.o):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;A classic, clean example of a startup routine for an embedded system.<\/li>\n\n\n\n<li><strong>Key Actions:<\/strong>\n<ol start=\"1\">\n<li><strong>Initialize Stack Pointer:<\/strong>&nbsp;Sets the SP to the end of RAM.<\/li>\n\n\n\n<li><strong>Copy .data:<\/strong>&nbsp;Copies the initial values from Flash (.data section) to SRAM.<\/li>\n\n\n\n<li><strong>Clear .bss:<\/strong>&nbsp;Zeros out the uninitialized data section in SRAM.<\/li>\n\n\n\n<li><strong>Call main():<\/strong>&nbsp;Jumps to the user&#8217;s&nbsp;<code>main()<\/code>&nbsp;function.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><strong>Complexity:<\/strong>&nbsp;Low. Very straightforward and easy to understand.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Linker File (.ld):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;To define the memory layout (Flash, RAM, and EEPROM) and section placement for the target AVR chip.<\/li>\n\n\n\n<li><strong>Key Components:<\/strong>\n<ul>\n<li><code>MEMORY<\/code>: Declares the size and origin of Flash (rx), RAM (rwx), and EEPROM (r).<\/li>\n\n\n\n<li><code>SECTIONS<\/code>: Defines where to place&nbsp;<code>.text<\/code>,&nbsp;<code>.data<\/code>,&nbsp;<code>.bss<\/code>,&nbsp;<code>.noinit<\/code>, and&nbsp;<code>.eeprom<\/code>&nbsp;sections.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Philosophy:<\/strong>&nbsp;<strong>Transparent and Linear.<\/strong>&nbsp;The memory map is simple and linear, making linker scripts easy to write and modify. The avr-libc provides excellent default scripts.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">4. MSP430<\/h4>\n\n\n\n<p><strong>Architecture:<\/strong>&nbsp;Von Neumann. Has a unified address space for RAM and Flash.<\/p>\n\n\n\n<ul>\n<li><strong>Startup File (startup_&lt;device&gt;.c \/ .s):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;Similar to AVR but often includes more functionality, especially for low-power modes and C++.<\/li>\n\n\n\n<li><strong>Key Actions:<\/strong>\n<ol start=\"1\">\n<li><strong>Disable Watchdog:<\/strong>&nbsp;A critical first step on MSP430.<\/li>\n\n\n\n<li><strong>Set up Stack Pointer.<\/strong><\/li>\n\n\n\n<li><strong>Copy .data:<\/strong>&nbsp;From Flash to RAM.<\/li>\n\n\n\n<li><strong>Clear .bss.<\/strong><\/li>\n\n\n\n<li><strong>Call C++ Constructors:<\/strong>&nbsp;For global objects (if using C++).<\/li>\n\n\n\n<li><strong>Call main()<\/strong>.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><strong>Complexity:<\/strong>&nbsp;Low to Medium. TI&#8217;s Code Composer Studio provides well-commented startup files for each device family.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Linker File (.cmd):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;To define the unified memory map and assign sections to either Flash or RAM.<\/li>\n\n\n\n<li><strong>Key Components:<\/strong>\n<ul>\n<li><code>MEMORY<\/code>: Defines ranges (e.g.,&nbsp;<code>FLASH : origin = 0x8000, length = 0x7FFF<\/code>,&nbsp;<code>RAM : origin = 0x2000, length = 0x1000<\/code>).<\/li>\n\n\n\n<li><code>SECTIONS<\/code>: Assigns&nbsp;<code>.text<\/code>,&nbsp;<code>.data<\/code>,&nbsp;<code>.bss<\/code>,&nbsp;<code>.stack<\/code>, and, crucially, the&nbsp;<strong>INTERRUPT VECTOR TABLE<\/strong>&nbsp;to specific addresses.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Philosophy:<\/strong>&nbsp;<strong>Unified and Efficient.<\/strong>&nbsp;The unified memory space simplifies the linker script compared to banked Harvard architectures. The focus is on efficient placement of code and data between volatile (RAM) and non-volatile (Flash) memory.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">5. ARM (Cortex-M)<\/h4>\n\n\n\n<p><strong>Architecture:<\/strong>&nbsp;Von Neumann or Harvard (depending on specific core), but presented with a unified memory map.<\/p>\n\n\n\n<ul>\n<li><strong>Startup File (startup_&lt;device&gt;.s):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;<strong>Extremely complex and critical.<\/strong>&nbsp;It does far more than just initialize variables.<\/li>\n\n\n\n<li><strong>Key Actions:<\/strong>\n<ol start=\"1\">\n<li><strong>Initialize the Stack Pointer<\/strong>&nbsp;from the first entry in the vector table.<\/li>\n\n\n\n<li><strong>Initialize the Process Stack Pointer<\/strong>&nbsp;(on cores that support it).<\/li>\n\n\n\n<li><strong>Set the Vector Table Offset Register (VTOR)<\/strong>.<\/li>\n\n\n\n<li><strong>Copy .data from Flash to RAM.<\/strong><\/li>\n\n\n\n<li><strong>Zero out the .bss section.<\/strong><\/li>\n\n\n\n<li><strong>Configure System Clock and PLL.<\/strong>&nbsp;(Often done in&nbsp;<code>SystemInit()<\/code>&nbsp;called before&nbsp;<code>main<\/code>).<\/li>\n\n\n\n<li><strong>Call C++ Constructors<\/strong>&nbsp;(for global objects,&nbsp;<code>__libc_init_array<\/code>).<\/li>\n\n\n\n<li><strong>Call main()<\/strong>.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><strong>Complexity:<\/strong>&nbsp;<strong>High.<\/strong>&nbsp;This file is highly vendor-specific (ST, NXP, TI, etc.) and is often provided as part of a Device Family Pack (DFP) or Hardware Abstraction Layer (HAL). It&#8217;s tightly coupled with the system initialization code.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Linker File (.ld \/ .icf \/ .sct):<\/strong>\n<ul>\n<li><strong>Purpose:<\/strong>&nbsp;To define the complex memory map of a modern ARM SoC, which often includes multiple Flash banks (for dual-banking\/OTA updates), multiple RAM banks (core, DMA, TCM), and peripheral memory.<\/li>\n\n\n\n<li><strong>Key Components:<\/strong>\n<ul>\n<li><code>MEMORY<\/code>: Extensive definition of all memory regions (e.g.,&nbsp;<code>FLASH<\/code>,&nbsp;<code>RAM<\/code>,&nbsp;<code>CCMRAM<\/code>,&nbsp;<code>BACKUP_SRAM<\/code>).<\/li>\n\n\n\n<li><code>SECTIONS<\/code>: Detailed placement of:\n<ul>\n<li><code>.isr_vector<\/code>: The interrupt vector table (must be placed at correct base address).<\/li>\n\n\n\n<li><code>.text<\/code>: Code and constants.<\/li>\n\n\n\n<li><code>.data \/ .bss<\/code>: Initialized\/Uninitialized data.<\/li>\n\n\n\n<li><code>._user_heap_stack<\/code>: Defines the heap and stack areas.<\/li>\n\n\n\n<li>Special sections for other cores (e.g.,&nbsp;<code>.ARM.exidx<\/code>&nbsp;for exception unwinding).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Philosophy:<\/strong>&nbsp;<strong>Flexible and Powerful.<\/strong>&nbsp;ARM linker scripts are the most complex, offering fine-grained control over memory layout. They are essential for optimizing performance (placing critical code in fast TCM RAM) and enabling advanced features like bootloaders.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusion<\/h3>\n\n\n\n<p>The evolution from&nbsp;<strong>8051\/PIC<\/strong>&nbsp;to&nbsp;<strong>AVR\/MSP430<\/strong>&nbsp;to&nbsp;<strong>ARM<\/strong>&nbsp;shows a clear trend:<\/p>\n\n\n\n<ol start=\"1\">\n<li><strong>From Manual to Automatic:<\/strong>&nbsp;Moving away from manual memory banking to automated, linear(ish) memory models.<\/li>\n\n\n\n<li><strong>From Simple to Complex:<\/strong>&nbsp;As microcontrollers became more powerful, the startup and linker processes grew to handle complex silicon features like multiple memory types, system clocks, and C++ support.<\/li>\n\n\n\n<li><strong>From Vendor-Agnostic to Vendor-Specific:<\/strong>&nbsp;While the ARM&nbsp;<em>core<\/em>&nbsp;is standard, the implementation (startup and linker files) is entirely vendor-specific, abstracted away by powerful IDEs and configuration tools (STM32CubeMX, MCUXpresso). For 8051\/PIC\/AVR, the files are simpler but often require more manual intervention from the developer.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Comparing the startup and linker files across these architectures reveals a lot about their core design philosophies, from the simple, linear memory models of older architectures to the complex, vendor-specific ecosystems of modern ones. Here is a detailed comparison, breaking down the purpose, key components, and architectural implications for each family. Executive Summary Microcontroller Startup [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/xtronix.in\/index.php?rest_route=\/wp\/v2\/posts\/75"}],"collection":[{"href":"https:\/\/xtronix.in\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/xtronix.in\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/xtronix.in\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/xtronix.in\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=75"}],"version-history":[{"count":1,"href":"https:\/\/xtronix.in\/index.php?rest_route=\/wp\/v2\/posts\/75\/revisions"}],"predecessor-version":[{"id":76,"href":"https:\/\/xtronix.in\/index.php?rest_route=\/wp\/v2\/posts\/75\/revisions\/76"}],"wp:attachment":[{"href":"https:\/\/xtronix.in\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=75"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/xtronix.in\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=75"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/xtronix.in\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=75"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}