Home > Back-end >  Is it possible to access a C variable from a linker script
Is it possible to access a C variable from a linker script

Time:09-25

Let's say for example I need to get the size of the process loaded into memory then I define this in my code:

#include <stdio.h>

ssize_t prog_sz;
int main()
{
     printf("%x\n", prog_sz);
}

then I have a linker script accessing it with a line like this proc_sz = .

NOTE: all linker scripts I test with my programs always produce errors which is why I specified only a line from the script. For example something as simple as this without that line I first talked about:

SECTIONS
{
    .text : { *(.text) }
    .data : { *(.data) }
    .bss : { *(.bss) }
}

produces annoying errors like these:

/usr/bin/ld: a.out: error: PHDR segment not covered by LOAD segment
/usr/bin/ld: /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS): in function `__libc_csu_init':
(.text 0x9): undefined reference to `__init_array_start'
/usr/bin/ld: (.text 0x20): undefined reference to `__init_array_end'
/usr/bin/ld: a.out: hidden symbol `__init_array_end' isn't defined
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status

even an example from the ld info documentation produces that annoying error. Maybe you can help me solve that issue too.

CodePudding user response:

It looks like you have two separate issues.

The first issue involves the symbol/variable prog_sz. The approach that you have shown will just cause the linker to try and create another symbol named prog_sz, which would not likely accomplish the goal.

Without further detail on exactly what is being done, I will present three objectives and their solution:

  1. Set the variable prog_sz to contain the address of a symbol defined in the linker file.

Define the symbol in your command file with a different name, such as prog_sz__. You can then add directly above the declaration of prog_sz in your code the line:

extern char prog_sz;

The type char does not really matter here. This statement is just necessary to tell the compiler that the symbol will be defined somewhere else. After this, you can assign the address of the symbol to prog_sz by modifying your definition to:

size_t prog_sz = (size_t)(&prog_sz__);

Using & tells the program to store the address associated with symbol prog_sz__ in variable prog_sz. This will assign the symbol defined in your linker script to your variable prog_sz.

  1. Position the variable at a fixed location using the linker script there is a way to do this.

Assuming that you are using the GNU toolchain, when you are building use the GCC option -fdata-sections. This will place each variable into its own data section. Be aware that your .bss and .data sections will be replaced with a section for each variable prefixed .data or .bss and you may need to use a wildcard * to capture the .bss and .data sections.

You can then add a section just below the location in the linker file where . is set to the desired address.

For example:

SECTION
{
...

    . = where_i_want_prog_sz;
    prog_sz_section :
    {
        * (.bss.prog_sz)
    }
...
}

Note that this will store prog_sz at a specific location, but will not set prog_sz to the value of the location.

  1. Treat a linker symbol defined in the command file as a size_t variable.

Define the variable using the extern keyword: extern size_t prog_sz;

This tells the compiler that the symbol is defined elsewhere but will be of type size_t. Keep in mind, if this is what is being done, then you will need to be sure that the memory location is not being used for anything else, otherwise prog_sz may overlap other data in the system.

Regarding the second issue, which is the list of linker error messages, I believe that you may not have the linker configured correctly. Symbols __init_array_end and __init_array_start are related to initializing the C programming environment. I would suggest reviewing the linker settings and documentation to make sure that the program is properly configured. If you are using the GNU toolchain, you can find documentation here:

https://sourceware.org/binutils/docs-2.37/

  • Related