AnsweredAssumed Answered

Freemarker Linker Script Templates

Question asked by LPCware Support on Mar 31, 2016

Freemarker Linker Script Templates


By default, LPCXpresso IDE projects use a managed linker script mechanism which automatically generates a linker script file without user intervention - allowing the project code and data to be laid out in memory based on the IDE's knowledge of the memory layout of the target MCU.


However sometimes the linker script generated in this way may not provide exactly the memory layout required. LPCXpresso IDE V7.8.0 and earlier provide a linker script template mechanism that allowed the user to tweak the generated linker script by using a file called link_template.ld placed into the linkscripts sub-directory of the project.


In LPCXpresso IDE V7.9.0 and later, the linker script template mechanism has been overhauled to provide a much more flexible and powerful means for the user to change the content of the linker script generated by the managed linker script mechanism. This FAQ details this new functionality.




Starting with LPCXpresso IDE V7.9.0, the new scheme uses templates that are processed by the Freemarker template engine to create the linker script. FreeMarker is a template engine: a generic tool to generate text output (HTML web pages, e-mails, configuration files, source code, etc.) based on templates and changing data. Templates are written in the FreeMarker Template Language (FTL). It's a simple, specialized language, not a full-blown programming language like PHP. Full documentation for Freemarker can be found at


LPCXpresso IDE automatically invokes Freemarker, passing it a data model that describes the memory layout of the target together with a 'root' template that is processed to create the linker script. This root template, #include's further 'component' templates. This structure allows a linker script to be broken down into various components, and allows a user to provide their own templates for a component, instead of having to (re-)write the whole template. For example, component templates are provided for text, data and bss sections, allowing the user to provide a different implementations as necessary, but leaving the other parts of the linker script untouched.


Freemarker flow.preview.png

Migrating Linker Script Templates


For a short 'migration' period, both the old-style and Freemarker linker script templates are provided. The default behaviour is to create linker scripts using the new Freemarker templates AND the original linker scripts, compare them and report any differences. If no local modifications are made to linker scripts, there will be no differences reported. This migration support will only be available for a short time until the old-style linker script template support is removed completely.


Convert to Freemarker template


To simplify the conversion of old-style linker script template, an LPCXpresso IDE menu option is provided to convert an old-style link_template.ld into Freemarker link_template.ldt. The converter is designed to be a quick way for users to convert existing templates. It is not guaranteed that this will be 100% accurate, but will work in the vast majority of cases.


To run this converter, select the link_template.ld file in the project linkscript directory, right-click and select Tools -> Convert to Freemarker template. The file will be converted and saved as linkscript.ldt.


Disabling the comparison


By default, the Freemarker generated linker script is compared with the linker script generated with the old-style generator. This can be used to highlight differences between the scripts and allow for the user to correct any problems. The comparison can be disabled by unchecking the preference:

LPCXpresso -> Default Tool settings -> compare old and new linker scripts

or by using the following setting in a template

<#global skipCompare=true> 


Restoring LPCXpresso IDE V7.8.0 and earlier behavior


The original 7.8.0 and earlier behaviour can be restored by clearing (un-checking) the preference:

LPCXpresso -> Default Tool settings -> Use Freemarker linker script templates

As old-style linker script templates are now deprecated and will be removed from a future LPCXpresso release, it is strongly recommended that any local linker script templates are converted to use Freemarker templates as soon as possible.


Headless (Command line) Builds


The default behaviour of Headless builds is to mirror the behaviour of the GUI. As it may not be simple to set appropriate workspace preferences in the Headless environment, there are two ENVIRONMENT variables that may be used to control the behaviour:



  • set this (to ANY value) to disable the use of Freemarker template. This is equivalent to the unchecking the Use Freemarker linker script template preference, described above.



  • set this (to ANY value) to disable reporting an error when old-style templates exist in the project. A comparison between old and Freemarker generated linker scripts will still be performed and differences will be reported in the Headless Build Log.




Found old-style linker script templates, but using Freemarker linker script templates.

This error is caused by have an old-style linker script template (a file with an "ld" file extension) in the project linkscripts directory. The consequences are that the generated linker script  will not include any changes made by the old-style linker script template. To fix this issue, either

  • convert the linker script template to a Freemarker template (preferred)
  • switch off the Freemarker linker script templates. See 'Restoring LPCXpresso IDE V7.8.0 and earlier behaviour' (above).

This error is not reported if a Freemarker linker template (file with an "ldt" file extension) is found in the linkscripts directory.


User aborted linker script generation

This error will be reported in the Build log when Cancel is pressed on the "Found old-style..." error dialog.


Differences in linker scripts

When comparing Freemarker and old-style generated linker scripts, differences are reported in a dialog. Typically these errors will be reported if an old-style template is used. The differences are listed in the dialog, prefixed with <<< or >>> and the line number. Pressing OK to close the dialog accepts the difference and the build will continue. Pressing Cancel will cause an error to be reported in the Build log.


Comparison of Freemarker and old-style linker scripts failed

The error will be reported in the Build log when Cancel is pressed in the Differences dialog.




Some example Freemarker linker script templates can be found in the FAQ




Freemarker reads input files, copying text and processing Freemarker directives and 'variables', and writes an output file. As used by the LPCXpresso Managed Linker Script, the input files describe the various components of a linker script which, together with variables defined by the IDE, are used to generate a complete linker script. Any of the component template input files may be overriden by providing a local version in the project.


The component template input files are provided as a hierarchy, shown below, where each file #include's those files nested below. This allows for individual components of the linker script to be overridden without having to supply the entire linker script, increasing flexibility, while maintaining the benefits of Managed Linker Scripts.


Linker script template hierarchy


linkscript.ldt (top level)

  • user.ldt (an empty file designed to be overridden by users that is included in linkscript, memory and library templates)
  • user_linkscript.ldt (an empty file designed to be overridden by users that is included in linkscript only)
  • linkscript_lpc3xxx.ldt (specific to LPC3xxx targets)
  • linkscript_lpc29xx.ldt (specific to LPC29xx targets)
  • linkscript_common.ldt (used for all other targets)
    • header.ldt (the header for scripts)
      • listvars.ldt (a script to output a list of all predefined variables available to the template)
    • includes.ldt (includes the memory and library scripts)
    • section_top.ldt (top of the linker script SECTION directive)
    • text_section.ldt (text sections for each secondary flash)
      • text_section_multicore.ldt (text sections for multicore targets)
      • text.ldt (for inserting *text)
      • rodata.ldt (for inserting rodata)
    • main_text_section.ldt (the primary text section)
      • global_section_table.ldt (the global section table)
      • crp.ldt (the CRP information)
      • main_text.ldt (for inserting *text)
      • main_rodata.ldt (read-only data)
      • cpp_info.ldt (additional C++ requirements)
    • exdata.ldt (the exdata sections)
    • end_text.ldt (end of text marker)
    • data_section.ldt (data sections for secondary ram)
      • data_section_multicore.ldt (data sections for multicore targets)
      • data.ldt (for inserting *data)
    • mtb_default_section.ldt (special section for MTB (cortex-m0+ targets)
    • uninit_reserved_section.ldt (uninitialised data)
    • main_data_section.ldt primary data section)
      • main_data.ldt (for inserting *data)
    • bss_section.ldt (secondary bss sections)
      • bss.ldt (for inserting *bss)
    • main_bss_section.ldt primary bss section)
      • main_bss.ldt (for inserting *bss)
    • noinit_section.ldt (no-init data)
    • noinit_noload_section.ldt (no-load data)
    • stack_heap.ldt (define the stack and heap)
    • checksum.ldt (create the LPC checksum)
    • section_tail.ldt (immediately before the send of linker SECTION directive)


library.ldt (the standard libraries used in the application)

  • user.ldt (an empty file designed to be overridden by users that is included in linkscript, memory and library templates)
  • user_library.ldt (an empty file designed to be overridden by users that is included in library only)

memory.ldt (the memory map)

  • user.ldt (an empty file designed to be overridden by users that is included in linkscript, memory and library templates)
  • user_memory.ldt (an empty file designed to be overridden by users that is included in memory only)


Linker script search paths


Whenever a linker script template is used, LPCXpresso will search in the following locations, in the order shown

  1. <project>/linkscripts
  2. the searchPath global variable
    • The searchPath can be set in a script by using the syntax <#global searchPath="c:/windows/path;d:/another/windows/path">
    • each directory to search is seperated by a semi-colon ';'
  3. <lpcxpresso_install_dir>/lpcxpresso/Data/Linkscripts
    • linker templates can be placed in this directory to override the default templates for an entire installation
  4. lpcxpresso internally provided templates (not directly visible to users)


Thus, a project can simply override any template by simply creating a linkscript directory within the project and placing the appropriate template in there.Using the special syntax "super@" an overridden template can reference a file from the next level of the search path


e.g. <#include "super@user.ldt">


Linker script templates


Copies of the default linker script templates used within LPCXpresso IDE can be found in the Wizards/linker directory within the LPCXpresso IDE install.


Predefined variables (macros)


LPCXpresso IDE defines the following variables for use in the templates. All variable are case sensitive, so must be used exactly as listed below.

List (sequence) variables (used in <#list>)

  • libraries[]
    • list of the libraries to be included in the "lib" script
    • for example (Redlib nohost)
      •   libraries[0]=libcr_c.a
      •   libraries[1]=libcr_eabihelpers.a
  • configMemory[]
    • list of each memory region defined in the memory map for the project. Each entry has the following fields defined
      • name - the name of the memory region
      • alias - the alias of the memory region
      • location - the base address of the memory
      • size - the size of the memory region
      • sizek - the printable size of the memory region in k or M
      • mcuPattern
      • defaultRAM - boolean indicating if this is the default RAM region
      • defaultFlash - boolean indication if this is the default Flash region
      • RAM - boolean indicating if this is RAM
      • flash - boolean indicating if this is Flash
    • for example
      • configMemory[0]= name=MFlashA512 alias=Flash location=0x1a000000 size=0x80000 sizek=512K bytes mcuPattern=Flash flash=true RAM=false defaultFlash=true defaultRAM=false
      • configMemory[2]= name=RamLoc32 alias=RAM location=0x10000000 size=0x8000 sizek=32K bytes mcuPattern=RAM flash=false RAM=true defaultFlash=false defaultRAM=true
  • slaves[]
    • list of the slaves in a Multicore project. This variable is only defined in Multicore projects. Each entry has the following fields defined
      • name - name of the slave
      • enabled - boolean indicating if this slave is enabled
      • objPath - path to the object file for the slave image
      • linkSection - name of the section this slave is to be linked in
      • runtimeSection
      • textSection - name of the text section
      • textSectionNormalized - normalized name of the text section
      • dataStartSymbol - name of the Symbol defining the start of the data
      • dataEndSymbol - name of the Symbol defining the end of the data
    • for example
      • slaves[0] = name=M0APP objectPath=${workspace_loc:/MCB4357_Blinky_DualM0/Debug/MCB4357_Blinky_DualM0.axf.o} linkSection=Flash2 runtimeSection= textSection=.core_m0app textSectionNormalized=_core_m0app dataStartSymbol=__start_data dataEndSymbol=__end_data enabled=true;

Simple variables

  • CODE - name of the memory region to place the default code (text) section
  • CRP_ADDRESS - location of the Code Read Protect value
  • DATA - name of the memory region to place the default data section
  • LINK_TO_RAM - value of the "Link to RAM" linker option
  • STACK_OFFSET - value of the Stack Offset linker option
  • FLASHn - defined for each FLASH memory
  • RAMn - defined for each RAM memory
  • basename - internal name of the process
  • bss_align - alignment for .bss sections
  • buildConfig - the name of the configuration being built
  • chipFamily - the chip family
  • chipName - name of the target chip
  • data_align - alignment for .data section
  • date - date string
  • heap_symbol - name of the symbol used to define the heap
  • isCppProject - boolean indicating if this is a C++ project
  • isSlave - boolean indicating if this target is a slave - true iff is a slave core in a multicore system
  • library_include - name of the library include file
  • libtype - C library type
  • memory_include - name of the memory include file
  • mtb_supported - boolean indicating if mtb is supported for this target
  • numCores - number of cores in this target
  • procName - the name of the target processor
  • project - the name of the project
  • script - name of the script file
  • slaveName - is the name of the slave (only present for slaves)
  • stack_section - the name of the section where the stack is to be placed
  • start_symbol - the name of the start symbol (entry point)
  • scriptType - the type of script being generated (one of "script", "memory", or "library")
  • text_align - alignment for .text section
  • version - product version string
  • workspace_loc - workspace directory
  • year - the year (extracted from the date)


Extended variables

Two 'extended' variables are available:



The environment variable makes the host Operating System environment variables available. For example, the Path variable is available as ${environment["Path"]}. Note that environment variables are case sensitive.


The Java system properties are available through the systemProperties variable. For example the "" system property is available as ${systemProperties[""]}. Note that the system properties are case sensitive.


Outputting variables


A list of all predefined variables and their values can be output to the generated linker script by setting the Preference:

LPCXpresso -> Default Tool settings -> list predefined variables in the script

A list of extended variables and their values can be output to the generated linker script by creating a linkscripts/user.ldt file in the project with the content

<#assign listvarsext=true>

(This is likely to be used less often, hence the slightly longer winded method of specifying the option)


For more information:


Using your own linker scripts