return -1;
}
} else
- insn->call_dest = rela->sym;
+ insn->call_dest = reloc->sym;
- if (rela) {
- rela->type = R_NONE;
- elf_write_rela(file->elf, rela);
+ /*
+ * 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 (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.
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;
}
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;
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;
};
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);
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)