Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Check local label in add_dead_ends()

When update the latest upstream gcc and binutils, it generates more
objtool warnings on LoongArch, like this:

init/main.o: warning: objtool: unexpected relocation symbol type in .rela.discard.unreachable

We can see that the reloc sym name is local label instead of section in
relocation section '.rela.discard.unreachable', in this case, the reloc
sym type is STT_NOTYPE instead of STT_SECTION.

As suggested by Peter Zijlstra, we add a "local_label" member in struct
symbol, then set it as true if symbol type is STT_NOTYPE and symbol name
starts with ".L" string in classify_symbols().

Let's check reloc->sym->local_label to not return -1 in add_dead_ends(),
and also use reloc->sym->offset instead of reloc addend which is 0 to
find the corresponding instruction. At the same time, let's replace the
variable "addend" with "offset" to reflect the reality.

Here are some detailed info:
[fedora@linux 6.8.test]$ gcc --version
gcc (GCC) 14.0.1 20240129 (experimental)
[fedora@linux 6.8.test]$ as --version
GNU assembler (GNU Binutils) 2.42.50.20240129
[fedora@linux 6.8.test]$ readelf -r init/main.o | grep -A 2 "rela.discard.unreachable"
Relocation section '.rela.discard.unreachable' at offset 0x6028 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000000000 00d900000063 R_LARCH_32_PCREL 00000000000002c4 .L500^B1 + 0

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>

authored by

Tiezhu Yang and committed by
Huacai Chen
d5ab2bc3 3c7266cd

+24 -17
+23 -17
tools/objtool/check.c
··· 20 20 #include <linux/hashtable.h> 21 21 #include <linux/kernel.h> 22 22 #include <linux/static_call_types.h> 23 + #include <linux/string.h> 23 24 24 25 struct alternative { 25 26 struct alternative *next; ··· 585 584 struct section *rsec; 586 585 struct reloc *reloc; 587 586 struct instruction *insn; 588 - s64 addend; 587 + unsigned long offset; 589 588 590 589 /* 591 590 * Check for manually annotated dead ends. ··· 595 594 goto reachable; 596 595 597 596 for_each_reloc(rsec, reloc) { 598 - 599 - if (reloc->sym->type != STT_SECTION) { 597 + if (reloc->sym->type == STT_SECTION) { 598 + offset = reloc_addend(reloc); 599 + } else if (reloc->sym->local_label) { 600 + offset = reloc->sym->offset; 601 + } else { 600 602 WARN("unexpected relocation symbol type in %s", rsec->name); 601 603 return -1; 602 604 } 603 605 604 - addend = reloc_addend(reloc); 605 - 606 - insn = find_insn(file, reloc->sym->sec, addend); 606 + insn = find_insn(file, reloc->sym->sec, offset); 607 607 if (insn) 608 608 insn = prev_insn_same_sec(file, insn); 609 - else if (addend == reloc->sym->sec->sh.sh_size) { 609 + else if (offset == reloc->sym->sec->sh.sh_size) { 610 610 insn = find_last_insn(file, reloc->sym->sec); 611 611 if (!insn) { 612 612 WARN("can't find unreachable insn at %s+0x%" PRIx64, 613 - reloc->sym->sec->name, addend); 613 + reloc->sym->sec->name, offset); 614 614 return -1; 615 615 } 616 616 } else { 617 617 WARN("can't find unreachable insn at %s+0x%" PRIx64, 618 - reloc->sym->sec->name, addend); 618 + reloc->sym->sec->name, offset); 619 619 return -1; 620 620 } 621 621 ··· 635 633 return 0; 636 634 637 635 for_each_reloc(rsec, reloc) { 638 - 639 - if (reloc->sym->type != STT_SECTION) { 636 + if (reloc->sym->type == STT_SECTION) { 637 + offset = reloc_addend(reloc); 638 + } else if (reloc->sym->local_label) { 639 + offset = reloc->sym->offset; 640 + } else { 640 641 WARN("unexpected relocation symbol type in %s", rsec->name); 641 642 return -1; 642 643 } 643 644 644 - addend = reloc_addend(reloc); 645 - 646 - insn = find_insn(file, reloc->sym->sec, addend); 645 + insn = find_insn(file, reloc->sym->sec, offset); 647 646 if (insn) 648 647 insn = prev_insn_same_sec(file, insn); 649 - else if (addend == reloc->sym->sec->sh.sh_size) { 648 + else if (offset == reloc->sym->sec->sh.sh_size) { 650 649 insn = find_last_insn(file, reloc->sym->sec); 651 650 if (!insn) { 652 651 WARN("can't find reachable insn at %s+0x%" PRIx64, 653 - reloc->sym->sec->name, addend); 652 + reloc->sym->sec->name, offset); 654 653 return -1; 655 654 } 656 655 } else { 657 656 WARN("can't find reachable insn at %s+0x%" PRIx64, 658 - reloc->sym->sec->name, addend); 657 + reloc->sym->sec->name, offset); 659 658 return -1; 660 659 } 661 660 ··· 2525 2522 struct symbol *func; 2526 2523 2527 2524 for_each_sym(file, func) { 2525 + if (func->type == STT_NOTYPE && strstarts(func->name, ".L")) 2526 + func->local_label = true; 2527 + 2528 2528 if (func->bind != STB_GLOBAL) 2529 2529 continue; 2530 2530
+1
tools/objtool/include/objtool/elf.h
··· 67 67 u8 profiling_func : 1; 68 68 u8 warned : 1; 69 69 u8 embedded_insn : 1; 70 + u8 local_label : 1; 70 71 struct list_head pv_target; 71 72 struct reloc *relocs; 72 73 };