Importing a symbol from C file into linker script

c++gccldlinker

I have created a section called .co_stack in my C file and have an array called pulStack to define the area.

#define STACK_SIZE       0x00003000      /*!< Stack size (in Words)           */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];

My gcc linker script defining the stack section looks like this

.co_stack : {
    _fstackptr = ORIGIN(ram) + LENGTH(ram) - 4;
    _fstacksize = 0x00003000 * 4;       
    . = (_fstackptr - _fstacksize);
    *(.co_stack .co_stack.*)
}

As you can see I end up defining the stack size in 2 places.
One as STACK_SIZE in my .c file and _fstacksize in my .ld file.

How can I define this in just one place?

For e.g.
I want to create a variable pulStackSize as follows.

const unsigned long pulStackSize = sizeof(pulStack);

I want to define _fstacksize in .ld file as

_fstacksize = STACK_SIZE * 4;

If I do this, I get an error saying stack overflowed by 48K bytes.

How can I import a symbol from .c to my .ld file ?

Best Solution

Some solutions (to the more general question "how to share values between C and LD script?"):

1) (NOTE: for this solution I'll assume that you are using a recent version of GNU ld, docs here : http://www.math.utah.edu/docs/info/ld_3.html)

You can associate an absolute value to a symbol inside the script by defining it outside the section compounds (e.g. at the very begin of the script). Than you can import the symbol in C by defining it as extern. Beware that the value you need in C is the ADDRESS of the symbol:

Script:

StackSize = 0x00003000 * 4; /* the size */
.co_stack : {  
    _fstackptr = ORIGIN(ram) + LENGTH(ram) - 4;
    _fstacksize = StackSize;       
    . = (_fstackptr - _fstacksize);
    *(.co_stack .co_stack.*)
}

C:

extern long StackSize;
#define STACK_SIZE (((size_t)&StackSize)/sizeof(long))

This solution may impose restrictions in the use of the value obtained, e.g. most compilers will not accept a line like this:

long my_stack[STACK_SIZE];

but you don't need it anymore, since you can define the symbol "my_stack" inside the script and import it as "extern long my_stack[];". I think that it's an acceptable limitation anyway.

2) Another way is to define in the script two symbols located at the start and at the and of the section and import them as "extern char" in C. The size of the section in bytes is the difference of their two addresses. This solution has the same limitation of (1)

3) If your linker is not smart enough, you can use the C preprocessor to produce a suitable script at compilation time by expanding the macro STACK_SIZE as in C. You have to

a) create the file "stacksize.h" containing

#define STACK_SIZE 0x3000

b) Add the line #include "stacksize.h" at the beginning of the script and use STACK_SIZE whenever you need. Save the script as "ldscript.c".

c) in your makefile (or equivalent compilation procedure) invoke the preprocessor. If you have GCC the command is:

gcc -P -E ldscript.c -o ldscript.ld

Please note that some gcc versions give a special meaning to the input file's extension. So I suggest to use ".c", it's the safest way.

d) Use the file "ldscript.ld" produced by the C preprocessor as link script

Related Question