[GIT PULL] objtool fix

Ingo Molnar
2020-12-27T09:32:06Z

Linus,

Please pull the latest objtool/urgent git tree from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git objtool-urgent-2020-12-27

# HEAD: 44f6a7c0755d8dd453c70557e11687bb080a6f21 objtool: Fix seg fault with Clang non-section symbols

Fix a segfault that occurs when built with Clang.

Thanks,

Ingo

------------------>
Josh Poimboeuf (1):
objtool: Fix seg fault with Clang non-section symbols

tools/objtool/check.c | 11 +++++++++--
tools/objtool/elf.c | 26 ++++++++++++++++++++++++++
tools/objtool/elf.h | 2 ++
tools/objtool/orc_gen.c | 29 +++++------------------------
4 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index c6ab44543c92..5f8d3eed78a1 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -467,13 +467,20 @@ static int create_static_call_sections(struct objtool_file *file)

/* populate reloc for 'addr' */
reloc = malloc(sizeof(*reloc));
+
if (!reloc) {
perror("malloc");
return -1;
}
memset(reloc, 0, sizeof(*reloc));
- reloc->sym = insn->sec->sym;
- reloc->addend = insn->offset;
+
+ insn_to_reloc_sym_addend(insn->sec, insn->offset, reloc);
+ if (!reloc->sym) {
+ WARN_FUNC("static call tramp: missing containing symbol",
+ insn->sec, insn->offset);
+ return -1;
+ }
+
reloc->type = R_X86_64_PC32;
reloc->offset = idx * sizeof(struct static_call_site);
reloc->sec = reloc_sec;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 4e1d7460574b..be89c741ba9a 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -262,6 +262,32 @@ struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, uns
return find_reloc_by_dest_range(elf, sec, offset, 1);
}

+void insn_to_reloc_sym_addend(struct section *sec, unsigned long offset,
+ struct reloc *reloc)
+{
+ if (sec->sym) {
+ reloc->sym = sec->sym;
+ reloc->addend = offset;
+ return;
+ }
+
+ /*
+ * The Clang assembler strips section symbols, so we have to reference
+ * the function symbol instead:
+ */
+ reloc->sym = find_symbol_containing(sec, offset);
+ if (!reloc->sym) {
+ /*
+ * Hack alert. This happens when we need to reference the NOP
+ * pad insn immediately after the function.
+ */
+ reloc->sym = find_symbol_containing(sec, offset - 1);
+ }
+
+ if (reloc->sym)
+ reloc->addend = offset - reloc->sym->offset;
+}
+
static int read_sections(struct elf *elf)
{
Elf_Scn *s = NULL;
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index 807f8c670097..e6890cc70a25 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -140,6 +140,8 @@ struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, uns
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
unsigned long offset, unsigned int len);
struct symbol *find_func_containing(struct section *sec, unsigned long offset);
+void insn_to_reloc_sym_addend(struct section *sec, unsigned long offset,
+ struct reloc *reloc);
int elf_rebuild_reloc_section(struct elf *elf, struct section *sec);

#define for_each_sec(file, sec) \
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c
index 235663b96adc..9ce68b385a1b 100644
--- a/tools/objtool/orc_gen.c
+++ b/tools/objtool/orc_gen.c
@@ -105,30 +105,11 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti
}
memset(reloc, 0, sizeof(*reloc));

- if (insn_sec->sym) {
- reloc->sym = insn_sec->sym;
- reloc->addend = insn_off;
- } else {
- /*
- * The Clang assembler doesn't produce section symbols, so we
- * have to reference the function symbol instead:
- */
- reloc->sym = find_symbol_containing(insn_sec, insn_off);
- if (!reloc->sym) {
- /*
- * Hack alert. This happens when we need to reference
- * the NOP pad insn immediately after the function.
- */
- reloc->sym = find_symbol_containing(insn_sec,
- insn_off - 1);
- }
- if (!reloc->sym) {
- WARN("missing symbol for insn at offset 0x%lx\n",
- insn_off);
- return -1;
- }
-
- reloc->addend = insn_off - reloc->sym->offset;
+ insn_to_reloc_sym_addend(insn_sec, insn_off, reloc);
+ if (!reloc->sym) {
+ WARN("missing symbol for insn at offset 0x%lx",
+ insn_off);
+ return -1;
}

reloc->type = R_X86_64_PC32;