Utilizing same header file for linker script and C program, is it possible?

132 views Asked by At

For example I want to place a special data in 0x100000000, 0x100100000, 0x100200000, ... and for this I want to do in a header file,

#define DATA_START 0x100000000
#define DATA_GAP 0x100000
#define DATA0_START DATA_START + 0*DATA_GAP
#define DATA1_START DATA_START + 1*DATA_GAP
#define DATA2_START DATA_START + 2*DATA_GAP

Now I want to have a linker script and define sections there and want to do something like this. (so that the C program and linker script match).

. = DATA_START;
.mydata : {
  *(.data0)
   . = ALIGN(DATA_GAP);
  *(.data1)
   . = ALIGN(DATA_GAP);
...
}

of course with enough value for DATA_GAP so that data don't overlap.
But in linker script, the define statement is not "#define DATA_START 0x100000000" but "DATA_START = 0x100000000;". So if I want to use a single file to be used in C and linker script, how can I do it?? (I read somewhere that in programs there should be single point of truth, without having to fix data in multiple places..)
I know how to declare a variable in linker script and use it C program (using "var = ." in linker sciprt and using &var in C program..), but this time I want to statically allocate some data.

2

There are 2 answers

0
Chan Kim On BEST ANSWER

Marco Bonelli's answer can be a solution but I though this method is simpler.
In Makefile, I added this command in the recipe before the actual compilation.

sed -e 's/#define ([A-Z0-9_][A-Z0-9_]) (.)/\1 = \2;/' sections.h > linkadd.h

and the actual linker script now has this line at the start.

INCLUDE linkadd.h

So before the compilation, the C header file looks like

#define DATA_START 0x82000000
#define DATA_GAP 0x100000
#define ARGBUF0 DATA_START
#define ARGBUF1 DATA_START + DATA_GAP
#define ARGBUF2 DATA_START + 2*DATA_GAP

and the linker script looks like

INCLUDE linkadd.h

  . = DATA_START;
  .mydata : {
    _mydata_start = .;
        . = ARGBUF0;
        *(.data_args0)
        . = ARGBUF1;
        *(.data_args1)
        . = ARGBUF2;
        *(.data_args2)

I think this looks better.

1
Marco Bonelli On

Only working solution I can think of:

  1. Create a separate header file for those constants.
  2. Use #ifdef to split definitions for C programs and for the linker script.
  3. Include the header file in both your program (other .c files) and the linker script.
  4. Preprocess the linker script with the C preprocessor too. You will have to use a different name/extension for the original linker script (with the #include) and the final one.

The header file would look something like this:

#ifndef SECTIONS_H
#define SECTIONS_H

#define _DATA_START  0x100000000
#define _DATA_GAP    0x100000
#define _DATA0_START _DATA_START + 0*_DATA_GAP
#define _DATA1_START _DATA_START + 1*_DATA_GAP
#define _DATA2_START _DATA_START + 2*_DATA_GAP

#ifdef LINKER_SCRIPT

DATA_START  = _DATA_START
DATA_GAP    = _DATA_GAP
DATA0_START = _DATA0_START
DATA1_START = _DATA1_START
DATA2_START = _DATA2_START

#else // !LINKER_SCRIPT

#define DATA_START  _DATA_START
#define DATA_GAP    _DATA_GAP
#define DATA0_START _DATA0_START
#define DATA1_START _DATA1_START
#define DATA2_START _DATA2_START

#endif // LINKER_SCRIPT

#endif // SECTIONS_H

Then in your linker file you can do:

#include "sections.h"

. = DATA_START;
.mydata : {
  *(.data0)
   . = ALIGN(DATA_GAP);
  *(.data1)
   . = ALIGN(DATA_GAP);
...
}

And then you could do:

gcc -E -P -xc -DLINKER_SCRIPT script.ldX > script.ld
gcc -T script.ld -o program foo.o bar.o baz.o