From: Peter Zijlstra <peterz@infradead.org> Date: Thu, 18 Jun 2020 15:55:29 +0000 (+0200) Subject: Merge branch 'objtool/urgent' into objtool/core X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=d832c0051f4e9cc7d26ef3bc6e9b662bc6a90f3a;p=linux.git Merge branch 'objtool/urgent' into objtool/core Conflicts: tools/objtool/elf.c tools/objtool/elf.h tools/objtool/orc_gen.c tools/objtool/check.c Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> --- d832c0051f4e9cc7d26ef3bc6e9b662bc6a90f3a diff --cc tools/objtool/arch.h index d0969a9328c2d,3c5967748abb9..2e2ce089b0e9e --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@@ -82,6 -82,8 +82,8 @@@ bool arch_callee_saved_reg(unsigned cha unsigned long arch_jump_destination(struct instruction *insn); -unsigned long arch_dest_rela_offset(int addend); +unsigned long arch_dest_reloc_offset(int addend); + const char *arch_nop_insn(int len); + #endif /* _ARCH_H */ diff --cc tools/objtool/check.c index 559c1baf9fc51,478267a072d08..a2313ecce6d18 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@@ -763,8 -764,26 +764,26 @@@ static int add_call_destinations(struc return -1; } } else - insn->call_dest = rela->sym; + insn->call_dest = reloc->sym; + /* + * Many compilers cannot disable KCOV with a function attribute + * so they need a little help, NOP out any KCOV calls from noinstr + * text. + */ + if (insn->sec->noinstr && + !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) { - if (rela) { - rela->type = R_NONE; - elf_write_rela(file->elf, rela); ++ if (reloc) { ++ reloc->type = R_NONE; ++ elf_write_reloc(file->elf, reloc); + } + + elf_write_insn(file->elf, insn->sec, + insn->offset, insn->len, + arch_nop_insn(insn->len)); + insn->type = INSN_NOP; + } + /* * Whatever stack impact regular CALLs have, should be undone * by the RETURN of the called function. diff --cc tools/objtool/elf.c index 95d86bcb95122,26d11d8219418..3ddbd66f1a376 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@@ -551,22 -518,22 +551,24 @@@ static int read_relocs(struct elf *elf perror("malloc"); return -1; } - memset(rela, 0, sizeof(*rela)); - - if (!gelf_getrela(sec->data, i, &rela->rela)) { - WARN_ELF("gelf_getrela"); - return -1; + memset(reloc, 0, sizeof(*reloc)); + switch (sec->sh.sh_type) { + case SHT_REL: + if (read_rel_reloc(sec, i, reloc, &symndx)) + return -1; + break; + case SHT_RELA: + if (read_rela_reloc(sec, i, reloc, &symndx)) + return -1; + break; + default: return -1; } - reloc->sym = find_symbol_by_index(elf, symndx); + - rela->type = GELF_R_TYPE(rela->rela.r_info); - rela->addend = rela->rela.r_addend; - rela->offset = rela->rela.r_offset; - symndx = GELF_R_SYM(rela->rela.r_info); - rela->sec = sec; - rela->idx = i; - rela->sym = find_symbol_by_index(elf, symndx); - if (!rela->sym) { - WARN("can't find rela entry symbol %d for %s", + reloc->sec = sec; ++ reloc->idx = i; ++ reloc->sym = find_symbol_by_index(elf, symndx); + if (!reloc->sym) { + WARN("can't find reloc entry symbol %d for %s", symndx, sec->name); return -1; } @@@ -880,23 -785,44 +884,73 @@@ static int elf_rebuild_rela_reloc_secti return 0; } - int elf_rebuild_reloc_section(struct section *sec) ++int elf_rebuild_reloc_section(struct elf *elf, struct section *sec) +{ + struct reloc *reloc; + int nr; + ++ sec->changed = true; ++ elf->changed = true; ++ + nr = 0; + list_for_each_entry(reloc, &sec->reloc_list, list) + nr++; + + switch (sec->sh.sh_type) { + case SHT_REL: return elf_rebuild_rel_reloc_section(sec, nr); + case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr); + default: return -1; + } +} + - int elf_write(const struct elf *elf) + int elf_write_insn(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int len, + const char *insn) + { + Elf_Data *data = sec->data; + + if (data->d_type != ELF_T_BYTE || data->d_off) { + WARN("write to unexpected data for section: %s", sec->name); + return -1; + } + + memcpy(data->d_buf + offset, insn, len); + elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY); + + elf->changed = true; + + return 0; + } + -int elf_write_rela(struct elf *elf, struct rela *rela) ++int elf_write_reloc(struct elf *elf, struct reloc *reloc) + { - struct section *sec = rela->sec; ++ struct section *sec = reloc->sec; + - rela->rela.r_info = GELF_R_INFO(rela->sym->idx, rela->type); - rela->rela.r_addend = rela->addend; - rela->rela.r_offset = rela->offset; ++ if (sec->sh.sh_type == SHT_REL) { ++ reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); ++ reloc->rel.r_offset = reloc->offset; + - if (!gelf_update_rela(sec->data, rela->idx, &rela->rela)) { - WARN_ELF("gelf_update_rela"); - return -1; ++ if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) { ++ WARN_ELF("gelf_update_rel"); ++ return -1; ++ } ++ } else { ++ reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); ++ reloc->rela.r_addend = reloc->addend; ++ reloc->rela.r_offset = reloc->offset; ++ ++ if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) { ++ WARN_ELF("gelf_update_rela"); ++ return -1; ++ } + } + + elf->changed = true; + + return 0; + } + + int elf_write(struct elf *elf) { struct section *sec; Elf_Scn *s; diff --cc tools/objtool/elf.h index 78a2db23b8b6f,7324e772583ee..6cc80a0751668 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@@ -58,18 -58,16 +58,19 @@@ struct symbol bool uaccess_safe; }; -struct rela { +struct reloc { struct list_head list; struct hlist_node hash; - GElf_Rela rela; + union { + GElf_Rela rela; + GElf_Rel rel; + }; struct section *sec; struct symbol *sym; - unsigned int type; unsigned long offset; + unsigned int type; int addend; + int idx; bool jump_table_start; }; @@@ -119,9 -118,13 +121,13 @@@ static inline u32 reloc_hash(struct rel struct elf *elf_open_read(const char *name, int flags); struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr); -struct section *elf_create_rela_section(struct elf *elf, struct section *base); -void elf_add_rela(struct elf *elf, struct rela *rela); +struct section *elf_create_reloc_section(struct elf *elf, struct section *base, int reltype); +void elf_add_reloc(struct elf *elf, struct reloc *reloc); - int elf_write(const struct elf *elf); + int elf_write_insn(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int len, + const char *insn); -int elf_write_rela(struct elf *elf, struct rela *rela); ++int elf_write_reloc(struct elf *elf, struct reloc *reloc); + int elf_write(struct elf *elf); void elf_close(struct elf *elf); struct section *find_section_by_name(const struct elf *elf, const char *name); @@@ -129,11 -132,11 +135,11 @@@ struct symbol *find_func_by_offset(stru struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); -struct rela *find_rela_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); -struct rela *find_rela_by_dest_range(const struct elf *elf, struct section *sec, +struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); +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); - int elf_rebuild_reloc_section(struct section *sec); -int elf_rebuild_rela_section(struct elf *elf, struct section *sec); ++int elf_rebuild_reloc_section(struct elf *elf, struct section *sec); #define for_each_sec(file, sec) \ list_for_each_entry(sec, &file->elf->sections, list) diff --cc tools/objtool/orc_gen.c index 75e08cf0709b4,4c37f80eb987f..968f55e6dd94d --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@@ -222,7 -222,7 +222,7 @@@ int create_orc_sections(struct objtool_ } } - if (elf_rebuild_reloc_section(ip_relocsec)) - if (elf_rebuild_rela_section(file->elf, ip_relasec)) ++ if (elf_rebuild_reloc_section(file->elf, ip_relocsec)) return -1; return 0;