@@ -952,7 +952,7 @@ static int create_cfi_sections(struct objtool_file *file)
static int create_mcount_loc_sections(struct objtool_file *file)
{
- int addrsize = elf_class_addrsize(file->elf);
+ size_t addr_size = elf_addr_size(file->elf);
struct instruction *insn;
struct section *sec;
int idx;
@@ -971,25 +971,25 @@ static int create_mcount_loc_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->mcount_loc_list, call_node)
idx++;
- sec = elf_create_section(file->elf, "__mcount_loc", addrsize, idx);
+ sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx);
if (!sec)
return -1;
- sec->sh.sh_addralign = addrsize;
+ sec->sh.sh_addralign = addr_size;
idx = 0;
list_for_each_entry(insn, &file->mcount_loc_list, call_node) {
void *loc;
loc = sec->data->d_buf + idx;
- memset(loc, 0, addrsize);
+ memset(loc, 0, addr_size);
if (elf_add_reloc_to_insn(file->elf, sec, idx,
- addrsize == sizeof(u64) ? R_ABS64 : R_ABS32,
+ addr_size == sizeof(u64) ? R_ABS64 : R_ABS32,
insn->sec, insn->offset))
return -1;
- idx += addrsize;
+ idx += addr_size;
}
return 0;
@@ -533,16 +533,15 @@ err:
return -1;
}
-static struct section *elf_create_reloc_section(struct elf *elf,
- struct section *sec,
- int reltype);
+static struct section *elf_create_rela_section(struct elf *elf,
+ struct section *sec);
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
unsigned int type, struct symbol *sym, s64 addend)
{
struct reloc *reloc;
- if (!sec->rsec && !elf_create_reloc_section(elf, sec, SHT_RELA))
+ if (!sec->rsec && !elf_create_rela_section(elf, sec))
return -1;
reloc = malloc(sizeof(*reloc));
@@ -865,29 +864,25 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
return elf_add_reloc(elf, sec, offset, type, sym, addend);
}
-static int read_rel_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx)
+static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
{
- if (!gelf_getrel(rsec->data, i, &reloc->rel)) {
- WARN_ELF("gelf_getrel");
- return -1;
- }
- reloc->type = GELF_R_TYPE(reloc->rel.r_info);
- reloc->addend = 0;
- reloc->offset = reloc->rel.r_offset;
- *symndx = GELF_R_SYM(reloc->rel.r_info);
- return 0;
-}
+ bool rela = rsec->sh.sh_type == SHT_RELA;
+ void *retp;
-static int read_rela_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx)
-{
- if (!gelf_getrela(rsec->data, i, &reloc->rela)) {
+ if (rela)
+ retp = gelf_getrela(rsec->data, i, &reloc->rela);
+ else
+ retp = gelf_getrel(rsec->data, i, &reloc->rel);
+
+ if (!retp) {
WARN_ELF("gelf_getrela");
return -1;
}
- reloc->type = GELF_R_TYPE(reloc->rela.r_info);
- reloc->addend = reloc->rela.r_addend;
- reloc->offset = reloc->rela.r_offset;
- *symndx = GELF_R_SYM(reloc->rela.r_info);
+
+ reloc->offset = reloc->rel.r_offset;
+ reloc->type = GELF_R_TYPE(reloc->rel.r_info);
+ reloc->addend = rela ? reloc->rela.r_addend : 0;
+
return 0;
}
@@ -926,20 +921,13 @@ static int read_relocs(struct elf *elf)
}
for (i = 0; i < rsec->sh.sh_size / rsec->sh.sh_entsize; i++) {
reloc = &rsec->reloc_data[i];
- switch (rsec->sh.sh_type) {
- case SHT_REL:
- if (read_rel_reloc(rsec, i, reloc, &symndx))
- return -1;
- break;
- case SHT_RELA:
- if (read_rela_reloc(rsec, i, reloc, &symndx))
- return -1;
- break;
- default: return -1;
- }
+
+ if (read_reloc(rsec, i, reloc))
+ return -1;
reloc->sec = rsec;
reloc->idx = i;
+ symndx = GELF_R_SYM(reloc->rel.r_info);
reloc->sym = sym = find_symbol_by_index(elf, symndx);
if (!reloc->sym) {
WARN("can't find reloc entry symbol %d for %s",
@@ -1141,86 +1129,42 @@ struct section *elf_create_section(struct elf *elf, const char *name,
return sec;
}
-static struct section *elf_create_rel_reloc_section(struct elf *elf,
- struct section *sec)
+static struct section *elf_create_rela_section(struct elf *elf,
+ struct section *sec)
{
- char *relocname;
struct section *rsec;
+ char *rsec_name;
- relocname = malloc(strlen(sec->name) + strlen(".rel") + 1);
- if (!relocname) {
+ rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1);
+ if (!rsec_name) {
perror("malloc");
return NULL;
}
- strcpy(relocname, ".rel");
- strcat(relocname, sec->name);
+ strcpy(rsec_name, ".rela");
+ strcat(rsec_name, sec->name);
- rsec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0);
- free(relocname);
+ rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0);
+ free(rsec_name);
if (!rsec)
return NULL;
sec->rsec = rsec;
rsec->base = sec;
- rsec->sh.sh_type = SHT_REL;
- rsec->sh.sh_addralign = 8;
- rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
- rsec->sh.sh_info = sec->idx;
- rsec->sh.sh_flags = SHF_INFO_LINK;
-
- return rsec;
-}
-
-static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base)
-{
- char *relocname;
- struct section *rsec;
- int addrsize = elf_class_addrsize(elf);
-
- relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
- if (!relocname) {
- perror("malloc");
- return NULL;
- }
- strcpy(relocname, ".rela");
- strcat(relocname, base->name);
-
- if (addrsize == sizeof(u32))
- rsec = elf_create_section(elf, relocname, sizeof(Elf32_Rela), 0);
- else
- rsec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0);
- free(relocname);
- if (!rsec)
- return NULL;
-
- base->rsec = rsec;
- rsec->base = base;
-
rsec->sh.sh_type = SHT_RELA;
- rsec->sh.sh_addralign = addrsize;
+ rsec->sh.sh_addralign = elf_addr_size(elf);
rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
- rsec->sh.sh_info = base->idx;
+ rsec->sh.sh_info = sec->idx;
rsec->sh.sh_flags = SHF_INFO_LINK;
return rsec;
}
-static struct section *elf_create_reloc_section(struct elf *elf,
- struct section *base,
- int reltype)
-{
- switch (reltype) {
- case SHT_REL: return elf_create_rel_reloc_section(elf, base);
- case SHT_RELA: return elf_create_rela_reloc_section(elf, base);
- default: return NULL;
- }
-}
-
-static int elf_rebuild_rel_reloc_section(struct section *rsec)
+static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
{
+ bool rela = rsec->sh.sh_type == SHT_RELA;
struct reloc *reloc;
- int idx = 0;
+ int idx = 0, ret;
void *buf;
/* Allocate a buffer for relocations */
@@ -1232,46 +1176,20 @@ static int elf_rebuild_rel_reloc_section(struct section *rsec)
rsec->data->d_buf = buf;
rsec->data->d_size = rsec->sh.sh_size;
- rsec->data->d_type = ELF_T_REL;
+ rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL;
idx = 0;
list_for_each_entry(reloc, &rsec->reloc_list, list) {
reloc->rel.r_offset = reloc->offset;
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
- if (!gelf_update_rel(rsec->data, idx, &reloc->rel)) {
- WARN_ELF("gelf_update_rel");
- return -1;
+ if (rela) {
+ reloc->rela.r_addend = reloc->addend;
+ ret = gelf_update_rela(rsec->data, idx, &reloc->rela);
+ } else {
+ ret = gelf_update_rel(rsec->data, idx, &reloc->rel);
}
- idx++;
- }
-
- return 0;
-}
-
-static int elf_rebuild_rela_reloc_section(struct section *rsec)
-{
- struct reloc *reloc;
- int idx = 0;
- void *buf;
-
- /* Allocate a buffer for relocations with addends */
- buf = malloc(rsec->sh.sh_size);
- if (!buf) {
- perror("malloc");
- return -1;
- }
-
- rsec->data->d_buf = buf;
- rsec->data->d_size = rsec->sh.sh_size;
- rsec->data->d_type = ELF_T_RELA;
-
- idx = 0;
- list_for_each_entry(reloc, &rsec->reloc_list, list) {
- reloc->rela.r_offset = reloc->offset;
- reloc->rela.r_addend = reloc->addend;
- reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
- if (!gelf_update_rela(rsec->data, idx, &reloc->rela)) {
- WARN_ELF("gelf_update_rela");
+ if (!ret) {
+ WARN_ELF("gelf_update_rel");
return -1;
}
idx++;
@@ -1280,15 +1198,6 @@ static int elf_rebuild_rela_reloc_section(struct section *rsec)
return 0;
}
-static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
-{
- switch (rsec->sh.sh_type) {
- case SHT_REL: return elf_rebuild_rel_reloc_section(rsec);
- case SHT_RELA: return elf_rebuild_rela_reloc_section(rsec);
- default: return -1;
- }
-}
-
int elf_write_insn(struct elf *elf, struct section *sec,
unsigned long offset, unsigned int len,
const char *insn)
@@ -1311,24 +1220,21 @@ int elf_write_insn(struct elf *elf, struct section *sec,
int elf_write_reloc(struct elf *elf, struct reloc *reloc)
{
struct section *rsec = reloc->sec;
+ int ret;
- if (rsec->sh.sh_type == SHT_REL) {
- reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
- reloc->rel.r_offset = reloc->offset;
+ reloc->rel.r_offset = reloc->offset;
+ reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
- if (!gelf_update_rel(rsec->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);
+ if (rsec->sh.sh_type == SHT_RELA) {
reloc->rela.r_addend = reloc->addend;
- reloc->rela.r_offset = reloc->offset;
+ ret = gelf_update_rela(rsec->data, reloc->idx, &reloc->rela);
+ } else {
+ ret = gelf_update_rel(rsec->data, reloc->idx, &reloc->rel);
+ }
- if (!gelf_update_rela(rsec->data, reloc->idx, &reloc->rela)) {
- WARN_ELF("gelf_update_rela");
- return -1;
- }
+ if (!ret) {
+ WARN_ELF("gelf_update_rela");
+ return -1;
}
elf->changed = true;
@@ -12,6 +12,7 @@
#include <linux/hashtable.h>
#include <linux/rbtree.h>
#include <linux/jhash.h>
+#include <arch/elf.h>
#ifdef LIBELF_USE_DEPRECATED
# define elf_getshdrnum elf_getshnum
@@ -147,12 +148,14 @@ static inline bool has_multiple_files(struct elf *elf)
return elf->num_files > 1;
}
-static inline int elf_class_addrsize(struct elf *elf)
+static inline size_t elf_addr_size(struct elf *elf)
{
- if (elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32)
- return sizeof(u32);
- else
- return sizeof(u64);
+ return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+}
+
+static inline size_t elf_rela_size(struct elf *elf)
+{
+ return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
}
#define for_each_sec(file, sec) \