Skip to content

Commit 53257a9

Browse files
committed
objtool: Consolidate rel/rela handling
The GElf_Rel[a] structs have more similarities than differences. It's safe to hard-code the assumptions about their shared fields as they will never change. Consolidate their handling where possible, getting rid of duplicated code. Also, at least for now we only ever create rela sections, so simplify the relocation creation code to be rela-only. Link: https://lore.kernel.org/r/dcabf6df400ca500ea929f1e4284f5e5ec0b27c8.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
1 parent a5bd623 commit 53257a9

3 files changed

Lines changed: 68 additions & 159 deletions

File tree

tools/objtool/check.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ static int create_cfi_sections(struct objtool_file *file)
952952

953953
static int create_mcount_loc_sections(struct objtool_file *file)
954954
{
955-
int addrsize = elf_class_addrsize(file->elf);
955+
size_t addr_size = elf_addr_size(file->elf);
956956
struct instruction *insn;
957957
struct section *sec;
958958
int idx;
@@ -971,25 +971,25 @@ static int create_mcount_loc_sections(struct objtool_file *file)
971971
list_for_each_entry(insn, &file->mcount_loc_list, call_node)
972972
idx++;
973973

974-
sec = elf_create_section(file->elf, "__mcount_loc", addrsize, idx);
974+
sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx);
975975
if (!sec)
976976
return -1;
977977

978-
sec->sh.sh_addralign = addrsize;
978+
sec->sh.sh_addralign = addr_size;
979979

980980
idx = 0;
981981
list_for_each_entry(insn, &file->mcount_loc_list, call_node) {
982982
void *loc;
983983

984984
loc = sec->data->d_buf + idx;
985-
memset(loc, 0, addrsize);
985+
memset(loc, 0, addr_size);
986986

987987
if (elf_add_reloc_to_insn(file->elf, sec, idx,
988-
addrsize == sizeof(u64) ? R_ABS64 : R_ABS32,
988+
addr_size == sizeof(u64) ? R_ABS64 : R_ABS32,
989989
insn->sec, insn->offset))
990990
return -1;
991991

992-
idx += addrsize;
992+
idx += addr_size;
993993
}
994994

995995
return 0;

tools/objtool/elf.c

Lines changed: 54 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -533,16 +533,15 @@ static int read_symbols(struct elf *elf)
533533
return -1;
534534
}
535535

536-
static struct section *elf_create_reloc_section(struct elf *elf,
537-
struct section *sec,
538-
int reltype);
536+
static struct section *elf_create_rela_section(struct elf *elf,
537+
struct section *sec);
539538

540539
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
541540
unsigned int type, struct symbol *sym, s64 addend)
542541
{
543542
struct reloc *reloc;
544543

545-
if (!sec->rsec && !elf_create_reloc_section(elf, sec, SHT_RELA))
544+
if (!sec->rsec && !elf_create_rela_section(elf, sec))
546545
return -1;
547546

548547
reloc = malloc(sizeof(*reloc));
@@ -865,29 +864,25 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
865864
return elf_add_reloc(elf, sec, offset, type, sym, addend);
866865
}
867866

868-
static int read_rel_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx)
867+
static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
869868
{
870-
if (!gelf_getrel(rsec->data, i, &reloc->rel)) {
871-
WARN_ELF("gelf_getrel");
872-
return -1;
873-
}
874-
reloc->type = GELF_R_TYPE(reloc->rel.r_info);
875-
reloc->addend = 0;
876-
reloc->offset = reloc->rel.r_offset;
877-
*symndx = GELF_R_SYM(reloc->rel.r_info);
878-
return 0;
879-
}
869+
bool rela = rsec->sh.sh_type == SHT_RELA;
870+
void *retp;
880871

881-
static int read_rela_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx)
882-
{
883-
if (!gelf_getrela(rsec->data, i, &reloc->rela)) {
872+
if (rela)
873+
retp = gelf_getrela(rsec->data, i, &reloc->rela);
874+
else
875+
retp = gelf_getrel(rsec->data, i, &reloc->rel);
876+
877+
if (!retp) {
884878
WARN_ELF("gelf_getrela");
885879
return -1;
886880
}
887-
reloc->type = GELF_R_TYPE(reloc->rela.r_info);
888-
reloc->addend = reloc->rela.r_addend;
889-
reloc->offset = reloc->rela.r_offset;
890-
*symndx = GELF_R_SYM(reloc->rela.r_info);
881+
882+
reloc->offset = reloc->rel.r_offset;
883+
reloc->type = GELF_R_TYPE(reloc->rel.r_info);
884+
reloc->addend = rela ? reloc->rela.r_addend : 0;
885+
891886
return 0;
892887
}
893888

@@ -926,20 +921,13 @@ static int read_relocs(struct elf *elf)
926921
}
927922
for (i = 0; i < rsec->sh.sh_size / rsec->sh.sh_entsize; i++) {
928923
reloc = &rsec->reloc_data[i];
929-
switch (rsec->sh.sh_type) {
930-
case SHT_REL:
931-
if (read_rel_reloc(rsec, i, reloc, &symndx))
932-
return -1;
933-
break;
934-
case SHT_RELA:
935-
if (read_rela_reloc(rsec, i, reloc, &symndx))
936-
return -1;
937-
break;
938-
default: return -1;
939-
}
924+
925+
if (read_reloc(rsec, i, reloc))
926+
return -1;
940927

941928
reloc->sec = rsec;
942929
reloc->idx = i;
930+
symndx = GELF_R_SYM(reloc->rel.r_info);
943931
reloc->sym = sym = find_symbol_by_index(elf, symndx);
944932
if (!reloc->sym) {
945933
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,
11411129
return sec;
11421130
}
11431131

1144-
static struct section *elf_create_rel_reloc_section(struct elf *elf,
1145-
struct section *sec)
1132+
static struct section *elf_create_rela_section(struct elf *elf,
1133+
struct section *sec)
11461134
{
1147-
char *relocname;
11481135
struct section *rsec;
1136+
char *rsec_name;
11491137

1150-
relocname = malloc(strlen(sec->name) + strlen(".rel") + 1);
1151-
if (!relocname) {
1138+
rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1);
1139+
if (!rsec_name) {
11521140
perror("malloc");
11531141
return NULL;
11541142
}
1155-
strcpy(relocname, ".rel");
1156-
strcat(relocname, sec->name);
1143+
strcpy(rsec_name, ".rela");
1144+
strcat(rsec_name, sec->name);
11571145

1158-
rsec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0);
1159-
free(relocname);
1146+
rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0);
1147+
free(rsec_name);
11601148
if (!rsec)
11611149
return NULL;
11621150

11631151
sec->rsec = rsec;
11641152
rsec->base = sec;
11651153

1166-
rsec->sh.sh_type = SHT_REL;
1167-
rsec->sh.sh_addralign = 8;
1168-
rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
1169-
rsec->sh.sh_info = sec->idx;
1170-
rsec->sh.sh_flags = SHF_INFO_LINK;
1171-
1172-
return rsec;
1173-
}
1174-
1175-
static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base)
1176-
{
1177-
char *relocname;
1178-
struct section *rsec;
1179-
int addrsize = elf_class_addrsize(elf);
1180-
1181-
relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
1182-
if (!relocname) {
1183-
perror("malloc");
1184-
return NULL;
1185-
}
1186-
strcpy(relocname, ".rela");
1187-
strcat(relocname, base->name);
1188-
1189-
if (addrsize == sizeof(u32))
1190-
rsec = elf_create_section(elf, relocname, sizeof(Elf32_Rela), 0);
1191-
else
1192-
rsec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0);
1193-
free(relocname);
1194-
if (!rsec)
1195-
return NULL;
1196-
1197-
base->rsec = rsec;
1198-
rsec->base = base;
1199-
12001154
rsec->sh.sh_type = SHT_RELA;
1201-
rsec->sh.sh_addralign = addrsize;
1155+
rsec->sh.sh_addralign = elf_addr_size(elf);
12021156
rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
1203-
rsec->sh.sh_info = base->idx;
1157+
rsec->sh.sh_info = sec->idx;
12041158
rsec->sh.sh_flags = SHF_INFO_LINK;
12051159

12061160
return rsec;
12071161
}
12081162

1209-
static struct section *elf_create_reloc_section(struct elf *elf,
1210-
struct section *base,
1211-
int reltype)
1212-
{
1213-
switch (reltype) {
1214-
case SHT_REL: return elf_create_rel_reloc_section(elf, base);
1215-
case SHT_RELA: return elf_create_rela_reloc_section(elf, base);
1216-
default: return NULL;
1217-
}
1218-
}
1219-
1220-
static int elf_rebuild_rel_reloc_section(struct section *rsec)
1163+
static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
12211164
{
1165+
bool rela = rsec->sh.sh_type == SHT_RELA;
12221166
struct reloc *reloc;
1223-
int idx = 0;
1167+
int idx = 0, ret;
12241168
void *buf;
12251169

12261170
/* Allocate a buffer for relocations */
@@ -1232,46 +1176,20 @@ static int elf_rebuild_rel_reloc_section(struct section *rsec)
12321176

12331177
rsec->data->d_buf = buf;
12341178
rsec->data->d_size = rsec->sh.sh_size;
1235-
rsec->data->d_type = ELF_T_REL;
1179+
rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL;
12361180

12371181
idx = 0;
12381182
list_for_each_entry(reloc, &rsec->reloc_list, list) {
12391183
reloc->rel.r_offset = reloc->offset;
12401184
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1241-
if (!gelf_update_rel(rsec->data, idx, &reloc->rel)) {
1242-
WARN_ELF("gelf_update_rel");
1243-
return -1;
1185+
if (rela) {
1186+
reloc->rela.r_addend = reloc->addend;
1187+
ret = gelf_update_rela(rsec->data, idx, &reloc->rela);
1188+
} else {
1189+
ret = gelf_update_rel(rsec->data, idx, &reloc->rel);
12441190
}
1245-
idx++;
1246-
}
1247-
1248-
return 0;
1249-
}
1250-
1251-
static int elf_rebuild_rela_reloc_section(struct section *rsec)
1252-
{
1253-
struct reloc *reloc;
1254-
int idx = 0;
1255-
void *buf;
1256-
1257-
/* Allocate a buffer for relocations with addends */
1258-
buf = malloc(rsec->sh.sh_size);
1259-
if (!buf) {
1260-
perror("malloc");
1261-
return -1;
1262-
}
1263-
1264-
rsec->data->d_buf = buf;
1265-
rsec->data->d_size = rsec->sh.sh_size;
1266-
rsec->data->d_type = ELF_T_RELA;
1267-
1268-
idx = 0;
1269-
list_for_each_entry(reloc, &rsec->reloc_list, list) {
1270-
reloc->rela.r_offset = reloc->offset;
1271-
reloc->rela.r_addend = reloc->addend;
1272-
reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1273-
if (!gelf_update_rela(rsec->data, idx, &reloc->rela)) {
1274-
WARN_ELF("gelf_update_rela");
1191+
if (!ret) {
1192+
WARN_ELF("gelf_update_rel");
12751193
return -1;
12761194
}
12771195
idx++;
@@ -1280,15 +1198,6 @@ static int elf_rebuild_rela_reloc_section(struct section *rsec)
12801198
return 0;
12811199
}
12821200

1283-
static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
1284-
{
1285-
switch (rsec->sh.sh_type) {
1286-
case SHT_REL: return elf_rebuild_rel_reloc_section(rsec);
1287-
case SHT_RELA: return elf_rebuild_rela_reloc_section(rsec);
1288-
default: return -1;
1289-
}
1290-
}
1291-
12921201
int elf_write_insn(struct elf *elf, struct section *sec,
12931202
unsigned long offset, unsigned int len,
12941203
const char *insn)
@@ -1311,24 +1220,21 @@ int elf_write_insn(struct elf *elf, struct section *sec,
13111220
int elf_write_reloc(struct elf *elf, struct reloc *reloc)
13121221
{
13131222
struct section *rsec = reloc->sec;
1223+
int ret;
13141224

1315-
if (rsec->sh.sh_type == SHT_REL) {
1316-
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1317-
reloc->rel.r_offset = reloc->offset;
1225+
reloc->rel.r_offset = reloc->offset;
1226+
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
13181227

1319-
if (!gelf_update_rel(rsec->data, reloc->idx, &reloc->rel)) {
1320-
WARN_ELF("gelf_update_rel");
1321-
return -1;
1322-
}
1323-
} else {
1324-
reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1228+
if (rsec->sh.sh_type == SHT_RELA) {
13251229
reloc->rela.r_addend = reloc->addend;
1326-
reloc->rela.r_offset = reloc->offset;
1230+
ret = gelf_update_rela(rsec->data, reloc->idx, &reloc->rela);
1231+
} else {
1232+
ret = gelf_update_rel(rsec->data, reloc->idx, &reloc->rel);
1233+
}
13271234

1328-
if (!gelf_update_rela(rsec->data, reloc->idx, &reloc->rela)) {
1329-
WARN_ELF("gelf_update_rela");
1330-
return -1;
1331-
}
1235+
if (!ret) {
1236+
WARN_ELF("gelf_update_rela");
1237+
return -1;
13321238
}
13331239

13341240
elf->changed = true;

tools/objtool/include/objtool/elf.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/hashtable.h>
1313
#include <linux/rbtree.h>
1414
#include <linux/jhash.h>
15+
#include <arch/elf.h>
1516

1617
#ifdef LIBELF_USE_DEPRECATED
1718
# define elf_getshdrnum elf_getshnum
@@ -147,12 +148,14 @@ static inline bool has_multiple_files(struct elf *elf)
147148
return elf->num_files > 1;
148149
}
149150

150-
static inline int elf_class_addrsize(struct elf *elf)
151+
static inline size_t elf_addr_size(struct elf *elf)
151152
{
152-
if (elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32)
153-
return sizeof(u32);
154-
else
155-
return sizeof(u64);
153+
return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
154+
}
155+
156+
static inline size_t elf_rela_size(struct elf *elf)
157+
{
158+
return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
156159
}
157160

158161
#define for_each_sec(file, sec) \

0 commit comments

Comments
 (0)