Search code examples
ldcortex-mlinker-scripts

conditional statements for linker command language LD


Are there conditional statements for the GNU LD linker command language?

Context: I am developing firmware for an arm cortex m0+, which consists of a bootloader and an application. Both are compiled and flashed to target in separate projects, but I use a framework with symbolic links to the drivers, makefile and loader scripts so that I can reuse those for every app I make without copying these files for each app. Currently I have two loader files, for bootloader and application (makefile automatically specifies the appropriate one), with memory assigment as follows:

bootloader

MEMORY { 
  flash (rx)  : ORIGIN = 0x00000000, LENGTH = 16K
  ram   (rwx) : ORIGIN = 0x1FFFF000, LENGTH =  16K
}

app

MEMORY { 
  flash (rx)  : ORIGIN = 0x00004000, LENGTH = 112K
  ram   (rwx) : ORIGIN = 0x1FFFF000, LENGTH =  16K
}

Like the makefile, I want to merge these to something like this (using C expressions to clarify)

MEMORY { 
#ifdef(bootloaderSymbol)
  flash (rx)  : ORIGIN = 0x00000000, LENGTH = 16K
#else
  flash (rx)  : ORIGIN = 0x00004000, LENGTH = 112K
#endif
  ram   (rwx) : ORIGIN = 0x1FFFF000, LENGTH =  16K
}

Solution

  • Although its not its primary purpose, you can always run the C preprocessor (cpp) on your linker scripts:

    #if defined(MACHINE1)
    #    define TARGET_ADDRESS 0x80000000
    #    define SDRAM_START xxx
    #    define SDRAM_SIZE yyy
    #    define ROMFLAGS   rx
    #elif defined(MACHINE2)
    #    define TARGET_ADDRESS 0x40000000
    #    define SDRAM_START zzz
    #    define SDRAM_SIZE  aaa
    #    define ROMFLAGS rwx
    #else
    #    error unknown machine
    #endif
    
    MEMORY
    {
       rom (ROMFLAGS) : ORIGIN = TARGET_ADDRESS, LENGTH = 0x00100000
       ram (WX) : ORIGIN = SDRAM_START + SDRAM_SIZE - 0x00200000, LENGTH = 0x00100000
       driver_ram (WX) : ORIGIN = SDRAM_START + SDRAM_SIZE - 0x00100000, LENGTH = 0x00100000
    }
    
    ...
    

    You just need to make sure your macros don't collide with linker script syntax. Then save your linker script as xxx.lk.in (instead of xxx.lk) and add a recipe to your Makefile:

    xxx.lk: xxx.lk.in
            $(CPP) -P $(INCLUDE) -D$(MACHINE) $< $@
    

    All that's left to do is to add xxx.lk as dependency to your final executables build recipe. I'm using similar processes on many of my projects successfully.