Skip to contentSkip to conversation

kbuild: Avoid weak external linkage where possible

PATCH Superseded Ard Biesheuvel 5 participants 12 messages Apr 9, 2024 – Apr 10, 2024

Subsystems (6)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 cover kbuild: Avoid weak external linkage where possible

From: Ard Biesheuvel <[email protected]>

Weak external linkage is intended for cases where a symbol reference can remain unsatisfied in the final link. Taking the address of such a symbol should yield NULL if the reference was not satisfied.

Given that ordinary RIP or PC relative references cannot produce NULL, some kind of indirection is always needed in such cases, and in position independent code, this results in a GOT entry. In ordinary code, it is arch specific but amounts to the same thing.

While unavoidable in some cases, weak references are currently also used to declare symbols that are always defined in the final link, but not in the first linker pass. This means we end up with worse codegen for no good reason. So let's clean this up, by providing preliminary definitions that are only used as a fallback.

Changes since v1:
- update second occurrence of BTF start/end markers
- drop NULL check of __start_BTF[] which is no longer meaningful
- avoid the preliminary BTF symbols if CONFIG_DEBUG_INFO_BTF is not set
- add Andrii's ack to patch #3
- patches #1 and #2 unchanged

Cc Masahiro Yamada <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Martin KaFai Lau <[email protected]>
Cc Andrii Nakryiko <[email protected]>

Ard Biesheuvel (3):
kallsyms: Avoid weak references for kallsyms symbols
vmlinux: Avoid weak reference to notes section
btf: Avoid weak external references

 include/asm-generic/vmlinux.lds.h | 28 ++++++++++++++++++
 kernel/bpf/btf.c                  |  4 +--
 kernel/bpf/sysfs_btf.c            |  6 ++--
 kernel/kallsyms.c                 |  6 ----
 kernel/kallsyms_internal.h        | 30 ++++++++------------
 kernel/ksysfs.c                   |  4 +--
 lib/buildid.c                     |  4 +--
 7 files changed, 49 insertions(+), 33 deletions(-)
Signature · 1 line
2.44.0.478.gd926399ef9-goog
#1 lore raw

PATCH v2 1/3 kallsyms: Avoid weak references for kallsyms symbols

From: Ard Biesheuvel <[email protected]>

kallsyms is a directory of all the symbols in the vmlinux binary, and so creating it is somewhat of a chicken-and-egg problem, as its non-zero size affects the layout of the binary, and therefore the values of the symbols.

For this reason, the kernel is linked more than once, and the first pass does not include any kallsyms data at all. For the linker to accept this, the symbol declarations describing the kallsyms metadata are emitted as having weak linkage, so they can remain unsatisfied. During the subsequent passes, the weak references are satisfied by the kallsyms metadata that was constructed based on information gathered from the preceding passes.

Weak references lead to somewhat worse codegen, because taking their address may need to produce NULL (if the reference was unsatisfied), and this is not usually supported by RIP or PC relative symbol references.

Given that these references are ultimately always satisfied in the final link, let's drop the weak annotation, and instead, provide fallback definitions in the linker script that are only emitted if an unsatisfied reference exists.

While at it, drop the FRV specific annotation that these symbols reside in .rodata - FRV is long gone.

---
 include/asm-generic/vmlinux.lds.h | 19 +++++++++++++
 kernel/kallsyms.c                 |  6 ----
 kernel/kallsyms_internal.h        | 30 ++++++++------------
 3 files changed, 31 insertions(+), 24 deletions(-)
include/asm-generic/vmlinux.lds.h +19 -0
index f7749d0f2562..e8449be62058 100644
@@ -448,11 +448,30 @@
 #endif
 #endif
 
+/*
+ * Some symbol definitions will not exist yet during the first pass of the
+ * link, but are guaranteed to exist in the final link. Provide preliminary
+ * definitions that will be superseded in the final link to avoid having to
+ * rely on weak external linkage, which requires a GOT when used in position
+ * independent code.
+ */
+#define PRELIMINARY_SYMBOL_DEFINITIONS					\
+	PROVIDE(kallsyms_addresses = .);				\
+	PROVIDE(kallsyms_offsets = .);					\
+	PROVIDE(kallsyms_names = .);					\
+	PROVIDE(kallsyms_num_syms = .);					\
+	PROVIDE(kallsyms_relative_base = .);				\
+	PROVIDE(kallsyms_token_table = .);				\
+	PROVIDE(kallsyms_token_index = .);				\
+	PROVIDE(kallsyms_markers = .);					\
+	PROVIDE(kallsyms_seqs_of_names = .);
+
 /*
  * Read only Data
  */
 #define RO_DATA(align)							\
 	. = ALIGN((align));						\
+	PRELIMINARY_SYMBOL_DEFINITIONS					\
 	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
 		__start_rodata = .;					\
 		*(.rodata) *(.rodata.*)					\
kernel/kallsyms.c +0 -6
index 18edd57b5fe8..22ea19a36e6e 100644
@@ -325,12 +325,6 @@ static unsigned long get_symbol_pos(unsigned long addr,
 	unsigned long symbol_start = 0, symbol_end = 0;
 	unsigned long i, low, high, mid;
 
-	/* This kernel should never had been booted. */
-	if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
-		BUG_ON(!kallsyms_addresses);
-	else
-		BUG_ON(!kallsyms_offsets);
-
 	/* Do a binary search on the sorted kallsyms_addresses array. */
 	low = 0;
 	high = kallsyms_num_syms;
kernel/kallsyms_internal.h +12 -18
index 27fabdcc40f5..85480274fc8f 100644
@@ -5,27 +5,21 @@
 #include <linux/types.h>
 
 /*
- * These will be re-linked against their real values
- * during the second link stage.
+ * These will be re-linked against their real values during the second link
+ * stage. Preliminary values must be provided in the linker script using the
+ * PROVIDE() directive so that the first link stage can complete successfully.
  */
-extern const unsigned long kallsyms_addresses[] __weak;
-extern const int kallsyms_offsets[] __weak;
-extern const u8 kallsyms_names[] __weak;
+extern const unsigned long kallsyms_addresses[];
+extern const int kallsyms_offsets[];
+extern const u8 kallsyms_names[];
 
-/*
- * Tell the compiler that the count isn't in the small data section if the arch
- * has one (eg: FRV).
- */
-extern const unsigned int kallsyms_num_syms
-__section(".rodata") __attribute__((weak));
-
-extern const unsigned long kallsyms_relative_base
-__section(".rodata") __attribute__((weak));
+extern const unsigned int kallsyms_num_syms;
+extern const unsigned long kallsyms_relative_base;
 
-extern const char kallsyms_token_table[] __weak;
-extern const u16 kallsyms_token_index[] __weak;
+extern const char kallsyms_token_table[];
+extern const u16 kallsyms_token_index[];
 
-extern const unsigned int kallsyms_markers[] __weak;
-extern const u8 kallsyms_seqs_of_names[] __weak;
+extern const unsigned int kallsyms_markers[];
+extern const u8 kallsyms_seqs_of_names[];
 
 #endif // LINUX_KALLSYMS_INTERNAL_H_
Signature · 1 line
2.44.0.478.gd926399ef9-goog
maintainer Acked-by on v2 1/3
#2 lore raw

Re: [PATCH v2 1/3] kallsyms: Avoid weak references for kallsyms symbols

Quoted 24 lines · Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

kallsyms is a directory of all the symbols in the vmlinux binary, and so creating it is somewhat of a chicken-and-egg problem, as its non-zero size affects the layout of the binary, and therefore the values of the symbols.

For this reason, the kernel is linked more than once, and the first pass does not include any kallsyms data at all. For the linker to accept this, the symbol declarations describing the kallsyms metadata are emitted as having weak linkage, so they can remain unsatisfied. During the subsequent passes, the weak references are satisfied by the kallsyms metadata that was constructed based on information gathered from the preceding passes.

Weak references lead to somewhat worse codegen, because taking their address may need to produce NULL (if the reference was unsatisfied), and this is not usually supported by RIP or PC relative symbol references.

Given that these references are ultimately always satisfied in the final link, let's drop the weak annotation, and instead, provide fallback definitions in the linker script that are only emitted if an unsatisfied reference exists.

Quoted 8 lines

While at it, drop the FRV specific annotation that these symbols reside in .rodata - FRV is long gone.

#3 lore raw

PATCH v2 2/3 vmlinux: Avoid weak reference to notes section

In reply to Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

Weak references are references that are permitted to remain unsatisfied in the final link. This means they cannot be implemented using place relative relocations, resulting in GOT entries when using position independent code generation.

The notes section should always exist, so the weak annotations can be omitted.

---
 kernel/ksysfs.c | 4 ++--
 lib/buildid.c   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)
kernel/ksysfs.c +2 -2
index 495b69a71a5d..07fb5987b42b 100644
@@ -228,8 +228,8 @@ KERNEL_ATTR_RW(rcu_normal);
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
-extern const void __start_notes __weak;
-extern const void __stop_notes __weak;
+extern const void __start_notes;
+extern const void __stop_notes;
 #define	notes_size (&__stop_notes - &__start_notes)
 
 static ssize_t notes_read(struct file *filp, struct kobject *kobj,
lib/buildid.c +2 -2
index 898301b49eb6..7954dd92e36c 100644
@@ -182,8 +182,8 @@ unsigned char vmlinux_build_id[BUILD_ID_SIZE_MAX] __ro_after_init;
  */
 void __init init_vmlinux_build_id(void)
 {
-	extern const void __start_notes __weak;
-	extern const void __stop_notes __weak;
+	extern const void __start_notes;
+	extern const void __stop_notes;
 	unsigned int size = &__stop_notes - &__start_notes;
 
 	build_id_parse_buf(&__start_notes, vmlinux_build_id, size);
Signature · 1 line
2.44.0.478.gd926399ef9-goog
maintainer Acked-by on v2 2/3
#4 lore raw

Re: [PATCH v2 2/3] vmlinux: Avoid weak reference to notes section

Quoted 11 lines · Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

Weak references are references that are permitted to remain unsatisfied in the final link. This means they cannot be implemented using place relative relocations, resulting in GOT entries when using position independent code generation.

The notes section should always exist, so the weak annotations can be omitted.

#5 lore raw

PATCH v2 3/3 btf: Avoid weak external references

In reply to Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

If the BTF code is enabled in the build configuration, the start/stop BTF markers are guaranteed to exist in the final link but not during the first linker pass.

Avoid GOT based relocations to these markers in the final executable by providing preliminary definitions that will be used by the first linker pass, and superseded by the actual definitions in the subsequent ones.

Make the preliminary definitions dependent on CONFIG_DEBUG_INFO_BTF so that inadvertent references to this section will trigger a link failure if they occur in code that does not honour CONFIG_DEBUG_INFO_BTF.

Note that Clang will notice that taking the address of__start_BTF cannot yield NULL any longer, so testing for that condition is no longer needed.

---
 include/asm-generic/vmlinux.lds.h | 9 +++++++++
 kernel/bpf/btf.c                  | 4 ++--
 kernel/bpf/sysfs_btf.c            | 6 +++---
 3 files changed, 14 insertions(+), 5 deletions(-)
include/asm-generic/vmlinux.lds.h +9 -0
index e8449be62058..4cb3d88449e5 100644
@@ -456,6 +456,7 @@
  * independent code.
  */
 #define PRELIMINARY_SYMBOL_DEFINITIONS					\
+	PRELIMINARY_BTF_DEFINITIONS					\
 	PROVIDE(kallsyms_addresses = .);				\
 	PROVIDE(kallsyms_offsets = .);					\
 	PROVIDE(kallsyms_names = .);					\
@@ -466,6 +467,14 @@
 	PROVIDE(kallsyms_markers = .);					\
 	PROVIDE(kallsyms_seqs_of_names = .);
 
+#ifdef CONFIG_DEBUG_INFO_BTF
+#define PRELIMINARY_BTF_DEFINITIONS					\
+	PROVIDE(__start_BTF = .);					\
+	PROVIDE(__stop_BTF = .);
+#else
+#define PRELIMINARY_BTF_DEFINITIONS
+#endif
+
 /*
  * Read only Data
  */
kernel/bpf/btf.c +2 -2
index 90c4a32d89ff..46a56bf067a8 100644
@@ -5642,8 +5642,8 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
 	return ERR_PTR(err);
 }
 
-extern char __weak __start_BTF[];
-extern char __weak __stop_BTF[];
+extern char __start_BTF[];
+extern char __stop_BTF[];
 extern struct btf *btf_vmlinux;
 
 #define BPF_MAP_TYPE(_id, _ops)
kernel/bpf/sysfs_btf.c +3 -3
index ef6911aee3bb..fedb54c94cdb 100644
@@ -9,8 +9,8 @@
 #include <linux/sysfs.h>
 
 /* See scripts/link-vmlinux.sh, gen_btf() func for details */
-extern char __weak __start_BTF[];
-extern char __weak __stop_BTF[];
+extern char __start_BTF[];
+extern char __stop_BTF[];
 
 static ssize_t
 btf_vmlinux_read(struct file *file, struct kobject *kobj,
@@ -32,7 +32,7 @@ static int __init btf_vmlinux_init(void)
 {
 	bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF;
 
-	if (!__start_BTF || bin_attr_btf_vmlinux.size == 0)
+	if (bin_attr_btf_vmlinux.size == 0)
 		return 0;
 
 	btf_kobj = kobject_create_and_add("btf", kernel_kobj);
Signature · 1 line
2.44.0.478.gd926399ef9-goog
maintainer Acked-by on v2 3/3
#6 lore raw

Re: [PATCH v2 3/3] btf: Avoid weak external references

Quoted 14 lines · Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

If the BTF code is enabled in the build configuration, the start/stop BTF markers are guaranteed to exist in the final link but not during the first linker pass.

Avoid GOT based relocations to these markers in the final executable by providing preliminary definitions that will be used by the first linker pass, and superseded by the actual definitions in the subsequent ones.

Make the preliminary definitions dependent on CONFIG_DEBUG_INFO_BTF so that inadvertent references to this section will trigger a link failure if they occur in code that does not honour CONFIG_DEBUG_INFO_BTF.

Quoted 6 lines

Note that Clang will notice that taking the address of__start_BTF cannot yield NULL any longer, so testing for that condition is no longer needed.

#7 lore raw

Re: [PATCH v2 3/3] btf: Avoid weak external references

In reply to Ard Biesheuvel
kernel test robot noticed the following build errors:

Hi Ard,

kernel test robot noticed the following build errors:

[auto build test ERROR on arnd-asm-generic/master]
[also build test ERROR on bpf-next/master bpf/master linus/master v6.9-rc3 next-20240409] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ard-Biesheuvel/kallsyms-Avoid-weak-references-for-kallsyms-symbols/20240409-230510
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git master
patch link:    https://lore.kernel.org/r/20240409150132.4097042-8-ardb%2Bgit%40google.com
patch subject: [PATCH v2 3/3] btf: Avoid weak external references
config: riscv-defconfig (https://download.01.org/0day-ci/archive/20240410/[email protected]/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 8b3b4a92adee40483c27f26c478a384cd69c6f05)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240410/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: __start_BTF
   >>> referenced by btf.c
   >>>               kernel/bpf/btf.o:(btf_parse_vmlinux) in archive vmlinux.a
--
>> ld.lld: error: undefined symbol: __stop_BTF
   >>> referenced by btf.c
   >>>               kernel/bpf/btf.o:(btf_parse_vmlinux) in archive vmlinux.a
Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#8 lore raw

Re: [PATCH v2 3/3] btf: Avoid weak external references

In reply to Ard Biesheuvel
kernel test robot noticed the following build errors:

Hi Ard,

kernel test robot noticed the following build errors:

[auto build test ERROR on arnd-asm-generic/master]
[also build test ERROR on bpf-next/master bpf/master linus/master v6.9-rc3 next-20240409] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ard-Biesheuvel/kallsyms-Avoid-weak-references-for-kallsyms-symbols/20240409-230510
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git master
patch link:    https://lore.kernel.org/r/20240409150132.4097042-8-ardb%2Bgit%40google.com
patch subject: [PATCH v2 3/3] btf: Avoid weak external references
config: s390-defconfig (https://download.01.org/0day-ci/archive/20240410/[email protected]/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 8b3b4a92adee40483c27f26c478a384cd69c6f05)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240410/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

s390x-linux-ld: kernel/bpf/btf.o: in function `btf_parse_vmlinux':

>> kernel/bpf/btf.c:5910:(.text+0x3b72): undefined reference to `__start_BTF'
>> s390x-linux-ld: kernel/bpf/btf.c:5911:(.text+0x3b78): undefined reference to `__stop_BTF'

vim +5910 kernel/bpf/btf.c

49f4e6720748c7 Jiri Olsa               2020-07-11  5888  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5889  struct btf *btf_parse_vmlinux(void)
8580ac9404f624 Alexei Starovoitov      2019-10-15  5890  {
8580ac9404f624 Alexei Starovoitov      2019-10-15  5891  	struct btf_verifier_env *env = NULL;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5892  	struct bpf_verifier_log *log;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5893  	struct btf *btf = NULL;
49f4e6720748c7 Jiri Olsa               2020-07-11  5894  	int err;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5895  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5896  	env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5897  	if (!env)
8580ac9404f624 Alexei Starovoitov      2019-10-15  5898  		return ERR_PTR(-ENOMEM);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5899  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5900  	log = &env->log;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5901  	log->level = BPF_LOG_KERNEL;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5902  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5903  	btf = kzalloc(sizeof(*btf), GFP_KERNEL | __GFP_NOWARN);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5904  	if (!btf) {
8580ac9404f624 Alexei Starovoitov      2019-10-15  5905  		err = -ENOMEM;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5906  		goto errout;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5907  	}
8580ac9404f624 Alexei Starovoitov      2019-10-15  5908  	env->btf = btf;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5909  
90ceddcb495008 Fangrui Song            2020-03-18 @5910  	btf->data = __start_BTF;
90ceddcb495008 Fangrui Song            2020-03-18 @5911  	btf->data_size = __stop_BTF - __start_BTF;
5329722057d41a Andrii Nakryiko         2020-11-09  5912  	btf->kernel_btf = true;
5329722057d41a Andrii Nakryiko         2020-11-09  5913  	snprintf(btf->name, sizeof(btf->name), "vmlinux");
8580ac9404f624 Alexei Starovoitov      2019-10-15  5914  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5915  	err = btf_parse_hdr(env);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5916  	if (err)
8580ac9404f624 Alexei Starovoitov      2019-10-15  5917  		goto errout;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5918  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5919  	btf->nohdr_data = btf->data + btf->hdr.hdr_len;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5920  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5921  	err = btf_parse_str_sec(env);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5922  	if (err)
8580ac9404f624 Alexei Starovoitov      2019-10-15  5923  		goto errout;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5924  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5925  	err = btf_check_all_metas(env);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5926  	if (err)
8580ac9404f624 Alexei Starovoitov      2019-10-15  5927  		goto errout;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5928  
eb596b0905584a Kumar Kartikeya Dwivedi 2022-04-19  5929  	err = btf_check_type_tags(env, btf, 1);
eb596b0905584a Kumar Kartikeya Dwivedi 2022-04-19  5930  	if (err)
eb596b0905584a Kumar Kartikeya Dwivedi 2022-04-19  5931  		goto errout;
eb596b0905584a Kumar Kartikeya Dwivedi 2022-04-19  5932  
a2d0d62f4d9e35 Andrey Ignatov          2020-06-19  5933  	/* btf_parse_vmlinux() runs under bpf_verifier_lock */
49f4e6720748c7 Jiri Olsa               2020-07-11  5934  	bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);
91cc1a99740e2e Alexei Starovoitov      2019-11-14  5935  
d3e42bb0a329fa Martin KaFai Lau        2020-01-27  5936  	bpf_struct_ops_init(btf, log);
27ae7997a66174 Martin KaFai Lau        2020-01-08  5937  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5938  	refcount_set(&btf->refcnt, 1);
5329722057d41a Andrii Nakryiko         2020-11-09  5939  
5329722057d41a Andrii Nakryiko         2020-11-09  5940  	err = btf_alloc_id(btf);
5329722057d41a Andrii Nakryiko         2020-11-09  5941  	if (err)
5329722057d41a Andrii Nakryiko         2020-11-09  5942  		goto errout;
5329722057d41a Andrii Nakryiko         2020-11-09  5943  
5329722057d41a Andrii Nakryiko         2020-11-09  5944  	btf_verifier_env_free(env);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5945  	return btf;
8580ac9404f624 Alexei Starovoitov      2019-10-15  5946  
8580ac9404f624 Alexei Starovoitov      2019-10-15  5947  errout:
8580ac9404f624 Alexei Starovoitov      2019-10-15  5948  	btf_verifier_env_free(env);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5949  	if (btf) {
8580ac9404f624 Alexei Starovoitov      2019-10-15  5950  		kvfree(btf->types);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5951  		kfree(btf);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5952  	}
8580ac9404f624 Alexei Starovoitov      2019-10-15  5953  	return ERR_PTR(err);
8580ac9404f624 Alexei Starovoitov      2019-10-15  5954  }
8580ac9404f624 Alexei Starovoitov      2019-10-15  5955  
Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#9 lore raw

Re: [PATCH v2 3/3] btf: Avoid weak external references

In reply to Ard Biesheuvel
Quoted 39 lines · Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

If the BTF code is enabled in the build configuration, the start/stop BTF markers are guaranteed to exist in the final link but not during the first linker pass.

Avoid GOT based relocations to these markers in the final executable by providing preliminary definitions that will be used by the first linker pass, and superseded by the actual definitions in the subsequent ones.

Make the preliminary definitions dependent on CONFIG_DEBUG_INFO_BTF so that inadvertent references to this section will trigger a link failure if they occur in code that does not honour CONFIG_DEBUG_INFO_BTF.

Note that Clang will notice that taking the address of__start_BTF cannot yield NULL any longer, so testing for that condition is no longer needed.

---
 include/asm-generic/vmlinux.lds.h | 9 +++++++++
 kernel/bpf/btf.c                  | 4 ++--
 kernel/bpf/sysfs_btf.c            | 6 +++---
 3 files changed, 14 insertions(+), 5 deletions(-)
include/asm-generic/vmlinux.lds.h +1 -0
index e8449be62058..4cb3d88449e5 100644
@@ -456,6 +456,7 @@
  * independent code.
  */
 #define PRELIMINARY_SYMBOL_DEFINITIONS					\
+	PRELIMINARY_BTF_DEFINITIONS					\
 	PROVIDE(kallsyms_addresses = .);				\
 	PROVIDE(kallsyms_offsets = .);					\
 	PROVIDE(kallsyms_names = .);					\

include/asm-generic/vmlinux.lds.h line 476

Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7 -0
@@ -466,6 +467,14 @@
 	PROVIDE(kallsyms_markers = .);					\
 	PROVIDE(kallsyms_seqs_of_names = .);
 
+#ifdef CONFIG_DEBUG_INFO_BTF
+#define PRELIMINARY_BTF_DEFINITIONS					\
+	PROVIDE(__start_BTF = .);					\
+	PROVIDE(__stop_BTF = .);
+#else
+#define PRELIMINARY_BTF_DEFINITIONS
+#endif

hi,
I'm getting following compilation fail when CONFIG_DEBUG_INFO_BTF is disabled

[jolsa@krava linux-qemu]$ make
CALL scripts/checksyscalls.sh
DESCEND objtool
INSTALL libsubcmd_headers
UPD include/generated/utsversion.h
CC init/version-timestamp.o
LD .tmp_vmlinux.kallsyms1
ld: kernel/bpf/btf.o: in function `btf_parse_vmlinux':
/home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5988: undefined reference to `__start_BTF'
ld: /home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5989: undefined reference to `__stop_BTF'
ld: /home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5989: undefined reference to `__start_BTF' make[2]: *** [scripts/Makefile.vmlinux:37: vmlinux] Error 1
make[1]: *** [/home/jolsa/kernel/linux-qemu/Makefile:1160: vmlinux] Error 2
make: *** [Makefile:240: __sub-make] Error 2

maybe the assumption was that kernel/bpf/btf.o is compiled only for CONFIG_DEBUG_INFO_BTF, but it's actually:

  obj-$(CONFIG_BPF_SYSCALL) += btf.o memalloc.o

I guess we just need !CONFIG_DEBUG_INFO_BTF version of btf_parse_vmlinux function

jirka

Quoted 47 lines
include/asm-generic/vmlinux.lds.h +1 -0
+
 /*
  * Read only Data
  */
kernel/bpf/btf.c +2 -2
index 90c4a32d89ff..46a56bf067a8 100644
@@ -5642,8 +5642,8 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
 	return ERR_PTR(err);
 }
 
-extern char __weak __start_BTF[];
-extern char __weak __stop_BTF[];
+extern char __start_BTF[];
+extern char __stop_BTF[];
 extern struct btf *btf_vmlinux;
 
 #define BPF_MAP_TYPE(_id, _ops)
kernel/bpf/sysfs_btf.c +3 -3
index ef6911aee3bb..fedb54c94cdb 100644
@@ -9,8 +9,8 @@
 #include <linux/sysfs.h>
 
 /* See scripts/link-vmlinux.sh, gen_btf() func for details */
-extern char __weak __start_BTF[];
-extern char __weak __stop_BTF[];
+extern char __start_BTF[];
+extern char __stop_BTF[];
 
 static ssize_t
 btf_vmlinux_read(struct file *file, struct kobject *kobj,
@@ -32,7 +32,7 @@ static int __init btf_vmlinux_init(void)
 {
 	bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF;
 
-	if (!__start_BTF || bin_attr_btf_vmlinux.size == 0)
+	if (bin_attr_btf_vmlinux.size == 0)
 		return 0;
 
 	btf_kobj = kobject_create_and_add("btf", kernel_kobj);
Signature · 1 line
2.44.0.478.gd926399ef9-goog
#10 lore raw

Re: [PATCH v2 3/3] btf: Avoid weak external references

Quoted 70 lines · Jiri Olsa
Quoted 39 lines · Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

If the BTF code is enabled in the build configuration, the start/stop BTF markers are guaranteed to exist in the final link but not during the first linker pass.

Avoid GOT based relocations to these markers in the final executable by providing preliminary definitions that will be used by the first linker pass, and superseded by the actual definitions in the subsequent ones.

Make the preliminary definitions dependent on CONFIG_DEBUG_INFO_BTF so that inadvertent references to this section will trigger a link failure if they occur in code that does not honour CONFIG_DEBUG_INFO_BTF.

Note that Clang will notice that taking the address of__start_BTF cannot yield NULL any longer, so testing for that condition is no longer needed.

---
 include/asm-generic/vmlinux.lds.h | 9 +++++++++
 kernel/bpf/btf.c                  | 4 ++--
 kernel/bpf/sysfs_btf.c            | 6 +++---
 3 files changed, 14 insertions(+), 5 deletions(-)
include/asm-generic/vmlinux.lds.h +1 -0
index e8449be62058..4cb3d88449e5 100644
@@ -456,6 +456,7 @@
  * independent code.
  */
 #define PRELIMINARY_SYMBOL_DEFINITIONS                                       \
+     PRELIMINARY_BTF_DEFINITIONS                                     \
      PROVIDE(kallsyms_addresses = .);                                \
      PROVIDE(kallsyms_offsets = .);                                  \
      PROVIDE(kallsyms_names = .);                                    \

include/asm-generic/vmlinux.lds.h line 476

Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7 -0
@@ -466,6 +467,14 @@
      PROVIDE(kallsyms_markers = .);                                  \
      PROVIDE(kallsyms_seqs_of_names = .);
 
+#ifdef CONFIG_DEBUG_INFO_BTF
+#define PRELIMINARY_BTF_DEFINITIONS                                  \
+     PROVIDE(__start_BTF = .);                                       \
+     PROVIDE(__stop_BTF = .);
+#else
+#define PRELIMINARY_BTF_DEFINITIONS
+#endif

hi,
I'm getting following compilation fail when CONFIG_DEBUG_INFO_BTF is disabled

[jolsa@krava linux-qemu]$ make
CALL scripts/checksyscalls.sh
DESCEND objtool
INSTALL libsubcmd_headers
UPD include/generated/utsversion.h
CC init/version-timestamp.o
LD .tmp_vmlinux.kallsyms1
ld: kernel/bpf/btf.o: in function `btf_parse_vmlinux':
/home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5988: undefined reference to `__start_BTF'
ld: /home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5989: undefined reference to `__stop_BTF'
ld: /home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5989: undefined reference to `__start_BTF' make[2]: *** [scripts/Makefile.vmlinux:37: vmlinux] Error 1
make[1]: *** [/home/jolsa/kernel/linux-qemu/Makefile:1160: vmlinux] Error 2
make: *** [Makefile:240: __sub-make] Error 2

Quoted 5 lines

maybe the assumption was that kernel/bpf/btf.o is compiled only for CONFIG_DEBUG_INFO_BTF, but it's actually:

  obj-$(CONFIG_BPF_SYSCALL) += btf.o memalloc.o

Interesting. I did build test this with and without CONFIG_DEBUG_INFO_BTF, but not with CONFIG_BPF_SYSCALL=y and CONFIG_DEBUG_INFO_BTF=n.

Quoted 3 lines

I guess we just need !CONFIG_DEBUG_INFO_BTF version of btf_parse_vmlinux function

The below gives me a working build.

kernel/bpf/btf.c +3 -0
@@ -5971,6 +5971,9 @@ struct btf *btf_parse_vmlinux(void)
        struct btf *btf = NULL;
        int err;
 
+       if (!IS_ENABLED(CONFIG_DEBUG_INFO_BTF))
+               return ERR_PTR(-ENOENT);
+
        env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN);
        if (!env)
                return ERR_PTR(-ENOMEM);
#11 lore raw

Re: [PATCH v2 3/3] btf: Avoid weak external references

Quoted 90 lines · Ard Biesheuvel
Quoted 70 lines · Jiri Olsa
Quoted 39 lines · Ard Biesheuvel

From: Ard Biesheuvel <[email protected]>

If the BTF code is enabled in the build configuration, the start/stop BTF markers are guaranteed to exist in the final link but not during the first linker pass.

Avoid GOT based relocations to these markers in the final executable by providing preliminary definitions that will be used by the first linker pass, and superseded by the actual definitions in the subsequent ones.

Make the preliminary definitions dependent on CONFIG_DEBUG_INFO_BTF so that inadvertent references to this section will trigger a link failure if they occur in code that does not honour CONFIG_DEBUG_INFO_BTF.

Note that Clang will notice that taking the address of__start_BTF cannot yield NULL any longer, so testing for that condition is no longer needed.

---
 include/asm-generic/vmlinux.lds.h | 9 +++++++++
 kernel/bpf/btf.c                  | 4 ++--
 kernel/bpf/sysfs_btf.c            | 6 +++---
 3 files changed, 14 insertions(+), 5 deletions(-)
include/asm-generic/vmlinux.lds.h +1 -0
index e8449be62058..4cb3d88449e5 100644
@@ -456,6 +456,7 @@
  * independent code.
  */
 #define PRELIMINARY_SYMBOL_DEFINITIONS                                       \
+     PRELIMINARY_BTF_DEFINITIONS                                     \
      PROVIDE(kallsyms_addresses = .);                                \
      PROVIDE(kallsyms_offsets = .);                                  \
      PROVIDE(kallsyms_names = .);                                    \

include/asm-generic/vmlinux.lds.h line 476

Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7 -0
@@ -466,6 +467,14 @@
      PROVIDE(kallsyms_markers = .);                                  \
      PROVIDE(kallsyms_seqs_of_names = .);
 
+#ifdef CONFIG_DEBUG_INFO_BTF
+#define PRELIMINARY_BTF_DEFINITIONS                                  \
+     PROVIDE(__start_BTF = .);                                       \
+     PROVIDE(__stop_BTF = .);
+#else
+#define PRELIMINARY_BTF_DEFINITIONS
+#endif

hi,
I'm getting following compilation fail when CONFIG_DEBUG_INFO_BTF is disabled

[jolsa@krava linux-qemu]$ make
CALL scripts/checksyscalls.sh
DESCEND objtool
INSTALL libsubcmd_headers
UPD include/generated/utsversion.h
CC init/version-timestamp.o
LD .tmp_vmlinux.kallsyms1
ld: kernel/bpf/btf.o: in function `btf_parse_vmlinux':
/home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5988: undefined reference to `__start_BTF'
ld: /home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5989: undefined reference to `__stop_BTF'
ld: /home/jolsa/kernel/linux-qemu/kernel/bpf/btf.c:5989: undefined reference to `__start_BTF' make[2]: *** [scripts/Makefile.vmlinux:37: vmlinux] Error 1
make[1]: *** [/home/jolsa/kernel/linux-qemu/Makefile:1160: vmlinux] Error 2
make: *** [Makefile:240: __sub-make] Error 2

Quoted 5 lines

maybe the assumption was that kernel/bpf/btf.o is compiled only for CONFIG_DEBUG_INFO_BTF, but it's actually:

  obj-$(CONFIG_BPF_SYSCALL) += btf.o memalloc.o

Interesting. I did build test this with and without CONFIG_DEBUG_INFO_BTF, but not with CONFIG_BPF_SYSCALL=y and CONFIG_DEBUG_INFO_BTF=n.

Quoted 3 lines

I guess we just need !CONFIG_DEBUG_INFO_BTF version of btf_parse_vmlinux function

The below gives me a working build.

kernel/bpf/btf.c struct btf *btf_parse_vmlinux(void) · line 5975

Quoted 5 lines
kernel/bpf/btf.c +2 -0
@@ -5971,6 +5971,9 @@ struct btf *btf_parse_vmlinux(void)
        struct btf *btf = NULL;
        int err;
 
+       if (!IS_ENABLED(CONFIG_DEBUG_INFO_BTF))
+               return ERR_PTR(-ENOENT);

nice, so this basically eliminates the rest of the function, I did not know this would work

build's fine now, thanks

jirka

Quoted 4 lines
kernel/bpf/btf.c +1 -0
+
        env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN);
        if (!env)
                return ERR_PTR(-ENOMEM);