Commit 44f6a7c0 authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Peter Zijlstra

objtool: Fix seg fault with Clang non-section symbols

The Clang assembler likes to strip section symbols, which means objtool
can't reference some text code by its section.  This confuses objtool
greatly, causing it to seg fault.

The fix is similar to what was done before, for ORC reloc generation:

  e81e0724 ("objtool: Support Clang non-section symbols in ORC generation")

Factor out that code into a common helper and use it for static call
reloc generation as well.
Reported-by: default avatarArnd Bergmann <arnd@kernel.org>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: default avatarNick Desaulniers <ndesaulniers@google.com>
Reviewed-by: default avatarMiroslav Benes <mbenes@suse.cz>
Link: https://github.com/ClangBuiltLinux/linux/issues/1207
Link: https://lkml.kernel.org/r/ba6b6c0f0dd5acbba66e403955a967d9fdd1726a.1607983452.git.jpoimboe@redhat.com
parent 2c85ebc5
...@@ -467,13 +467,20 @@ static int create_static_call_sections(struct objtool_file *file) ...@@ -467,13 +467,20 @@ static int create_static_call_sections(struct objtool_file *file)
/* populate reloc for 'addr' */ /* populate reloc for 'addr' */
reloc = malloc(sizeof(*reloc)); reloc = malloc(sizeof(*reloc));
if (!reloc) { if (!reloc) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
memset(reloc, 0, sizeof(*reloc)); 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->type = R_X86_64_PC32;
reloc->offset = idx * sizeof(struct static_call_site); reloc->offset = idx * sizeof(struct static_call_site);
reloc->sec = reloc_sec; reloc->sec = reloc_sec;
......
...@@ -262,6 +262,32 @@ struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, uns ...@@ -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); 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) static int read_sections(struct elf *elf)
{ {
Elf_Scn *s = NULL; Elf_Scn *s = NULL;
......
...@@ -140,6 +140,8 @@ struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, uns ...@@ -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, struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
unsigned long offset, unsigned int len); unsigned long offset, unsigned int len);
struct symbol *find_func_containing(struct section *sec, unsigned long offset); 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); int elf_rebuild_reloc_section(struct elf *elf, struct section *sec);
#define for_each_sec(file, sec) \ #define for_each_sec(file, sec) \
......
...@@ -105,32 +105,13 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti ...@@ -105,32 +105,13 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti
} }
memset(reloc, 0, sizeof(*reloc)); memset(reloc, 0, sizeof(*reloc));
if (insn_sec->sym) { insn_to_reloc_sym_addend(insn_sec, insn_off, reloc);
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) { if (!reloc->sym) {
WARN("missing symbol for insn at offset 0x%lx\n", WARN("missing symbol for insn at offset 0x%lx",
insn_off); insn_off);
return -1; return -1;
} }
reloc->addend = insn_off - reloc->sym->offset;
}
reloc->type = R_X86_64_PC32; reloc->type = R_X86_64_PC32;
reloc->offset = idx * sizeof(int); reloc->offset = idx * sizeof(int);
reloc->sec = ip_relocsec; reloc->sec = ip_relocsec;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment