Re: Broken 32-bit riscv debug build with ZSTD and FTRACE

From: Marco Bonelli
Date: Mon Jun 16 2025 - 21:53:34 EST


I did some digging adding prints to modpost.c, trying to understand the errors
complaining about "local symbol 'xxx' was exported" for now. For reference, I am
using commit 494e7fe591bf834d57c6607cdc26ab8873708aa7 for the broken build and
tag v6.14 for the sane build. Config as per my previous mail:

export ARCH=riscv CROSS_COMPILE=riscv32-linux-
make distclean
make defconfig
make 32-bit.config
./scripts/config \
-e FTRACE \
-e CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT \
-d RD_ZSTD \
-d SECURITY_APPARMOR_INTROSPECT_POLICY \
-d BTRFS_FS
make olddefconfig
make -j vmlinux

It seems like modpost is right: the sanity check for exported symbols fails
because somehow some of the entries of .rela.export_symbol reference wrong
LOCAL symbols.

Inspecting the sane vmlinux.o built on v6.14 I see:

$ readelf -W -r vmlinux.o | grep -A10 -F .rela.export_symbol
Relocation section '.rela.export_symbol' at offset 0x255c28c contains 11089 entries:
Offset Info Type Sym. Value Symbol's Name + Addend
00000004 0862be01 R_RISCV_32 00000028 system_state + 0
00000010 0892f901 R_RISCV_32 00000018 static_key_initialized + 0
00000018 084f0e01 R_RISCV_32 00000014 reset_devices + 0
00000020 08933601 R_RISCV_32 00000008 loops_per_jiffy + 0
0000002c 083fcf01 R_RISCV_32 00000110 init_uts_ns + 0
00000038 08761f01 R_RISCV_32 00000354 wait_for_initramfs + 0
00000040 084c4c01 R_RISCV_32 00000340 init_task + 0
00000048 0863e901 R_RISCV_32 00000aca riscv_cached_mvendorid + 0
00000050 08423d01 R_RISCV_32 00000af4 riscv_cached_marchid + 0

While for the broken vmlinux.o on 494e7fe5 I see:

$ readelf -W -r vmlinux.o | grep -A10 -F .rela.export_symbol
Relocation section '.rela.export_symbol' at offset 0x27aa24cc contains 11425 entries:
Offset Info Type Sym. Value Symbol's Name + Addend
00000004 fff15b01 R_RISCV_32 00000028 system_state + 0
00000010 ffeed801 R_RISCV_32 00000018 static_key_initialized + 0
00000018 fff07d01 R_RISCV_32 00000014 reset_devices + 0
00000020 00149201 R_RISCV_32 000036ed .LASF3838 + 0
0000002c ffde7c01 R_RISCV_32 00000324 init_uts_ns + 0
00000038 ffc4c801 R_RISCV_32 00000b3a wait_for_initramfs + 0
00000040 000d6801 R_RISCV_32 00011e04 .LASF2005 + 0
00000048 ffb72201 R_RISCV_32 000012b0 riscv_cached_mvendorid + 0
00000050 ffd14901 R_RISCV_32 000012da riscv_cached_marchid + 0

Notice how the 4th and 7th relocation entries reference some .LASFxxx label in
the broken build, but reference loops_per_jiffy and init_task in the sane build.

Those relocation entries seem bogus and point to LOCAL symbols. For example,
for .LASF3838 we have ELF32_R_SYM(rela->r_info) = 0x1492 = 5266, which is:

$ readelf -s vmlinux.o | grep ' 5266:'
5266: 000036ed 0 NOTYPE LOCAL DEFAULT 178 .LASF3838

So rela->r_info is bad, and when modpost looks at it, it rightfully complains
about the symbol being local. However, rela->r_offset (0x20) seems correct as it
points to __export_symbol_loops_per_jiffy (taken as offset in .export_symbols).
Therefore, we get the weird error message:

ERROR: modpost: vmlinux: local symbol 'loops_per_jiffy' was exported

Even though loops_per_jiffy is *GLOBAL* and *should* be exported.

FWIW, the call chain is:

section_rela() -> check_section_mismatch() -> check_export_symbol().

Anyhow, that's all I have for now. Seems like vmlinux.o is being built with
RELA relocations that have bogus r_info. Not sure how, will have to do more
digging if/when I have more time.

--
Marco Bonelli