Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+68 -159
+6 -6
tools/objtool/check.c
··· 952 952 953 953 static int create_mcount_loc_sections(struct objtool_file *file) 954 954 { 955 - int addrsize = elf_class_addrsize(file->elf); 955 + size_t addr_size = elf_addr_size(file->elf); 956 956 struct instruction *insn; 957 957 struct section *sec; 958 958 int idx; ··· 971 971 list_for_each_entry(insn, &file->mcount_loc_list, call_node) 972 972 idx++; 973 973 974 - sec = elf_create_section(file->elf, "__mcount_loc", addrsize, idx); 974 + sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx); 975 975 if (!sec) 976 976 return -1; 977 977 978 - sec->sh.sh_addralign = addrsize; 978 + sec->sh.sh_addralign = addr_size; 979 979 980 980 idx = 0; 981 981 list_for_each_entry(insn, &file->mcount_loc_list, call_node) { 982 982 void *loc; 983 983 984 984 loc = sec->data->d_buf + idx; 985 - memset(loc, 0, addrsize); 985 + memset(loc, 0, addr_size); 986 986 987 987 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, 989 989 insn->sec, insn->offset)) 990 990 return -1; 991 991 992 - idx += addrsize; 992 + idx += addr_size; 993 993 } 994 994 995 995 return 0;
+54 -148
tools/objtool/elf.c
··· 533 533 return -1; 534 534 } 535 535 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); 539 538 540 539 int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, 541 540 unsigned int type, struct symbol *sym, s64 addend) 542 541 { 543 542 struct reloc *reloc; 544 543 545 - if (!sec->rsec && !elf_create_reloc_section(elf, sec, SHT_RELA)) 544 + if (!sec->rsec && !elf_create_rela_section(elf, sec)) 546 545 return -1; 547 546 548 547 reloc = malloc(sizeof(*reloc)); ··· 864 865 return elf_add_reloc(elf, sec, offset, type, sym, addend); 865 866 } 866 867 867 - static int read_rel_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx) 868 + static int read_reloc(struct section *rsec, int i, struct reloc *reloc) 868 869 { 869 - if (!gelf_getrel(rsec->data, i, &reloc->rel)) { 870 - WARN_ELF("gelf_getrel"); 871 - return -1; 872 - } 873 - reloc->type = GELF_R_TYPE(reloc->rel.r_info); 874 - reloc->addend = 0; 875 - reloc->offset = reloc->rel.r_offset; 876 - *symndx = GELF_R_SYM(reloc->rel.r_info); 877 - return 0; 878 - } 870 + bool rela = rsec->sh.sh_type == SHT_RELA; 871 + void *retp; 879 872 880 - static int read_rela_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx) 881 - { 882 - if (!gelf_getrela(rsec->data, i, &reloc->rela)) { 873 + if (rela) 874 + retp = gelf_getrela(rsec->data, i, &reloc->rela); 875 + else 876 + retp = gelf_getrel(rsec->data, i, &reloc->rel); 877 + 878 + if (!retp) { 883 879 WARN_ELF("gelf_getrela"); 884 880 return -1; 885 881 } 886 - reloc->type = GELF_R_TYPE(reloc->rela.r_info); 887 - reloc->addend = reloc->rela.r_addend; 888 - reloc->offset = reloc->rela.r_offset; 889 - *symndx = GELF_R_SYM(reloc->rela.r_info); 882 + 883 + reloc->offset = reloc->rel.r_offset; 884 + reloc->type = GELF_R_TYPE(reloc->rel.r_info); 885 + reloc->addend = rela ? reloc->rela.r_addend : 0; 886 + 890 887 return 0; 891 888 } 892 889 ··· 921 926 } 922 927 for (i = 0; i < rsec->sh.sh_size / rsec->sh.sh_entsize; i++) { 923 928 reloc = &rsec->reloc_data[i]; 924 - switch (rsec->sh.sh_type) { 925 - case SHT_REL: 926 - if (read_rel_reloc(rsec, i, reloc, &symndx)) 927 - return -1; 928 - break; 929 - case SHT_RELA: 930 - if (read_rela_reloc(rsec, i, reloc, &symndx)) 931 - return -1; 932 - break; 933 - default: return -1; 934 - } 929 + 930 + if (read_reloc(rsec, i, reloc)) 931 + return -1; 935 932 936 933 reloc->sec = rsec; 937 934 reloc->idx = i; 935 + symndx = GELF_R_SYM(reloc->rel.r_info); 938 936 reloc->sym = sym = find_symbol_by_index(elf, symndx); 939 937 if (!reloc->sym) { 940 938 WARN("can't find reloc entry symbol %d for %s", ··· 1129 1141 return sec; 1130 1142 } 1131 1143 1132 - static struct section *elf_create_rel_reloc_section(struct elf *elf, 1133 - struct section *sec) 1144 + static struct section *elf_create_rela_section(struct elf *elf, 1145 + struct section *sec) 1134 1146 { 1135 - char *relocname; 1136 1147 struct section *rsec; 1148 + char *rsec_name; 1137 1149 1138 - relocname = malloc(strlen(sec->name) + strlen(".rel") + 1); 1139 - if (!relocname) { 1150 + rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1); 1151 + if (!rsec_name) { 1140 1152 perror("malloc"); 1141 1153 return NULL; 1142 1154 } 1143 - strcpy(relocname, ".rel"); 1144 - strcat(relocname, sec->name); 1155 + strcpy(rsec_name, ".rela"); 1156 + strcat(rsec_name, sec->name); 1145 1157 1146 - rsec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0); 1147 - free(relocname); 1158 + rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0); 1159 + free(rsec_name); 1148 1160 if (!rsec) 1149 1161 return NULL; 1150 1162 1151 1163 sec->rsec = rsec; 1152 1164 rsec->base = sec; 1153 1165 1154 - rsec->sh.sh_type = SHT_REL; 1155 - rsec->sh.sh_addralign = 8; 1166 + rsec->sh.sh_type = SHT_RELA; 1167 + rsec->sh.sh_addralign = elf_addr_size(elf); 1156 1168 rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; 1157 1169 rsec->sh.sh_info = sec->idx; 1158 1170 rsec->sh.sh_flags = SHF_INFO_LINK; ··· 1160 1172 return rsec; 1161 1173 } 1162 1174 1163 - static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base) 1175 + static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec) 1164 1176 { 1165 - char *relocname; 1166 - struct section *rsec; 1167 - int addrsize = elf_class_addrsize(elf); 1168 - 1169 - relocname = malloc(strlen(base->name) + strlen(".rela") + 1); 1170 - if (!relocname) { 1171 - perror("malloc"); 1172 - return NULL; 1173 - } 1174 - strcpy(relocname, ".rela"); 1175 - strcat(relocname, base->name); 1176 - 1177 - if (addrsize == sizeof(u32)) 1178 - rsec = elf_create_section(elf, relocname, sizeof(Elf32_Rela), 0); 1179 - else 1180 - rsec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0); 1181 - free(relocname); 1182 - if (!rsec) 1183 - return NULL; 1184 - 1185 - base->rsec = rsec; 1186 - rsec->base = base; 1187 - 1188 - rsec->sh.sh_type = SHT_RELA; 1189 - rsec->sh.sh_addralign = addrsize; 1190 - rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; 1191 - rsec->sh.sh_info = base->idx; 1192 - rsec->sh.sh_flags = SHF_INFO_LINK; 1193 - 1194 - return rsec; 1195 - } 1196 - 1197 - static struct section *elf_create_reloc_section(struct elf *elf, 1198 - struct section *base, 1199 - int reltype) 1200 - { 1201 - switch (reltype) { 1202 - case SHT_REL: return elf_create_rel_reloc_section(elf, base); 1203 - case SHT_RELA: return elf_create_rela_reloc_section(elf, base); 1204 - default: return NULL; 1205 - } 1206 - } 1207 - 1208 - static int elf_rebuild_rel_reloc_section(struct section *rsec) 1209 - { 1177 + bool rela = rsec->sh.sh_type == SHT_RELA; 1210 1178 struct reloc *reloc; 1211 - int idx = 0; 1179 + int idx = 0, ret; 1212 1180 void *buf; 1213 1181 1214 1182 /* Allocate a buffer for relocations */ ··· 1176 1232 1177 1233 rsec->data->d_buf = buf; 1178 1234 rsec->data->d_size = rsec->sh.sh_size; 1179 - rsec->data->d_type = ELF_T_REL; 1235 + rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL; 1180 1236 1181 1237 idx = 0; 1182 1238 list_for_each_entry(reloc, &rsec->reloc_list, list) { 1183 1239 reloc->rel.r_offset = reloc->offset; 1184 1240 reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); 1185 - if (!gelf_update_rel(rsec->data, idx, &reloc->rel)) { 1241 + if (rela) { 1242 + reloc->rela.r_addend = reloc->addend; 1243 + ret = gelf_update_rela(rsec->data, idx, &reloc->rela); 1244 + } else { 1245 + ret = gelf_update_rel(rsec->data, idx, &reloc->rel); 1246 + } 1247 + if (!ret) { 1186 1248 WARN_ELF("gelf_update_rel"); 1187 1249 return -1; 1188 1250 } ··· 1196 1246 } 1197 1247 1198 1248 return 0; 1199 - } 1200 - 1201 - static int elf_rebuild_rela_reloc_section(struct section *rsec) 1202 - { 1203 - struct reloc *reloc; 1204 - int idx = 0; 1205 - void *buf; 1206 - 1207 - /* Allocate a buffer for relocations with addends */ 1208 - buf = malloc(rsec->sh.sh_size); 1209 - if (!buf) { 1210 - perror("malloc"); 1211 - return -1; 1212 - } 1213 - 1214 - rsec->data->d_buf = buf; 1215 - rsec->data->d_size = rsec->sh.sh_size; 1216 - rsec->data->d_type = ELF_T_RELA; 1217 - 1218 - idx = 0; 1219 - list_for_each_entry(reloc, &rsec->reloc_list, list) { 1220 - reloc->rela.r_offset = reloc->offset; 1221 - reloc->rela.r_addend = reloc->addend; 1222 - reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); 1223 - if (!gelf_update_rela(rsec->data, idx, &reloc->rela)) { 1224 - WARN_ELF("gelf_update_rela"); 1225 - return -1; 1226 - } 1227 - idx++; 1228 - } 1229 - 1230 - return 0; 1231 - } 1232 - 1233 - static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec) 1234 - { 1235 - switch (rsec->sh.sh_type) { 1236 - case SHT_REL: return elf_rebuild_rel_reloc_section(rsec); 1237 - case SHT_RELA: return elf_rebuild_rela_reloc_section(rsec); 1238 - default: return -1; 1239 - } 1240 1249 } 1241 1250 1242 1251 int elf_write_insn(struct elf *elf, struct section *sec, ··· 1220 1311 int elf_write_reloc(struct elf *elf, struct reloc *reloc) 1221 1312 { 1222 1313 struct section *rsec = reloc->sec; 1314 + int ret; 1223 1315 1224 - if (rsec->sh.sh_type == SHT_REL) { 1225 - reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); 1226 - reloc->rel.r_offset = reloc->offset; 1316 + reloc->rel.r_offset = reloc->offset; 1317 + reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); 1227 1318 1228 - if (!gelf_update_rel(rsec->data, reloc->idx, &reloc->rel)) { 1229 - WARN_ELF("gelf_update_rel"); 1230 - return -1; 1231 - } 1232 - } else { 1233 - reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); 1319 + if (rsec->sh.sh_type == SHT_RELA) { 1234 1320 reloc->rela.r_addend = reloc->addend; 1235 - reloc->rela.r_offset = reloc->offset; 1321 + ret = gelf_update_rela(rsec->data, reloc->idx, &reloc->rela); 1322 + } else { 1323 + ret = gelf_update_rel(rsec->data, reloc->idx, &reloc->rel); 1324 + } 1236 1325 1237 - if (!gelf_update_rela(rsec->data, reloc->idx, &reloc->rela)) { 1238 - WARN_ELF("gelf_update_rela"); 1239 - return -1; 1240 - } 1326 + if (!ret) { 1327 + WARN_ELF("gelf_update_rela"); 1328 + return -1; 1241 1329 } 1242 1330 1243 1331 elf->changed = true;
+8 -5
tools/objtool/include/objtool/elf.h
··· 12 12 #include <linux/hashtable.h> 13 13 #include <linux/rbtree.h> 14 14 #include <linux/jhash.h> 15 + #include <arch/elf.h> 15 16 16 17 #ifdef LIBELF_USE_DEPRECATED 17 18 # define elf_getshdrnum elf_getshnum ··· 148 147 return elf->num_files > 1; 149 148 } 150 149 151 - static inline int elf_class_addrsize(struct elf *elf) 150 + static inline size_t elf_addr_size(struct elf *elf) 152 151 { 153 - if (elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32) 154 - return sizeof(u32); 155 - else 156 - return sizeof(u64); 152 + return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; 153 + } 154 + 155 + static inline size_t elf_rela_size(struct elf *elf) 156 + { 157 + return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela); 157 158 } 158 159 159 160 #define for_each_sec(file, sec) \