Custom Section Linker Script
The (ELF) programs you run on your (UNIX) computer have these fun little ‘sections’ in them: .text, .data, .bss… and many more. But what are these sections, and what if you wanted to make your own?
If you have a compulsive computer addiction and like reading GCC docs for fun, you probably already know all about ELF, so skip to the fun part if that sounds like you.
Otherwise, here is a short overview of how ELF (the Executable and Linkable Format) describes a standard for executable code.
the elf part
ELF is how Unix and Unix-like operating systems link and load compiled programs. When you compile a source file like a simple hello_world.c program with a compiler like gcc, what first is created is an object file: hello_world.o:
sh-5.3$ cat hello_world.c:
#include <stdio.h>
int main(void) {
printf("Hello, World!\n");
return 42;
}
1sh-5.3$ gcc -c hello_world.c; ls:
hello_world.c hello_world.o
This object file (ending in .o) isn’t quite an executable yet, but it is an ELF file.
Using objdump to show the sections in an executable, we can see what hello_world.o is made up of:
2sh-5.3$ objdump --headers hello_world.o:
hello_world.o: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000001a 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 0000000000000000 0000000000000000 0000005a 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 0000000000000000 0000000000000000 0000005a 2**0
ALLOC
3 .rodata 0000000e 0000000000000000 0000000000000000 0000005a 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 00000013 0000000000000000 0000000000000000 00000068 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 0000007b 2**0
CONTENTS, READONLY
6 .note.gnu.property 00000030 0000000000000000 0000000000000000 00000080 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .eh_frame 00000038 0000000000000000 0000000000000000 000000b0 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
You can see this is an ELF file from the header hello_world.o: file format elf64-x86-64–this was compiled on my PC running Linux with an AMD x86_64 CPU.
You can also see that hello_world.o contains several sections. Your compiled code lives in .text–this will be made of actual x86_64 machine code. You can disassemble it with objdump -d hello_world.o. Data that your program uses to run is stored across .data and .rodata–things like strings and globals. You can see that .rodata has a non-zero size–this is where the “Hello, world\n” string is saved! The .bss section is the last important one, and its kind of special. It stands for “Block Started Symbol”, and it holds metadata about the size of static variables in your code. The operating system’s loader uses .bss to determine how much space to allocate at load-time for static variables. This way, space can be saved in the executable file.
Finally, you can compile this .o file to an executable, again with gcc:
sh-5.3$ gcc -o hello_world hello_world.o; ls:
hello_world hello_world.c hello_world.o
sh-5.3$ ./hello_world:
Hello, World!
the fun part
GNU ld’s “linkerscripts” are the tool to reach for when you need control over your executable’s layout. Let’s say you were working on a project that required (for whatever reason) that certain source code ended up in a specific section:
src/
├─my_cool_section # <- this stuff should go in a new section ".my_cool_section"
└─everything_else # <- everything else should go in the regular sections
You could write a linker script that had a custom section defined as follows:
.my_cool_section ALIGN(0x200000) :
{
PROVIDE (__mycoolsection_start = ABSOLUTE(.));
KEEP(*/my_cool_section/*(.text))
. = ALIGN(0x200000);
PROVIDE (__mycoolsection_end = ABSOLUTE(.));
}
This would do a few cool things:
- Create a cool new section called
.my_cool_section - Align this cool new section to a 2 megabyte boundary
- Put all of the
.textsections from code in themy_cool_sectionfolder into.my_cool_section PROVIDEtwo new addresses:__mycoolsection_startand__mycoolsection_end, which you can access in your code using a declaration likeextern char[] __mycoolsection_start
When you go to compile your program with gcc, you can pass your custom linker script with the -T option: gcc -T myscript.ld ...
Congratulations! You now have an executable with a cool custom section. Now what?
-
I used the
-coption here so thatgccgave me an object file instead of a fully compiled and linked executable ↩ -
Technically if you followed me exactly you won’t get this exact output. It looked like the default optimization level did something weird (
.texthad size 0!), so I actually ran thegcccommand with-O0to disable optimization. ↩