joop
joop

Reputation: 53

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
}

Upvotes: 5

Views: 13119

Answers (3)

Bin S
Bin S

Reputation: 577

I think you can try "DEFINED(symbol)" according to https://sourceware.org/binutils/docs/ld/Builtin-Functions.html

Also, please don't forget to pass "--defsym=bootloaderSymbol=1" to ld.

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

Upvotes: 7

mfro
mfro

Reputation: 3335

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.

Upvotes: 5

escrafford
escrafford

Reputation: 2403

I've gone down this same path before, and later found out there's an ld command line argument to specify segment origin, which alleviates the need to figure it out in the linker script. From man page:

   -Tbss=org
   -Tdata=org
   -Ttext=org
       Same as --section-start, with ".bss", ".data" or ".text" as the section name.

So in your case, you would have -Ttext=0 (bootloader) or -Ttext=0x00004000 (app)

Upvotes: 1

Related Questions