I want to define a section in a linker script and take its value from the source code at runtime.
So far, I have taken the default gcc linker
script file and I have added my section as following:
...
.my_section : { BYTE(0xAA); }
...
After compiling, I can see the section:
> gcc -T ls.ld main.c -o main
> objdump -h main
...
...
27 .my_section 00000001 0000000000a01040 0000000000a01040 00001040 2**0
CONTENTS, ALLOC, LOAD, DATA
28 .comment 00000034 0000000000000000 0000000000000000 00001041 2**0
CONTENTS, READONLY
Now, I want to print that value to stdout
(and I'm expecting to obtain 0xAA
):
#include <stdio.h>
static volatile unsigned char SECTION __attribute__((section(".my_section")));
int main(){
printf("hello %d\n", SECTION);
return 0;
}
The value I obtain is always 0. What I'm doing wrong?
What I'm doing wrong?
You are forcing the linker to output in the program two sections, each called
.my_section
.
One of them is caused by:
static volatile unsigned char SECTION __attribute__((section(".my_section")));
in main.c
. In this .my_section
, a symbol named SECTION
is statically defined that
addresses a char
that by default is statically initialized = 0. When you
printf("hello %d\n", SECTION)
you are of course printing the integer at that 0-initialized symbol.
The other .my_section
is caused by the:
.my_section : { BYTE(0xAA); }
in ls.ld
. This second .my_section
begins with a byte = 0xAA
but is never
accessed by the program.
Here is an illustration. I have:
main.c
#include <stdio.h>
static volatile unsigned char MY_SECTION __attribute__((section(".my_section"))) = '!';
int main(){
printf("hello %c\n", MY_SECTION);
return 0;
}
and I have a linker-script ls.ld
that is my gcc
default linker script with:
.my_section : { BYTE(0xAA); }
appended last in SECTIONS
.
Compile, link and run:
$ gcc -Wall -Wextra -T ls.ld -o prog main.c
$ ./prog
hello !
Look at the section details of prog
:
$ readelf -t prog
There are 31 section headers, starting at offset 0x3990:
Section Headers:
[Nr] Name
Type Address Offset Link
Size EntSize Info Align
Flags
...
[24] .my_section
PROGBITS PROGBITS 0000000000004010 0000000000003010 0
0000000000000001 0000000000000000 0 1
[0000000000000003]: WRITE, ALLOC
[25] .bss
NOBITS NOBITS 0000000000004011 0000000000003011 0
0000000000000007 0000000000000000 0 1
[0000000000000003]: WRITE, ALLOC
[26] .comment
PROGBITS PROGBITS 0000000000000000 0000000000003019 0
0000000000000023 0000000000000001 0 1
[0000000000000030]: MERGE, STRINGS
[27] .my_section
PROGBITS PROGBITS 0000000000006018 0000000000003018 0
0000000000000001 0000000000000000 0 1
[0000000000000003]: WRITE, ALLOC
...
Section 24 is called .my_section
and so is section 27. The local symbol MY_SECTION
:
$ readelf -s prog | grep 'MY_SECTION'
37: 0000000000004010 1 OBJECT LOCAL DEFAULT 24 MY_SECTION
is defined in section 24
.
Then look at the disassembly:
$ objdump --disassemble-all prog
prog: file format elf64-x86-64
...
...
Disassembly of section .my_section:
0000000000004010 <__TMC_END__>:
4010: 21 .byte 0x21
...
...
Disassembly of section .my_section:
0000000000006018 <.my_section>:
6018: aa stos %al,%es:(%rdi)
...
...
The first one, starting with 0x21
= !
, is the one created in main.c
and accessed by the program. The second one, starting with 0xaa
, is
the one created by the linker script and not accessed by the program.
Choose one way of outputting your .my_section
or the other:-
You can do it in your source code with:
static volatile unsigned char MY_SECTION __attribute__((section(".my_section"))) = 0xAA;
Or you can do it in the linker script as @MichaelPetch commented, like:
.my_section : { my_section_addr = .; BYTE(0xAA); }
and access the section in a program like:
$ cat main1.c
#include <stdio.h>
extern unsigned char my_section_addr[];
int main(){
printf("section `.my_section` starts at %p and the 1st byte is %x\n",
my_section_addr, (unsigned int)my_section_addr[0]);
return 0;
}
$ gcc -Wall -Wextra -T ls.ld -o prog main1.c
$ ./prog
section `.my_section` starts at 0x560a32964018 and the 1st byte is aa
But it is not actually necessary to customize the linker script in order to obtain the address of a custom section in a program. See:
$ cat main2.c
#include <stdio.h>
static unsigned char pling __attribute__((section("my_section"))) = '!';
extern unsigned char __start_my_section;
extern unsigned char __stop_my_section;
static char * p_my_section_start = &__start_my_section;
static char * p_my_section_end = &__stop_my_section;
int main(){
printf("section `my_section` starts at %p, ends at %p, and the 1st byte is %c\n",
p_my_section_start, p_my_section_end, p_my_section_start[0]);
return 0;
}
$ gcc -o prog main2.c
$ ./prog
section `my_section` starts at 0x55db7b0fb020, ends at 0x55db7b0fb021, and the 1st byte is !
Seeing extern
declarations of the form __start_<section_name
or __stop_<section_name>
,
the linker will automatically place these symbols at the start and end respectively of
section <section_name>
.
And should you want to compile and link multiple source files that all access the same custom
section my_section
in a program, you can simply define symbols attributed to section
my_section
in the several source files and the linker, with the default linker script,
with merge all the sections called my_section
in the input object files into a single
output my_section
in the program. (Just as it merges, e.g. all the .text
sections
of the input object files into a single .text
section of program). See:
$ cat foo.c
#include <stdio.h>
unsigned int foo __attribute__((section("my_section"))) = 0xf00;
$ cat boo.c
#include <stdio.h>
unsigned int boo __attribute__((section("my_section"))) = 0xb00;
$ cat main3.c
#include <stdio.h>
extern unsigned int foo;
extern unsigned int boo;
int main(){
printf("foo=%x, boo=%x\n",foo,boo);
return 0;
}
$ gcc -Wall -o prog main3.c foo.c boo.c
$ ./prog
foo=f00, boo=b00
and:
$ readelf -t prog | grep my_section
[24] my_section
there is only one section, 24, called my_section
in the program, which:
$ readelf -s prog | egrep '(foo|boo)'
36: 0000000000000000 0 FILE LOCAL DEFAULT ABS foo.c
37: 0000000000000000 0 FILE LOCAL DEFAULT ABS boo.c
59: 0000000000004010 4 OBJECT GLOBAL DEFAULT 24 foo
66: 0000000000004014 4 OBJECT GLOBAL DEFAULT 24 boo
contains the definitions of both foo
and boo
.