Search code examples
gcclinkerlinker-errorsldlinker-scripts

Can you add two SECTION sections to ld script


I have an executable made by linking several .o files, using a somewhat involved linker script. If a particular environment flag is set, I'd like there to be another section involved. So, something like:

/* withfoo.ld */
SECTIONS {
 .foo 0x80000000 : {
    _start_foo = .;
    . += 0xfff;
    _end_foo = .;
 }
}

and then compile with:

if [ $FOO_DEFINED ]; then
    gcc -Wl,-T normal.ld $(OBJS) foo.o foo.ld
else
    gcc -Wl,-T normal.ld $(OBJS)
fi

where I'd like to not to have to modify normal.ld. normal.ld has a SECTIONS definition within it. So that gives me two SECTIONS... I'm getting the warning:

/usr/bin/ld: warning: foo.ld contains output sections; did you forget -T?

Is there an actual problem or is this just a warning? Also is there a proper way to do this that I'm not aware of?


Solution

  • GNU linker scripts and LD do not support conditional compile. You can't use two linker scripts at once and have it work as expected. You have to pre-process the linker script with some other type of macro language like m4 or even just use the GNU C Preprocessor cpp.


    Not sure if this is a type of solution you are looking for. The C preprocessor cpp can process the text of any kind of file (even non-C files) and will blindly parse for pre-processor directives and macros just like a C file. You can also pass C style defines through the cpp command line just like you can with GCC. You create a linker script with all the C pre-processor directives and generate specific linker scripts based on that. For example create a special linker script like this:

    linker.ld.pp :

    SECTIONS {
    #ifdef FOO
     .foo 0x80000000 : {
        _start_foo = .;
        . += 0xfff;
        _end_foo = .;
     }
    #endif
    }
    

    This uses typical C style #if/#ifdef/#endif for conditional compilation. If you run it through the C pre-processor with a command like:

    cpp -P -DFOO linker.ld.pp
    

    You'd get output like this:

    SECTIONS {
     .foo 0x80000000 : {
        _start_foo = .;
        . += 0xfff;
        _end_foo = .;
     }
    }
    

    Not defining FOO would be done like this:

    cpp -P linker.ld.pp
    

    The output would be:

    SECTIONS {
    }
    

    To redirect the pre-processor you can output to a linker script with:

    cpp -P -DFOO linker.ld.pp >withfoo.ld
    cpp -P linker.ld.pp >withoutfoo.ld
    

    You can specify multiple -D directives on the CPP command line to define multiple pre-processor symbols if you wish. The idea of this method is that you have a single linker script but you create a shell script to generate the necessary specialized scripts that are required.


    Other Observations

    Usually you specify linker scripts on the GCC command line with the -T option:

    gcc -T withfoo.ld $(OBJS) foo.o