From: Joe Stringer <hidden> Date: 2019-02-12 00:47:40
This series adds support to libbpf for relocating references to 32-bit
static data inside ELF files, both for .data and .bss, similar to one of
the approaches proposed in LPC 2018[0]. This improves a common workflow
for BPF users, where the BPF program may be customised each time it is
loaded, for example to tailor IP addresses for each instance of the
loaded program. Current approaches require full recompilation of the
programs for each load, however with templatized BPF programs, one ELF
template program may be generated, then the static data can be easily
substituted prior to loading into the kernel without invoking the
compiler again.
The approach here is useful for templating limited static data for ELF
programs, and will work regardless of kernel support for static data
sections. Its main limitation is that static data must be defined as
32-bit values in the BPF C input code (or defined using macros that use
32-bit values as the underlying store). The alternative approach
proposed at LPC would be more general and is being actively explored,
however it requires kernel extension and so will not solve this problem
for any existing kernels that are in use today.
There are similar patches floating around for iproute2 which I would
like to upstream as well[1].
[0] https://linuxplumbersconf.org/event/2/contributions/115/
[1] https://github.com/joestringer/iproute2/tree/bss
Joe Stringer (4):
libbpf: Refactor relocations
libbpf: Support 32-bit static data loads
libbpf: Support relocations for bss.
selftests/bpf: Test static data relocation
tools/lib/bpf/libbpf.c | 108 ++++++++++++------
tools/testing/selftests/bpf/Makefile | 2 +-
tools/testing/selftests/bpf/test_progs.c | 44 +++++++
.../selftests/bpf/test_static_data_kern.c | 47 ++++++++
4 files changed, 168 insertions(+), 33 deletions(-)
create mode 100644 tools/testing/selftests/bpf/test_static_data_kern.c
--
2.19.1
From: Joe Stringer <hidden> Date: 2019-02-12 00:47:42
Adjust the code for relocations slightly with no functional changes, so
that upcoming patches that will introduce support for relocations into
the .data and .bss sections can be added independent of these changes.
Signed-off-by: Joe Stringer <redacted>
---
tools/lib/bpf/libbpf.c | 62 ++++++++++++++++++++++--------------------
1 file changed, 32 insertions(+), 30 deletions(-)
@@ -852,20 +852,20 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)obj->efile.symbols=data;obj->efile.strtabidx=sh.sh_link;}-}elseif((sh.sh_type==SHT_PROGBITS)&&-(sh.sh_flags&SHF_EXECINSTR)&&-(data->d_size>0)){-if(strcmp(name,".text")==0)-obj->efile.text_shndx=idx;-err=bpf_object__add_program(obj,data->d_buf,-data->d_size,name,idx);-if(err){-charerrmsg[STRERR_BUFSIZE];-char*cp=libbpf_strerror_r(-err,errmsg,-sizeof(errmsg));--pr_warning("failed to alloc program %s (%s): %s",-name,obj->path,cp);+}elseif(sh.sh_type==SHT_PROGBITS&&data->d_size>0){+if(sh.sh_flags&SHF_EXECINSTR){+if(strcmp(name,".text")==0)+obj->efile.text_shndx=idx;+err=bpf_object__add_program(obj,data->d_buf,+data->d_size,name,idx);+if(err){+charerrmsg[STRERR_BUFSIZE];+char*cp=libbpf_strerror_r(-err,errmsg,+sizeof(errmsg));++pr_warning("failed to alloc program %s (%s): %s",+name,obj->path,cp);+}}}elseif(sh.sh_type==SHT_REL){void*reloc=obj->efile.reloc;
@@ -1027,24 +1027,26 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,return-LIBBPF_ERRNO__RELOC;}-/* TODO: 'maps' is sorted. We can use bsearch to make it faster. */-for(map_idx=0;map_idx<nr_maps;map_idx++){-if(maps[map_idx].offset==sym.st_value){-pr_debug("relocation: find map %zd (%s) for insn %u\n",-map_idx,maps[map_idx].name,insn_idx);-break;+if(sym.st_shndx==maps_shndx){+/* TODO: 'maps' is sorted. We can use bsearch to make it faster. */+for(map_idx=0;map_idx<nr_maps;map_idx++){+if(maps[map_idx].offset==sym.st_value){+pr_debug("relocation: find map %zd (%s) for insn %u\n",+map_idx,maps[map_idx].name,insn_idx);+break;+}}-}-if(map_idx>=nr_maps){-pr_warning("bpf relocation: map_idx %d large than %d\n",-(int)map_idx,(int)nr_maps-1);-return-LIBBPF_ERRNO__RELOC;-}+if(map_idx>=nr_maps){+pr_warning("bpf relocation: map_idx %d large than %d\n",+(int)map_idx,(int)nr_maps-1);+return-LIBBPF_ERRNO__RELOC;+}-prog->reloc_desc[i].type=RELO_LD64;-prog->reloc_desc[i].insn_idx=insn_idx;-prog->reloc_desc[i].map_idx=map_idx;+prog->reloc_desc[i].type=RELO_LD64;+prog->reloc_desc[i].insn_idx=insn_idx;+prog->reloc_desc[i].map_idx=map_idx;+}}return0;}
From: Joe Stringer <hidden> Date: 2019-02-12 00:47:45
Support loads of static 32-bit data when BPF writers make use of
convenience macros for accessing static global data variables. A later
patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will
complain if this technique is attempted with data of other sizes:
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
Based on the proof of concept by Daniel Borkmann (presented at LPC 2018).
Signed-off-by: Joe Stringer <redacted>
---
tools/lib/bpf/libbpf.c | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
@@ -866,6 +871,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)pr_warning("failed to alloc program %s (%s): %s",name,obj->path,cp);}+}elseif(strcmp(name,".data")==0){+obj->efile.global_data=data;+obj->efile.data_shndx=idx;}}elseif(sh.sh_type==SHT_REL){void*reloc=obj->efile.reloc;
From: Joe Stringer <hidden> Date: 2019-02-12 00:47:47
The BSS section in an ELF generated by LLVM represents constants for
uninitialized variables or variables that are configured with a zero
value. Support initializing zeroed static data by parsing the
relocations with references to the .bss section and zeroing them.
Signed-off-by: Joe Stringer <redacted>
---
tools/lib/bpf/libbpf.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
@@ -36,7 +36,7 @@ BPF_OBJ_FILES = \get_cgroup_id_kern.osocket_cookie_prog.otest_select_reuseport_kern.o\test_skb_cgroup_id_kern.obpf_flow.onetcnt_prog.otest_xdp_vlan.o\xdp_dummy.otest_map_in_map.otest_spin_lock.otest_map_lock.o\-test_sock_fields_kern.o+test_sock_fields_kern.otest_static_data_kern.o# Objects are built with default compilation flags and with sub-register# code-gen enabled.
On Mon, Feb 11, 2019 at 04:47:29PM -0800, Joe Stringer wrote:
Add tests for libbpf relocation of static variable references into the
.data and .bss sections of the ELF.
Signed-off-by: Joe Stringer <redacted>
...
+#define __fetch(x) (__u32)(&(x))
+
+static __u32 static_bss = 0; /* Reloc reference to .bss section */
+static __u32 static_data = 42; /* Reloc reference to .data section */
+
+/**
+ * Load a u32 value from a static variable into a map, for the userland test
+ * program to validate.
+ */
+SEC("static_data_load")
+int load_static_data(struct __sk_buff *skb)
+{
+ __u32 key, value;
+
+ key = 0;
+ value = __fetch(static_bss);
If we proceed with this approach we will not be able to add support
for normal 'value = static_bss;' C code in the future.
Let's figure out the way to do it right from the start.
Support for global and static variables is must have feature to add asap,
but let's not cut the corner like this.
We did such hacks in the past and every time it came back to bite us.
From: Joe Stringer <hidden> Date: 2019-02-12 20:43:36
On Mon, Feb 11, 2019 at 9:01 PM Alexei Starovoitov
[off-list ref] wrote:
On Mon, Feb 11, 2019 at 04:47:29PM -0800, Joe Stringer wrote:
quoted
Add tests for libbpf relocation of static variable references into the
.data and .bss sections of the ELF.
Signed-off-by: Joe Stringer <redacted>
...
quoted
+#define __fetch(x) (__u32)(&(x))
+
+static __u32 static_bss = 0; /* Reloc reference to .bss section */
+static __u32 static_data = 42; /* Reloc reference to .data section */
+
+/**
+ * Load a u32 value from a static variable into a map, for the userland test
+ * program to validate.
+ */
+SEC("static_data_load")
+int load_static_data(struct __sk_buff *skb)
+{
+ __u32 key, value;
+
+ key = 0;
+ value = __fetch(static_bss);
If we proceed with this approach we will not be able to add support
for normal 'value = static_bss;' C code in the future.
Hmm, completely agree that breaking future use of standard code is a
non-starter.
Digging around a bit more, I think I could drop the .bss patch/code
here and still end up with something that will work for my use case.
Just need to ensure that all template values are non-zero when run
through the compiler.
Let's figure out the way to do it right from the start.
Support for global and static variables is must have feature to add asap,
but let's not cut the corner like this.
We did such hacks in the past and every time it came back to bite us.
Do you see any value in having incremental support in libbpf that
could be used as a fallback for older kernels like in patch #2 of this
series? I could imagine libbpf probing kernel support for
global/static variables and attempting to handle references to .data
via some more comprehensive mechanism in-kernel, or falling back to
this approach if it is not available.
On Tue, Feb 12, 2019 at 12:43:21PM -0800, Joe Stringer wrote:
Do you see any value in having incremental support in libbpf that
could be used as a fallback for older kernels like in patch #2 of this
series? I could imagine libbpf probing kernel support for
global/static variables and attempting to handle references to .data
via some more comprehensive mechanism in-kernel, or falling back to
this approach if it is not available.
I don't think we have to view it as older vs new kernel and fallback discussion.
I think access to static vars can be implemented in libbpf today without
changing llvm and kernel.
For the following code:
static volatile __u32 static_data = 42;
SEC("anything")
int load_static_data(struct __sk_buff *skb)
{
__u32 value = static_data;
llvm will generate asm:
r1 = static_data ll
r1 = *(u32 *)(r1 + 0)
libbpf can replace first insn with r1 = 0 (or remove it altogether)
and second insn with r1 = 42 _when it is safe_.
If there was no volatile keyword llvm would have optimized
these two instructions into operation with immediate constant.
libbpf can do this opimization instead of llvm.
libbpf can check that 'static_data' is indeed not global in elf file
and there are no store operations in all programs in that elf file.
Then every load from that address can be replaced with rX=imm
of the value from data section.
libbpf would need to do data flow analysis which is substantial
feature addition. I think it's inevitable next step anyway.
The key point that this approach will be compatible with future
global variables and modifiable static variables.
In such case load/store instructions will stay as-is
and kernel support will be needed to replace 'r1 = static_data ll'
with properly marked ld_imm64 insn.
On Mon, Feb 11, 2019 at 4:48 PM Joe Stringer [off-list ref] wrote:
Support loads of static 32-bit data when BPF writers make use of
convenience macros for accessing static global data variables. A later
patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will
complain if this technique is attempted with data of other sizes:
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
A little bit clarification from compiler side.
The above compiler error is to prevent people use static variables since current
kernel/libbpf does not handle this. The compiler only warns if .bss or
.data section
has more than one definitions. The first definition always has section offset 0
and the compiler did not warn.
The restriction is a little strange. To only work with 32-bit data is
not a right
statement. The following are some examples.
The following static variable definitions will succeed:
static int a; /* one in .bss */
static long b = 2; /* one in .data */
The following definitions will fail as both in .bss.
static int a;
static int b;
The following definitions will fail as both in .data:
static char a = 2;
static int b = 3;
Using global variables can prevent compiler errors.
maps are defined as globals and the compiler does not
check whether a particular global variable is defining a map or not.
If you just use static variable like below
static int a = 2;
without potential assignment to a, the compiler will replace variable
a with 2 at compile time.
An alternative is to define like below
static volatile int a = 2;
You can get a "load" for variable "a" in the bpf load even if there is
no assignment to a.
Maybe now is the time to remove the compiler assertions as
libbpf/kernel starts to
handle static variables?
quoted hunk
Based on the proof of concept by Daniel Borkmann (presented at LPC 2018).
Signed-off-by: Joe Stringer <redacted>
---
tools/lib/bpf/libbpf.c | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
@@ -866,6 +871,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)pr_warning("failed to alloc program %s (%s): %s",name,obj->path,cp);}+}elseif(strcmp(name,".data")==0){+obj->efile.global_data=data;+obj->efile.data_shndx=idx;}}elseif(sh.sh_type==SHT_REL){void*reloc=obj->efile.reloc;
From: Joe Stringer <hidden> Date: 2019-02-15 07:16:50
On Thu, 14 Feb 2019 at 21:39, Y Song [off-list ref] wrote:
On Mon, Feb 11, 2019 at 4:48 PM Joe Stringer [off-list ref] wrote:
quoted
Support loads of static 32-bit data when BPF writers make use of
convenience macros for accessing static global data variables. A later
patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will
complain if this technique is attempted with data of other sizes:
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
A little bit clarification from compiler side.
The above compiler error is to prevent people use static variables since current
kernel/libbpf does not handle this. The compiler only warns if .bss or
.data section
has more than one definitions. The first definition always has section offset 0
and the compiler did not warn.
Ah, interesting. I observed that warning when I attempted to define
global variables of multiple sizes, and I thought also with sizes
other than 32-bit. This clarifies things a bit, thanks.
For the .bss my observation was that if you had a definition like:
static int a = 0;
Then this will be placed into .bss, hence why I looked into the
approach from this patch for patch 3 as well.
The restriction is a little strange. To only work with 32-bit data is
not a right
statement. The following are some examples.
The following static variable definitions will succeed:
static int a; /* one in .bss */
static long b = 2; /* one in .data */
The following definitions will fail as both in .bss.
static int a;
static int b;
The following definitions will fail as both in .data:
static char a = 2;
static int b = 3;
Are there type restrictions or something? I've been defining multiple
static uint32_t and using them per the approach in this patch series
without hitting this compiler assertion.
Using global variables can prevent compiler errors.
maps are defined as globals and the compiler does not
check whether a particular global variable is defining a map or not.
If you just use static variable like below
static int a = 2;
without potential assignment to a, the compiler will replace variable
a with 2 at compile time.
An alternative is to define like below
static volatile int a = 2;
You can get a "load" for variable "a" in the bpf load even if there is
no assignment to a.
I'll take a closer look at this too.
Maybe now is the time to remove the compiler assertions as
libbpf/kernel starts to
handle static variables?
I don't understand why those assertions exists in this form. It
already allows code which will not load with libbpf (ie generate any
.data/.bss), does it help prevent unexpected situations for
developers?
On Thu, Feb 14, 2019 at 9:38 PM Y Song [off-list ref] wrote:
On Mon, Feb 11, 2019 at 4:48 PM Joe Stringer [off-list ref] wrote:
quoted
Support loads of static 32-bit data when BPF writers make use of
convenience macros for accessing static global data variables. A later
patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will
complain if this technique is attempted with data of other sizes:
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
A little bit clarification from compiler side.
The above compiler error is to prevent people use static variables since current
kernel/libbpf does not handle this. The compiler only warns if .bss or
.data section
has more than one definitions. The first definition always has section offset 0
and the compiler did not warn.
ahh. missed that while playing with .s output.
when target is asm clang doesn't complain.
let's relax this llvm error.
will set of existing relocation be enough to generate
properly formed .o ?
or we need to define a new one?
On Thu, Feb 14, 2019 at 11:16 PM Joe Stringer [off-list ref] wrote:
On Thu, 14 Feb 2019 at 21:39, Y Song [off-list ref] wrote:
quoted
On Mon, Feb 11, 2019 at 4:48 PM Joe Stringer [off-list ref] wrote:
quoted
Support loads of static 32-bit data when BPF writers make use of
convenience macros for accessing static global data variables. A later
patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will
complain if this technique is attempted with data of other sizes:
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
A little bit clarification from compiler side.
The above compiler error is to prevent people use static variables since current
kernel/libbpf does not handle this. The compiler only warns if .bss or
.data section
has more than one definitions. The first definition always has section offset 0
and the compiler did not warn.
Ah, interesting. I observed that warning when I attempted to define
global variables of multiple sizes, and I thought also with sizes
other than 32-bit. This clarifies things a bit, thanks.
For the .bss my observation was that if you had a definition like:
static int a = 0;
Then this will be placed into .bss, hence why I looked into the
approach from this patch for patch 3 as well.
quoted
The restriction is a little strange. To only work with 32-bit data is
not a right
statement. The following are some examples.
The following static variable definitions will succeed:
static int a; /* one in .bss */
static long b = 2; /* one in .data */
The following definitions will fail as both in .bss.
static int a;
static int b;
The following definitions will fail as both in .data:
static char a = 2;
static int b = 3;
Are there type restrictions or something? I've been defining multiple
There is no type restrictions.
-bash-4.4$ cat g.c
struct t {
int a;
char b;
long c;
};
static volatile struct t v;
int test() { return v.a + v.b; }
-bash-4.4$ clang -O2 -g -c -target bpf g.c
-bash-4.4$
static uint32_t and using them per the approach in this patch series
without hitting this compiler assertion.
-bash-4.4$ cat g1.c
static volatile int a;
static volatile int b;
int test() { return a + b; }
-bash-4.4$ clang -O2 -g -c -target bpf g1.c
fatal error: error in backend: Unsupported relocation: try to compile
with -O2 or above, or check your static variable
usage
-bash-4.4$
quoted
Using global variables can prevent compiler errors.
maps are defined as globals and the compiler does not
check whether a particular global variable is defining a map or not.
If you just use static variable like below
static int a = 2;
without potential assignment to a, the compiler will replace variable
a with 2 at compile time.
An alternative is to define like below
static volatile int a = 2;
You can get a "load" for variable "a" in the bpf load even if there is
no assignment to a.
I'll take a closer look at this too.
quoted
Maybe now is the time to remove the compiler assertions as
libbpf/kernel starts to
handle static variables?
I don't understand why those assertions exists in this form. It
already allows code which will not load with libbpf (ie generate any
.data/.bss), does it help prevent unexpected situations for
developers?
The error is introduced by the following llvm commit:
commit 39184e407cd937f2f20d3f61eec205925bae7b13
Author: Yonghong Song [off-list ref]
Date: Wed Aug 22 21:21:03 2018 +0000
bpf: fix an assertion in BPFAsmBackend applyFixup()
Fix bug https://bugs.llvm.org/show_bug.cgi?id=38643
In BPFAsmBackend applyFixup(), there is an assertion for FixedValue to be 0.
This may not be true, esp. for optimiation level 0.
For example, in the above bug, for the following two
static variables:
@bpf_map_lookup_elem = internal global i8* (i8*, i8*)*
inttoptr (i64 1 to i8* (i8*, i8*)*), align 8
@bpf_map_update_elem = internal global i32 (i8*, i8*, i8*, i64)*
inttoptr (i64 2 to i32 (i8*, i8*, i8*, i64)*), align 8
The static variable @bpf_map_update_elem will have a symbol
offset of 8 and a FK_SecRel_8 with FixupValue 8 will cause
the assertion if llvm is built with -DLLVM_ENABLE_ASSERTIONS=ON.
The above relocations will not exist if the program is compiled
with optimization level -O1 and above as the compiler optimizes
those static variables away. In the below error message, -O2
is suggested as this is the common practice.
Note that FixedValue = 0 in applyFixup() does exist and is valid,
e.g., for the global variable my_map in the above bug. The bpf
loader will process them properly for map_id's before loading
the program into the kernel.
The static variables, which are not optimized away by compiler,
may have FK_SecRel_8 relocation with non-zero FixedValue.
The patch removed the offending assertion and will issue
a hard error as below if the FixedValue in applyFixup()
is not 0.
$ llc -march=bpf -filetype=obj fixup.ll
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
Its main purpose is to fix a behavior difference with and without
-DLLVM_ENABLE_ASSERTIONS=ON. The patch generated an error
regardless whether the compiler time assertion is turned on or not.
It does not catch all the cases e.g., only one static variable is defined,
which needs fine tuning as there are legitimate cases (e.g., in some dwarf
sessions) where the Fixup is valid with FixedValue = 0.
If you try to use more than onee static variables, the compiler will
print an error and let you know your potential issues.
The question is since we are on the path to allow static variables
in the bpf programs for later patching, we probably should remove
this compiler fatal error?
FYI.The latest llvm trunk will not emit errors for static variables. The patch
also gives detailed information how to relate a particular static
variable to a particular
relocation.
https://reviews.llvm.org/rL354954
Thanks,
Yonghong
On Fri, Feb 15, 2019 at 12:18 PM Y Song [off-list ref] wrote:
On Thu, Feb 14, 2019 at 11:16 PM Joe Stringer [off-list ref] wrote:
quoted
On Thu, 14 Feb 2019 at 21:39, Y Song [off-list ref] wrote:
quoted
On Mon, Feb 11, 2019 at 4:48 PM Joe Stringer [off-list ref] wrote:
quoted
Support loads of static 32-bit data when BPF writers make use of
convenience macros for accessing static global data variables. A later
patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will
complain if this technique is attempted with data of other sizes:
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
A little bit clarification from compiler side.
The above compiler error is to prevent people use static variables since current
kernel/libbpf does not handle this. The compiler only warns if .bss or
.data section
has more than one definitions. The first definition always has section offset 0
and the compiler did not warn.
Ah, interesting. I observed that warning when I attempted to define
global variables of multiple sizes, and I thought also with sizes
other than 32-bit. This clarifies things a bit, thanks.
For the .bss my observation was that if you had a definition like:
static int a = 0;
Then this will be placed into .bss, hence why I looked into the
approach from this patch for patch 3 as well.
quoted
The restriction is a little strange. To only work with 32-bit data is
not a right
statement. The following are some examples.
The following static variable definitions will succeed:
static int a; /* one in .bss */
static long b = 2; /* one in .data */
The following definitions will fail as both in .bss.
static int a;
static int b;
The following definitions will fail as both in .data:
static char a = 2;
static int b = 3;
Are there type restrictions or something? I've been defining multiple
There is no type restrictions.
-bash-4.4$ cat g.c
struct t {
int a;
char b;
long c;
};
static volatile struct t v;
int test() { return v.a + v.b; }
-bash-4.4$ clang -O2 -g -c -target bpf g.c
-bash-4.4$
quoted
static uint32_t and using them per the approach in this patch series
without hitting this compiler assertion.
-bash-4.4$ cat g1.c
static volatile int a;
static volatile int b;
int test() { return a + b; }
-bash-4.4$ clang -O2 -g -c -target bpf g1.c
fatal error: error in backend: Unsupported relocation: try to compile
with -O2 or above, or check your static variable
usage
-bash-4.4$
quoted
quoted
Using global variables can prevent compiler errors.
maps are defined as globals and the compiler does not
check whether a particular global variable is defining a map or not.
If you just use static variable like below
static int a = 2;
without potential assignment to a, the compiler will replace variable
a with 2 at compile time.
An alternative is to define like below
static volatile int a = 2;
You can get a "load" for variable "a" in the bpf load even if there is
no assignment to a.
I'll take a closer look at this too.
quoted
Maybe now is the time to remove the compiler assertions as
libbpf/kernel starts to
handle static variables?
I don't understand why those assertions exists in this form. It
already allows code which will not load with libbpf (ie generate any
.data/.bss), does it help prevent unexpected situations for
developers?
The error is introduced by the following llvm commit:
commit 39184e407cd937f2f20d3f61eec205925bae7b13
Author: Yonghong Song [off-list ref]
Date: Wed Aug 22 21:21:03 2018 +0000
bpf: fix an assertion in BPFAsmBackend applyFixup()
Fix bug https://bugs.llvm.org/show_bug.cgi?id=38643
In BPFAsmBackend applyFixup(), there is an assertion for FixedValue to be 0.
This may not be true, esp. for optimiation level 0.
For example, in the above bug, for the following two
static variables:
@bpf_map_lookup_elem = internal global i8* (i8*, i8*)*
inttoptr (i64 1 to i8* (i8*, i8*)*), align 8
@bpf_map_update_elem = internal global i32 (i8*, i8*, i8*, i64)*
inttoptr (i64 2 to i32 (i8*, i8*, i8*, i64)*), align 8
The static variable @bpf_map_update_elem will have a symbol
offset of 8 and a FK_SecRel_8 with FixupValue 8 will cause
the assertion if llvm is built with -DLLVM_ENABLE_ASSERTIONS=ON.
The above relocations will not exist if the program is compiled
with optimization level -O1 and above as the compiler optimizes
those static variables away. In the below error message, -O2
is suggested as this is the common practice.
Note that FixedValue = 0 in applyFixup() does exist and is valid,
e.g., for the global variable my_map in the above bug. The bpf
loader will process them properly for map_id's before loading
the program into the kernel.
The static variables, which are not optimized away by compiler,
may have FK_SecRel_8 relocation with non-zero FixedValue.
The patch removed the offending assertion and will issue
a hard error as below if the FixedValue in applyFixup()
is not 0.
$ llc -march=bpf -filetype=obj fixup.ll
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usage
Its main purpose is to fix a behavior difference with and without
-DLLVM_ENABLE_ASSERTIONS=ON. The patch generated an error
regardless whether the compiler time assertion is turned on or not.
It does not catch all the cases e.g., only one static variable is defined,
which needs fine tuning as there are legitimate cases (e.g., in some dwarf
sessions) where the Fixup is valid with FixedValue = 0.
If you try to use more than onee static variables, the compiler will
print an error and let you know your potential issues.
The question is since we are on the path to allow static variables
in the bpf programs for later patching, we probably should remove
this compiler fatal error?