objtool: Fix seg fault with Clang non-section symbols
authorJosh Poimboeuf <jpoimboe@redhat.com>
Mon, 14 Dec 2020 22:04:20 +0000 (16:04 -0600)
committerPeter Zijlstra <peterz@infradead.org>
Wed, 16 Dec 2020 13:35:46 +0000 (14:35 +0100)
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:

  e81e07244325 ("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: Arnd Bergmann <arnd@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Link: https://github.com/ClangBuiltLinux/linux/issues/1207
Link: https://lkml.kernel.org/r/ba6b6c0f0dd5acbba66e403955a967d9fdd1726a.1607983452.git.jpoimboe@redhat.com
tools/objtool/check.c
tools/objtool/elf.c
tools/objtool/elf.h
tools/objtool/orc_gen.c

index c6ab44543c92aea9999010b17931ac4430a14331..5f8d3eed78a1869e3f294e27b7522508a82bf17c 100644 (file)
@@ -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;
index 4e1d7460574b4ab6a532f4e68fe0208b1e9eaf7a..be89c741ba9a09441e80566f370b7f44102d0c33 100644 (file)
@@ -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;
index 807f8c670097473b569ba015cb64e79c6f3da45d..e6890cc70a25bae7b0689e7254c7879a875498ae 100644 (file)
@@ -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)                                                \
index 235663b96adc7dbd73eb71ea268879d87072cf6f..9ce68b385a1b81f43789a86cb3720e3e9485348c 100644 (file)
@@ -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;