objtool/klp: Fix symbol correlation for orphaned local symbols

When compiling with CONFIG_LTO_CLANG_THIN, vmlinux.o has
__irf_[start|end] before the first FILE entry:

$ readelf -sW vmlinux.o
Symbol table '.symtab' contains 597706 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE LOCAL DEFAULT 18 __irf_start
2: 0000000000000200 0 NOTYPE LOCAL DEFAULT 18 __irf_end
3: 0000000000000000 0 SECTION LOCAL DEFAULT 17 .text
4: 0000000000000000 0 SECTION LOCAL DEFAULT 18 .init.ramfs

This causes klp-build warnings like:

vmlinux.o: warning: objtool: no correlation: __irf_start
vmlinux.o: warning: objtool: no correlation: __irf_end

The problem is that Clang LTO is stripping the initramfs_data.o FILE
symbol, causing those two symbols to be orphaned and not noticed by
klp-diff's correlation logic. Add a loop to correlate any symbols found
before the first FILE symbol.

Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Reported-by: Song Liu <song@kernel.org>
Acked-by: Song Liu <song@kernel.org>
Link: https://patch.msgid.link/e21ec1141fc749b5f538d7329b531c1ab63a6d1a.1770055235.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

+34 -5
+34 -5
tools/objtool/klp-diff.c
··· 364 364 struct symbol *file1_sym, *file2_sym; 365 365 struct symbol *sym1, *sym2; 366 366 367 - /* Correlate locals */ 368 - for (file1_sym = first_file_symbol(e->orig), 369 - file2_sym = first_file_symbol(e->patched); ; 370 - file1_sym = next_file_symbol(e->orig, file1_sym), 371 - file2_sym = next_file_symbol(e->patched, file2_sym)) { 367 + file1_sym = first_file_symbol(e->orig); 368 + file2_sym = first_file_symbol(e->patched); 369 + 370 + /* 371 + * Correlate any locals before the first FILE symbol. This has been 372 + * seen when LTO inexplicably strips the initramfs_data.o FILE symbol 373 + * due to the file only containing data and no code. 374 + */ 375 + for_each_sym(e->orig, sym1) { 376 + if (sym1 == file1_sym || !is_local_sym(sym1)) 377 + break; 378 + 379 + if (dont_correlate(sym1)) 380 + continue; 381 + 382 + for_each_sym(e->patched, sym2) { 383 + if (sym2 == file2_sym || !is_local_sym(sym2)) 384 + break; 385 + 386 + if (sym2->twin || dont_correlate(sym2)) 387 + continue; 388 + 389 + if (strcmp(sym1->demangled_name, sym2->demangled_name)) 390 + continue; 391 + 392 + sym1->twin = sym2; 393 + sym2->twin = sym1; 394 + break; 395 + } 396 + } 397 + 398 + /* Correlate locals after the first FILE symbol */ 399 + for (; ; file1_sym = next_file_symbol(e->orig, file1_sym), 400 + file2_sym = next_file_symbol(e->patched, file2_sym)) { 372 401 373 402 if (!file1_sym && file2_sym) { 374 403 ERROR("FILE symbol mismatch: NULL != %s", file2_sym->name);