objtool: Keep track of retpoline call sites
[linux-2.6-microblaze.git] / tools / objtool / check.c
index 1d0415b..77074db 100644 (file)
@@ -433,8 +433,7 @@ reachable:
 
 static int create_static_call_sections(struct objtool_file *file)
 {
-       struct section *sec, *reloc_sec;
-       struct reloc *reloc;
+       struct section *sec;
        struct static_call_site *site;
        struct instruction *insn;
        struct symbol *key_sym;
@@ -452,7 +451,7 @@ static int create_static_call_sections(struct objtool_file *file)
                return 0;
 
        idx = 0;
-       list_for_each_entry(insn, &file->static_call_list, static_call_node)
+       list_for_each_entry(insn, &file->static_call_list, call_node)
                idx++;
 
        sec = elf_create_section(file->elf, ".static_call_sites", SHF_WRITE,
@@ -460,36 +459,18 @@ static int create_static_call_sections(struct objtool_file *file)
        if (!sec)
                return -1;
 
-       reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
-       if (!reloc_sec)
-               return -1;
-
        idx = 0;
-       list_for_each_entry(insn, &file->static_call_list, static_call_node) {
+       list_for_each_entry(insn, &file->static_call_list, call_node) {
 
                site = (struct static_call_site *)sec->data->d_buf + idx;
                memset(site, 0, sizeof(struct static_call_site));
 
                /* populate reloc for 'addr' */
-               reloc = malloc(sizeof(*reloc));
-
-               if (!reloc) {
-                       perror("malloc");
+               if (elf_add_reloc_to_insn(file->elf, sec,
+                                         idx * sizeof(struct static_call_site),
+                                         R_X86_64_PC32,
+                                         insn->sec, insn->offset))
                        return -1;
-               }
-               memset(reloc, 0, sizeof(*reloc));
-
-               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;
-               elf_add_reloc(file->elf, reloc);
 
                /* find key symbol */
                key_name = strdup(insn->call_dest->name);
@@ -526,18 +507,11 @@ static int create_static_call_sections(struct objtool_file *file)
                free(key_name);
 
                /* populate reloc for 'key' */
-               reloc = malloc(sizeof(*reloc));
-               if (!reloc) {
-                       perror("malloc");
+               if (elf_add_reloc(file->elf, sec,
+                                 idx * sizeof(struct static_call_site) + 4,
+                                 R_X86_64_PC32, key_sym,
+                                 is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
                        return -1;
-               }
-               memset(reloc, 0, sizeof(*reloc));
-               reloc->sym = key_sym;
-               reloc->addend = is_sibling_call(insn) ? STATIC_CALL_SITE_TAIL : 0;
-               reloc->type = R_X86_64_PC32;
-               reloc->offset = idx * sizeof(struct static_call_site) + 4;
-               reloc->sec = reloc_sec;
-               elf_add_reloc(file->elf, reloc);
 
                idx++;
        }
@@ -547,8 +521,7 @@ static int create_static_call_sections(struct objtool_file *file)
 
 static int create_mcount_loc_sections(struct objtool_file *file)
 {
-       struct section *sec, *reloc_sec;
-       struct reloc *reloc;
+       struct section *sec;
        unsigned long *loc;
        struct instruction *insn;
        int idx;
@@ -571,42 +544,17 @@ static int create_mcount_loc_sections(struct objtool_file *file)
        if (!sec)
                return -1;
 
-       reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
-       if (!reloc_sec)
-               return -1;
-
        idx = 0;
        list_for_each_entry(insn, &file->mcount_loc_list, mcount_loc_node) {
 
                loc = (unsigned long *)sec->data->d_buf + idx;
                memset(loc, 0, sizeof(unsigned long));
 
-               reloc = malloc(sizeof(*reloc));
-               if (!reloc) {
-                       perror("malloc");
+               if (elf_add_reloc_to_insn(file->elf, sec,
+                                         idx * sizeof(unsigned long),
+                                         R_X86_64_64,
+                                         insn->sec, insn->offset))
                        return -1;
-               }
-               memset(reloc, 0, sizeof(*reloc));
-
-               if (insn->sec->sym) {
-                       reloc->sym = insn->sec->sym;
-                       reloc->addend = insn->offset;
-               } else {
-                       reloc->sym = find_symbol_containing(insn->sec, insn->offset);
-
-                       if (!reloc->sym) {
-                               WARN("missing symbol for insn at offset 0x%lx\n",
-                                    insn->offset);
-                               return -1;
-                       }
-
-                       reloc->addend = insn->offset - reloc->sym->offset;
-               }
-
-               reloc->type = R_X86_64_64;
-               reloc->offset = idx * sizeof(unsigned long);
-               reloc->sec = reloc_sec;
-               elf_add_reloc(file->elf, reloc);
 
                idx++;
        }
@@ -881,13 +829,16 @@ static int add_jump_destinations(struct objtool_file *file)
                        else
                                insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
 
+                       list_add_tail(&insn->call_node,
+                                     &file->retpoline_call_list);
+
                        insn->retpoline_safe = true;
                        continue;
                } else if (insn->func) {
                        /* internal or external sibling call (with reloc) */
                        insn->call_dest = reloc->sym;
                        if (insn->call_dest->static_call_tramp) {
-                               list_add_tail(&insn->static_call_node,
+                               list_add_tail(&insn->call_node,
                                              &file->static_call_list);
                        }
                        continue;
@@ -949,7 +900,7 @@ static int add_jump_destinations(struct objtool_file *file)
                                /* internal sibling call (without reloc) */
                                insn->call_dest = insn->jump_dest->func;
                                if (insn->call_dest->static_call_tramp) {
-                                       list_add_tail(&insn->static_call_node,
+                                       list_add_tail(&insn->call_node,
                                                      &file->static_call_list);
                                }
                        }
@@ -1033,6 +984,9 @@ static int add_call_destinations(struct objtool_file *file)
                        insn->type = INSN_CALL_DYNAMIC;
                        insn->retpoline_safe = true;
 
+                       list_add_tail(&insn->call_node,
+                                     &file->retpoline_call_list);
+
                        remove_insn_ops(insn);
                        continue;
 
@@ -1040,7 +994,7 @@ static int add_call_destinations(struct objtool_file *file)
                        insn->call_dest = reloc->sym;
 
                if (insn->call_dest && insn->call_dest->static_call_tramp) {
-                       list_add_tail(&insn->static_call_node,
+                       list_add_tail(&insn->call_node,
                                      &file->static_call_list);
                }
 
@@ -1766,6 +1720,11 @@ static void mark_rodata(struct objtool_file *file)
        file->rodata = found;
 }
 
+__weak int arch_rewrite_retpolines(struct objtool_file *file)
+{
+       return 0;
+}
+
 static int decode_sections(struct objtool_file *file)
 {
        int ret;
@@ -1794,6 +1753,10 @@ static int decode_sections(struct objtool_file *file)
        if (ret)
                return ret;
 
+       /*
+        * Must be before add_special_section_alts() as that depends on
+        * jump_dest being set.
+        */
        ret = add_jump_destinations(file);
        if (ret)
                return ret;
@@ -1830,6 +1793,15 @@ static int decode_sections(struct objtool_file *file)
        if (ret)
                return ret;
 
+       /*
+        * Must be after add_special_section_alts(), since this will emit
+        * alternatives. Must be after add_{jump,call}_destination(), since
+        * those create the call insn lists.
+        */
+       ret = arch_rewrite_retpolines(file);
+       if (ret)
+               return ret;
+
        return 0;
 }