On Sun, Jul 12, 2026, 21:34 René J.V. Bertin via ffmpeg-devel < [email protected]> wrote:
> On Sunday July 12 2026 19:54:00 Dennis Mungai wrote: > > >Thanks for the follow-up and the additional context in the email > >above. Your clarification actually points directly to the root cause of > the > >issue. > > > >Since you confirmed that you wiped the directory entirely to ensure no > >artifacts remained, we can completely rule out lingering BFD plugin > issues. > >The true culprit is hiding in your environment variables. > >The RANLIB Trap > > > >You mentioned that you usually set the RANLIB variable to /bin/echo > because > >it is rarely needed in your experience. While it is true that standard C > >builds can often skip ranlib (since modern ar tools automatically generate > >the archive index), *LTO changes the rules of engagement completely*. > > > >When you build with --enable-lto, Clang outputs LLVM intermediate > >representation (IR) bitcode rather than standard machine code. If > >llvm-ranlib is bypassed by replacing it with /bin/echo, the static > archives > >(like libavcodec.a) are generated without a valid symbol index for those > >bitcode objects. > > > > Hi again, > > In my experience skipping ranlib when it is actually required usually > leads to a different error, that typically hints rather explicitly at the > error. Plus, I think you'd expect more symbols to be involved. But you're > right that we have a mixed toolchain issue here, one that maybe wouldn't > exist if it were possible to use an LLVM assembler instead of nasm or yasm > (and generate LLVM bitcode instead of an ELF object). (On a side-note: GCC > for Darwin actually uses clang as the assembler backend.) > > Anyway, I tried your suggestion of course, and ... it doesn't make a > difference. I should add that this time I saved some time and unnecessary > CPU heating by deleting only all .a and *.so* files from my build tree, as > the goal was to regenerate only all static archives and their dependents. > > ``` > > nm -UA libavcodec/libavcodec.a | fgrep ff_mlp > > /opt/local/var/lnxports/build/_opt_local_linux-ports_multimedia_ffmpeg8/ffmpeg8/work/ffmpeg-8.1.2 > nm: lcevctab.o: no symbols > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_calculate_parity > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_checksum16 > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_checksum8 > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_ch_info > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_ch_layouts > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_huffman_tables > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_init_crc > libavcodec/libavcodec.a:mlp.o:00000000 T ff_mlp_restart_checksum > libavcodec/libavcodec.a:mlp_parse.o:00000000 T ff_mlp_read_major_sync > libavcodec/libavcodec.a:mlp_parser.o:00000000 T ff_mlp_parser > libavcodec/libavcodec.a:mlpdec.o:00000000 T ff_mlp_decoder > libavcodec/libavcodec.a:mlpdsp.o:00000000 T ff_mlpdsp_init > libavcodec/libavcodec.a:mlpdsp.o:00000000 T ff_mlp_pack_output > libavcodec/libavcodec.a:mlpdsp.o:00000000 T ff_mlp_rematrix_channel > libavcodec/libavcodec.a:mlpenc.o:00000000 T ff_mlp_encoder > libavcodec/libavcodec.a:mlpdsp.o:0000000000000230 T > ff_mlp_rematrix_channel_avx2_bmi2 > libavcodec/libavcodec.a:mlpdsp.o:00000000000002d0 t > ff_mlp_rematrix_channel_avx2_bmi2.loop4 > libavcodec/libavcodec.a:mlpdsp.o:00000000000003c0 t > ff_mlp_rematrix_channel_avx2_bmi2.loop4_shift > libavcodec/libavcodec.a:mlpdsp.o:0000000000000270 t > ff_mlp_rematrix_channel_avx2_bmi2.loop8 > libavcodec/libavcodec.a:mlpdsp.o:0000000000000340 t > ff_mlp_rematrix_channel_avx2_bmi2.loop8_shift > libavcodec/libavcodec.a:mlpdsp.o:0000000000000324 t > ff_mlp_rematrix_channel_avx2_bmi2.shift > libavcodec/libavcodec.a:mlpdsp.o:0000000000000000 T > ff_mlp_rematrix_channel_sse4 > libavcodec/libavcodec.a:mlpdsp.o:00000000000000c0 t > ff_mlp_rematrix_channel_sse4.loop4 > libavcodec/libavcodec.a:mlpdsp.o:00000000000001c0 t > ff_mlp_rematrix_channel_sse4.loop4_shift > libavcodec/libavcodec.a:mlpdsp.o:0000000000000040 t > ff_mlp_rematrix_channel_sse4.loop8 > libavcodec/libavcodec.a:mlpdsp.o:0000000000000130 t > ff_mlp_rematrix_channel_sse4.loop8_shift > libavcodec/libavcodec.a:mlpdsp.o:0000000000000111 t > ff_mlp_rematrix_channel_sse4.shift > libavcodec/libavcodec.a:mlpdsp_init.o:00000000 T ff_mlpdsp_init_x86 > ``` > > Indeed, no ff_mlp_firorder symbols in libavcodec/x86/mlpdsp_init.o : > ``` > > nm -U libavcodec/x86/mlpdsp_init.o > 00000000 T ff_mlpdsp_init_x86 > ``` > > I extracted the build command for mlpdsp_init.o and ran it without the > `-flto` argument: > > ``` > > /opt/local/bin/clang-mp-17 -I. -I./ -isystem/opt/local/include > -D_ISOC11_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE > -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -I./compat/stdbit > -DZLIB_CONST -DHAVE_AV_CONFIG_H -DBUILDING_avcodec -Ofast -DHAVE_LRINTF > -Wno-deprecated-declarations -isystem/opt/local/include > -Wno-error=incompatible-pointer-types -march=westmere -msse4.1 -msse4.2 > -msse3 -mssse3 -msse2 -msse -mmmx -mpclmul -m64 -march=westmere -std=c17 > -fomit-frame-pointer -fPIC -pthread -I/opt/local/include/p11-kit-1 > -I/opt/local/include/fribidi -I/opt/local/include/freetype2 > -I/opt/local/include/libpng16 -I/opt/local/include/harfbuzz > -I/opt/local/include/glib-2.0 -I/opt/local/lib/glib-2.0/include > -I/opt/local/include/pcre2 -I/usr/include/freetype2 > -I/opt/local/include/libxml2 -I/opt/local/include/freetype2 > -I/opt/local/include/libpng16 -I/opt/local/include/harfbuzz > -I/opt/local/include/glib-2.0 -I/opt/local/lib/glib-2.0/include > -I/opt/local/include/pcre2 -I/usr/include/fr > eetype2 -I/opt/local/include/libdrm -I/opt/local/include/freetype2 > -I/opt/local/include/libpng16 -I/opt/local/include/harfbuzz > -I/opt/local/include/glib-2.0 -I/opt/local/lib/glib-2.0/include > -I/opt/local/include/pcre2 -I/usr/include/freetype2 > -I/opt/local/include/freetype2 -I/opt/local/include/libpng16 > -I/opt/local/include/harfbuzz -I/opt/local/include/glib-2.0 > -I/opt/local/lib/glib-2.0/include -I/opt/local/include/pcre2 > -I/opt/local/include/fribidi -I/opt/local/include/openjpeg-2.3 > -I/opt/local/include/opus -I/opt/local/include/opus -pthread > -I/opt/local/include/librsvg-2.0 -I/opt/local/include/gdk-pixbuf-2.0 > -I/opt/local/include/libmount -I/opt/local/include/blkid > -I/opt/local/include/uuid -I/opt/local/include/pcre > -I/opt/local/include/cairo -I/opt/local/include/pixman-1 > -I/opt/local/include/freetype2 -I/opt/local/include/harfbuzz > -I/opt/local/include/glib-2.0 -I/opt/local/lib/glib-2.0/include > -I/opt/local/include/pcre2 -I/opt/local/include/libdrm > -I/opt/local/include/libpng16 -I/ > usr/include/freetype2 -I/opt/local/include/samba-4.0 > -I/opt/local/include/libvmaf -I/opt/local/include/libdrm -g -Wall > -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings > -Wtype-limits -Wundef -Wempty-body -Wmissing-prototypes -Wstrict-prototypes > -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign > -Wno-unused-const-variable -Wno-bool-operation -Wno-char-subscripts > -Wno-implicit-const-int-float-conversion > -Wno-microsoft-enum-forward-reference -O3 -fno-math-errno -fno-signed-zeros > -mstack-alignment=16 -Qunused-arguments > -Werror=implicit-function-declaration -Werror=missing-prototypes > -Werror=return-type -MMD -MF libavcodec/x86/mlpdsp_init.d -MT > libavcodec/x86/mlpdsp_init.o -c -o libavcodec/x86/mlpdsp_init.o > libavcodec/x86/mlpdsp_init.c > > > nm -U libavcodec/x86/mlpdsp_init.o > 0000000000000000 T ff_mlpdsp_init_x86 > 00000000000000b1 t ff_mlp_firorder_0 > 00000000000000a7 t ff_mlp_firorder_1 > 0000000000000098 t ff_mlp_firorder_2 > 0000000000000089 t ff_mlp_firorder_3 > 000000000000007a t ff_mlp_firorder_4 > 000000000000006b t ff_mlp_firorder_5 > 000000000000005c t ff_mlp_firorder_6 > 000000000000004d t ff_mlp_firorder_7 > 000000000000003e t ff_mlp_firorder_8 > 00000000000000fc t ff_mlp_iirorder_0 > 00000000000000ea t ff_mlp_iirorder_1 > 00000000000000d8 t ff_mlp_iirorder_2 > 00000000000000c6 t ff_mlp_iirorder_3 > 00000000000000b4 t ff_mlp_iirorder_4 > 0000000000000000 d firtable > 0000000000000050 d iirtable > 0000000000000000 t mlp_filter_channel_x86 > ``` > > This suggests that the error is not with binutils/ld nor with the > provenance of ar and family, and it begs the question even more how I ever > got to build ffmpeg 8.0.1 with clang-17 AND LTO. The only logical > explanation that I can see right now is that I figured out the mlpdsp_init > build trick and then completely forgot about it (and that's not really > reassuring to accept either as this was back in mid April) ... > > Do you see any arguments in the clang invocation above that could explain > why clang suppresses the symbols from mlpdspinit.o? > > R. > _______________________________________________ > ffmpeg-devel mailing list -- [email protected] > To unsubscribe send an email to [email protected] Hi René, You hit the nail on the head. By isolating the compilation of mlpdsp_init.c with and without -flto, you've proven this isn't a linker or archive indexing issue; It's an LLVM IR visibility problem. To answer your question directly: it is exclusively the presence of the -flto argument that suppresses those symbols. None of the other flags in your invocation are responsible. Here is exactly why Clang's LTO drops them: The Opaque Assembly Problem: In libavcodec/x86/mlpdsp_init.c, FFmpeg defines the ff_mlp_firorder_* and ff_mlp_iirorder_* labels entirely inside an inline assembly block (__asm__). When you compile without -flto, the pipeline behaves normally: Clang generates LLVM IR, passes it to the backend, and hands it directly to the Integrated Assembler. The assembler parses the inline __asm__ text, recognizes the local labels, and embeds them properly into the resulting ELF object file's symbol table (which is why nm sees them in your test). When you compile with -flto, Clang stops short and emits LLVM IR (bitcode) instead of a native ELF object. Here is the fatal flaw: LLVM's IR optimizer cannot parse the inside of inline assembly blocks. To the compiler, an __asm__ block is just an opaque black box of text. Because the labels are hidden inside that black box, LLVM does not register them as globally or locally visible definitions at the IR level. Later, when the LTO pass performs whole-program optimization, it scans the C code, sees references to these symbols (like the pointers in the firtable and iirtable static arrays), and looks for their definitions. Finding no IR-level definitions, the optimizer assumes they are unresolved or dead code, and aggressively strips them out before the code is ever handed off to the assembler. The "Build Trick" You Likely Used in April: You mentioned that you suspect you figured out an mlpdsp_init build trick back in April and forgot it. Given how LLVM handles inline assembly during LTO, you almost certainly did one of two things: * Targeted Flag Override: You likely configured your build framework to append -fno-lto exclusively to the compilation flags for libavcodec/x86/mlpdsp_init.c. This forces Clang to compile just that specific file as a standard ELF object (preserving the symbols) while LTO optimizes the rest of the codebase. * Source Patching: You might have patched mlpdsp_init.c to explicitly tag the inline assembly operands or the referencing arrays with __attribute__((used)), forcing LLVM to keep them alive during the LTO pass. The most robust and least intrusive fix for your current framework is to re-implement the targeted override: instruct your build scripts to compile mlpdsp_init.c with -fno-lto. Does your framework have a quick way to isolate CFLAGS for a specific object file to test this? _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
