We have 4 instances of adding a relocation. Create a common helper to avoid growing even more.
Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org> --- tools/objtool/check.c | 76 ++++++---------------------- tools/objtool/elf.c | 90 +++++++++++++++++++++++----------- tools/objtool/include/objtool/check.h | 7 ++ tools/objtool/include/objtool/elf.h | 10 +++ tools/objtool/orc_gen.c | 57 ++++++++------------- 5 files changed, 119 insertions(+), 121 deletions(-) --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -433,8 +433,7 @@ static int add_dead_ends(struct objtool_ 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; @@ -460,8 +459,7 @@ static int create_static_call_sections(s if (!sec) return -1; - reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA); - if (!reloc_sec) + if (!elf_create_reloc_section(file->elf, sec, SHT_RELA)) return -1; idx = 0; @@ -471,26 +469,13 @@ static int create_static_call_sections(s memset(site, 0, sizeof(struct static_call_site)); /* populate reloc for 'addr' */ - reloc = malloc(sizeof(*reloc)); - - if (!reloc) { - perror("malloc"); - 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); + if (!elf_create_reloc(file->elf, sec, idx * sizeof(struct static_call_site), + R_X86_64_PC32, + reloc_to_insn, insn, 0)) { + WARN_ELF("elf_create_reloc: static_call_site::addr"); 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); if (!key_name) { @@ -526,18 +511,13 @@ static int create_static_call_sections(s free(key_name); /* populate reloc for 'key' */ - reloc = malloc(sizeof(*reloc)); - if (!reloc) { - perror("malloc"); + if (!elf_create_reloc(file->elf, sec, idx * sizeof(struct static_call_site) + 4, + R_X86_64_PC32, + reloc_to_sym, key_sym, + is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) { + WARN_ELF("elf_create_reloc: static_call_site::key"); 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 +527,7 @@ static int create_static_call_sections(s 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,8 +550,7 @@ static int create_mcount_loc_sections(st if (!sec) return -1; - reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA); - if (!reloc_sec) + if (!elf_create_reloc_section(file->elf, sec, SHT_RELA)) return -1; idx = 0; @@ -581,32 +559,12 @@ static int create_mcount_loc_sections(st loc = (unsigned long *)sec->data->d_buf + idx; memset(loc, 0, sizeof(unsigned long)); - reloc = malloc(sizeof(*reloc)); - if (!reloc) { - perror("malloc"); + if (!elf_create_reloc(file->elf, sec, idx * sizeof(unsigned long), + R_X86_64_64, + reloc_to_insn, insn, 0)) { + WARN_ELF("elf_create_reloc: __mcount_loc"); 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++; } --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -211,32 +211,6 @@ struct reloc *find_reloc_by_dest(const s 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; @@ -473,7 +447,7 @@ static int read_symbols(struct elf *elf) return -1; } -void elf_add_reloc(struct elf *elf, struct reloc *reloc) +static void elf_add_reloc(struct elf *elf, struct reloc *reloc) { struct section *sec = reloc->sec; @@ -483,6 +457,68 @@ void elf_add_reloc(struct elf *elf, stru sec->changed = true; } +void reloc_to_sym(struct reloc *reloc, void *dst) +{ + struct symbol *sym = dst; + reloc->sym = sym; +} + +void __reloc_to_insn(struct reloc *reloc, struct section *sec, unsigned long offset) +{ + 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; +} + +struct reloc *elf_create_reloc(struct elf *elf, + struct section *sec, unsigned long offset, + unsigned int type, + void (*set_dest)(struct reloc *, void *), void *dst, int addend) +{ + struct reloc *reloc; + + reloc = malloc(sizeof(*reloc)); + if (!reloc) { + perror("malloc"); + return NULL; + } + memset(reloc, 0, sizeof(*reloc)); + + reloc->sec = sec->reloc; + reloc->offset = offset; + reloc->type = type; + + set_dest(reloc, dst); + if (!reloc->sym) { + WARN("failed to create reloc"); + return NULL; + } + + reloc->addend += addend; + + elf_add_reloc(elf, reloc); + + return reloc; +} + static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx) { if (!gelf_getrel(sec->data, i, &reloc->rel)) { --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -9,6 +9,7 @@ #include <stdbool.h> #include <objtool/cfi.h> #include <objtool/arch.h> +#include <objtool/elf.h> struct insn_state { struct cfi_state cfi; @@ -91,4 +92,10 @@ struct instruction *find_insn(struct obj insn->sec == sec; \ insn = list_next_entry(insn, list)) +static inline void reloc_to_insn(struct reloc *reloc, void *dst) +{ + struct instruction *insn = dst; + __reloc_to_insn(reloc, insn->sec, insn->offset); +} + #endif /* _CHECK_H */ --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -123,7 +123,15 @@ static inline u32 reloc_hash(struct relo struct elf *elf_open_read(const char *name, int flags); struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr); struct section *elf_create_reloc_section(struct elf *elf, struct section *base, int reltype); -void elf_add_reloc(struct elf *elf, struct reloc *reloc); + +void reloc_to_sym(struct reloc *reloc, void *sym); +void __reloc_to_insn(struct reloc *reloc, struct section *sec, unsigned long offset); + +struct reloc *elf_create_reloc(struct elf *elf, + struct section *sec, unsigned long offset, + unsigned int type, + void (*set_dest)(struct reloc *reloc, void *), void *dst, int addend); + int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset, unsigned int len, const char *insn); --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -81,13 +81,25 @@ static int init_orc_entry(struct orc_ent return 0; } +struct orc_list_entry { + struct list_head list; + struct orc_entry orc; + struct section *insn_sec; + unsigned long insn_off; +}; + +static void reloc_to_orc(struct reloc *reloc, void *dst) +{ + struct orc_list_entry *entry = dst; + __reloc_to_insn(reloc, entry->insn_sec, entry->insn_off); +} + static int write_orc_entry(struct elf *elf, struct section *orc_sec, - struct section *ip_rsec, unsigned int idx, - struct section *insn_sec, unsigned long insn_off, - struct orc_entry *o) + struct section *ip_sec, unsigned int idx, + struct orc_list_entry *entry) { + struct orc_entry *o = &entry->orc; struct orc_entry *orc; - struct reloc *reloc; /* populate ORC data */ orc = (struct orc_entry *)orc_sec->data->d_buf + idx; @@ -96,36 +108,16 @@ static int write_orc_entry(struct elf *e orc->bp_offset = bswap_if_needed(orc->bp_offset); /* populate reloc for ip */ - reloc = malloc(sizeof(*reloc)); - if (!reloc) { - perror("malloc"); - return -1; - } - memset(reloc, 0, sizeof(*reloc)); - - insn_to_reloc_sym_addend(insn_sec, insn_off, reloc); - if (!reloc->sym) { - WARN("missing symbol for insn at offset 0x%lx", - insn_off); + if (!elf_create_reloc(elf, ip_sec, idx * sizeof(int), + R_X86_64_PC32, + reloc_to_orc, entry, 0)) { + WARN_ELF("elf_create_reloc: ORC ip"); return -1; } - reloc->type = R_X86_64_PC32; - reloc->offset = idx * sizeof(int); - reloc->sec = ip_rsec; - - elf_add_reloc(elf, reloc); - return 0; } -struct orc_list_entry { - struct list_head list; - struct orc_entry orc; - struct section *insn_sec; - unsigned long insn_off; -}; - static int orc_list_add(struct list_head *orc_list, struct orc_entry *orc, struct section *sec, unsigned long offset) { @@ -153,7 +145,7 @@ static unsigned long alt_group_len(struc int orc_create(struct objtool_file *file) { - struct section *sec, *ip_rsec, *orc_sec; + struct section *sec, *orc_sec; unsigned int nr = 0, idx = 0; struct orc_list_entry *entry; struct list_head orc_list; @@ -242,15 +234,12 @@ int orc_create(struct objtool_file *file sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), nr); if (!sec) return -1; - ip_rsec = elf_create_reloc_section(file->elf, sec, SHT_RELA); - if (!ip_rsec) + if (!elf_create_reloc_section(file->elf, sec, SHT_RELA)) return -1; /* Write ORC entries to sections: */ list_for_each_entry(entry, &orc_list, list) { - if (write_orc_entry(file->elf, orc_sec, ip_rsec, idx++, - entry->insn_sec, entry->insn_off, - &entry->orc)) + if (write_orc_entry(file->elf, orc_sec, sec, idx++, entry)) return -1; }