Skip to content

Conversation

@dylandreimerink
Copy link
Member

Lets add support for ELF object linking, that is loading ELF files that have been linked.

In normal non-eBPF C programs it is very normal to have multiple compilation units (C files that compile to .o files) and then at the end to have a separate linker combine these into an executable. In the eBPF world we typically work with single compilation units which we turn into CollectionSpec's and then Collections.

However, libbpf does offer linker logic which can be used via the bpftool utility. You invoke it like bpftool gen object out.o in1.o in2.o in3.o ..... In this linking process the contents of the sections are simply appended to each other, and the linker, and the linker keeps only the symbols that "win". The rule being that a strong symbol overwrites a weak symbol, so a strong symbol from in3.o will overwrite a weak symbol from in1.o. If multiple weak symbols are present then the first takes precedence. So a weak symbol in in1.o wins over one in in3.o.

So, a practical example is our new testdata added in the PR, this is linker1.o (edited to only show .text symbols):

llvm-objdump -j .text -t -s linker1-el.elf

linker1-el.elf: file format elf64-bpf

SYMBOL TABLE:
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000  w    F .text  0000000000000010 fun_l1w
0000000000000010 g     F .text  0000000000000010 fun_l1s
0000000000000020  w    F .text  0000000000000010 fun_ww
0000000000000030 g     F .text  0000000000000010 fun_l1os
0000000000000040  w    F .text  0000000000000010 fun_l1ow
0000000000000000         *UND*  0000000000000000 fun_l2os
Contents of section .text:
 0000 b7000000 01000000 95000000 00000000  ................
 0010 b7000000 02000000 95000000 00000000  ................
 0020 b7000000 03000000 95000000 00000000  ................
 0030 b7000000 04000000 95000000 00000000  ................
 0040 b7000000 05000000 95000000 00000000  ................

And here is linker2.o

llvm-objdump -j .text -t -s linker2-el.elf

linker2-el.elf: file format elf64-bpf

SYMBOL TABLE:
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 g     F .text  0000000000000010 fun_l1w
0000000000000010  w    F .text  0000000000000010 fun_l1s
0000000000000020  w    F .text  0000000000000010 fun_ww
0000000000000030 g     F .text  0000000000000010 fun_l2os
0000000000000040  w    F .text  0000000000000010 fun_l2ow
0000000000000000         *UND*  0000000000000000 fun_l1os
Contents of section .text:
 0000 b7000000 06000000 95000000 00000000  ................
 0010 b7000000 07000000 95000000 00000000  ................
 0020 b7000000 08000000 95000000 00000000  ................
 0030 b7000000 09000000 95000000 00000000  ................
 0040 b7000000 0a000000 95000000 00000000  ................

This is the linked object:

llvm-objdump -j .text -t -s linked-el.elf 

linked-el.elf:  file format elf64-bpf

SYMBOL TABLE:
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000050 g     F .text  0000000000000010 fun_l1w
0000000000000010 g     F .text  0000000000000010 fun_l1s
0000000000000020  w    F .text  0000000000000010 fun_ww
0000000000000030 g     F .text  0000000000000010 fun_l1os
0000000000000040  w    F .text  0000000000000010 fun_l1ow
0000000000000080 g     F .text  0000000000000010 fun_l2os
0000000000000090  w    F .text  0000000000000010 fun_l2ow
Contents of section .text:
 0000 b7000000 01000000 95000000 00000000  ................
 0010 b7000000 02000000 95000000 00000000  ................
 0020 b7000000 03000000 95000000 00000000  ................
 0030 b7000000 04000000 95000000 00000000  ................
 0040 b7000000 05000000 95000000 00000000  ................
 0050 b7000000 06000000 95000000 00000000  ................
 0060 b7000000 07000000 95000000 00000000  ................
 0070 b7000000 08000000 95000000 00000000  ................
 0080 b7000000 09000000 95000000 00000000  ................
 0090 b7000000 0a000000 95000000 00000000  ................

Here you can see, specifically from the second column of the .text dump that both sections are combined. Crucially for the assumptions of the library, is that not the whole contents of the section should be used. We need to collect all symbols for a given section, and only consider the bits of the section indicated by a symbol (offset ; offset+size). The same is also true for maps.

Fixes: #466

@dylandreimerink dylandreimerink force-pushed the feature/load-linked-elfs branch 7 times, most recently from 4520a8c to c5aba68 Compare January 26, 2026 13:40
This commit adds test data for ELF linking. `linker1.c` and `linker2.c`
contain strong an weak symbols. They are then linked together with
`bpftool gen object`.

This commit also updates the testdata docker image to include `bpftool`.

Signed-off-by: Dylan Reimerink <[email protected]>
You can define programs and functions as `__weak`. This allows you to
overwrite the definition of that program when linking multiple ELF files
together.

When multiple ELF files are linked together the linker will simply
combine both sections, so the resulting ELF contains both the original
and the new definition. However, the linker will only preserve the
symbol of the "winning" definition.

Up until now we have made the assumption that the whole section should
be translated into the ProgramSpec. However, we now change this to only
include the instructions that have a symbol, using the size of the
symbol to determine when to stop in case of tailing instructions.

Signed-off-by: Dylan Reimerink <[email protected]>
It is possible to define a map as `__weak`. This allows you to link
multiple ELF files together assuming the map definitions are compatible.
This means you can define logic that operates on a map in multiple
compilation units and have it be a single map after linking.

When multiple ELF files are linked together the contents of map sections
are merged. But only the symbol of the "winning" map is retained. Our
existing logic assumed that all of the contents of the map sections were
active maps and that it exactly matches the BTF var sec info.

This commit changes the logic to use the actual offset and sizes
indicated by the symbols and to compare these against the BTF var sec
info.

Signed-off-by: Dylan Reimerink <[email protected]>
@dylandreimerink dylandreimerink force-pushed the feature/load-linked-elfs branch from c5aba68 to 3b71af2 Compare January 26, 2026 15:47
@dylandreimerink dylandreimerink marked this pull request as ready for review January 29, 2026 09:13
@dylandreimerink dylandreimerink requested a review from a team as a code owner January 29, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

elf: support bpf object linking (bpftool gen object)

1 participant