summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@kernel.org>2025-11-20 12:52:16 -0800
committerPeter Zijlstra <peterz@infradead.org>2025-11-21 10:04:07 +0100
commit2c2acca2eabf53a954ed5aacef987bbf909b9f12 (patch)
tree3c331b7468ad182555b258fedd6bcf99478410d5
parent024020e2b6adb4e568fb80f624b5e20d8943f107 (diff)
objtool: Fix .cold function detection for duplicate symbols
The objtool .cold child/parent correlation is done in two phases: first in elf_add_symbol() and later in add_jump_destinations(). The first phase is rather crude and can pick the wrong parent if there are duplicates with the same name. The second phase usually fixes that, but only if the parent has a direct jump to the child. It does *not* work if the only branch from the parent to the child is an alternative or jump table entry. Make the first phase more robust by looking for the parent in the same STT_FILE as the child. Fixes the following objtool warnings in an AutoFDO build with a large CLANG_AUTOFDO_PROFILE profile: vmlinux.o: warning: objtool: rdev_add_key() falls through to next function rdev_add_key.cold() vmlinux.o: warning: objtool: rdev_set_default_key() falls through to next function rdev_set_default_key.cold() Fixes: 13810435b9a7 ("objtool: Support GCC 8's cold subfunctions") Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/82c7b52e40efa75dd10e1c550cc75c1ce10ac2c9.1763671318.git.jpoimboe@kernel.org
-rw-r--r--tools/objtool/elf.c28
-rw-r--r--tools/objtool/include/objtool/elf.h2
2 files changed, 27 insertions, 3 deletions
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 7895f65aca2a..fffca31d47ed 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -288,6 +288,23 @@ struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
return NULL;
}
+/* Find local symbol with matching STT_FILE */
+static struct symbol *find_local_symbol_by_file_and_name(const struct elf *elf,
+ struct symbol *file,
+ const char *name)
+{
+ struct symbol *sym;
+
+ elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(name)) {
+ if (sym->bind == STB_LOCAL && sym->file == file &&
+ !strcmp(sym->name, name)) {
+ return sym;
+ }
+ }
+
+ return NULL;
+}
+
struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *name)
{
struct symbol *sym;
@@ -524,7 +541,7 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym)
static int read_symbols(struct elf *elf)
{
struct section *symtab, *symtab_shndx, *sec;
- struct symbol *sym, *pfunc;
+ struct symbol *sym, *pfunc, *file = NULL;
int symbols_nr, i;
char *coldstr;
Elf_Data *shndx_data = NULL;
@@ -597,6 +614,11 @@ static int read_symbols(struct elf *elf)
if (elf_add_symbol(elf, sym))
return -1;
+
+ if (sym->type == STT_FILE)
+ file = sym;
+ else if (sym->bind == STB_LOCAL)
+ sym->file = file;
}
if (opts.stats) {
@@ -626,7 +648,9 @@ static int read_symbols(struct elf *elf)
return -1;
}
- pfunc = find_symbol_by_name(elf, pname);
+ pfunc = find_local_symbol_by_file_and_name(elf, sym->file, pname);
+ if (!pfunc)
+ pfunc = find_global_symbol_by_name(elf, pname);
free(pname);
if (!pfunc) {
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 21d8b825fd8f..e12c516bd320 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -69,7 +69,7 @@ struct symbol {
unsigned int idx, len;
unsigned long offset;
unsigned long __subtree_last;
- struct symbol *pfunc, *cfunc, *alias;
+ struct symbol *pfunc, *cfunc, *alias, *file;
unsigned char bind, type;
u8 uaccess_safe : 1;
u8 static_call_tramp : 1;