1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* This is included from relocs_32/64.c */ |
3 | |
4 | #define ElfW(type) _ElfW(ELF_BITS, type) |
5 | #define _ElfW(bits, type) __ElfW(bits, type) |
6 | #define __ElfW(bits, type) Elf##bits##_##type |
7 | |
8 | #define Elf_Addr ElfW(Addr) |
9 | #define Elf_Ehdr ElfW(Ehdr) |
10 | #define Elf_Phdr ElfW(Phdr) |
11 | #define Elf_Shdr ElfW(Shdr) |
12 | #define Elf_Sym ElfW(Sym) |
13 | |
14 | static Elf_Ehdr ehdr; |
15 | static unsigned long shnum; |
16 | static unsigned int shstrndx; |
17 | static unsigned int shsymtabndx; |
18 | static unsigned int shxsymtabndx; |
19 | |
20 | static int sym_index(Elf_Sym *sym); |
21 | |
22 | struct relocs { |
23 | uint32_t *offset; |
24 | unsigned long count; |
25 | unsigned long size; |
26 | }; |
27 | |
28 | static struct relocs relocs16; |
29 | static struct relocs relocs32; |
30 | |
31 | #if ELF_BITS == 64 |
32 | static struct relocs relocs64; |
33 | # define FMT PRIu64 |
34 | |
35 | #ifndef R_X86_64_REX_GOTPCRELX |
36 | # define R_X86_64_REX_GOTPCRELX 42 |
37 | #endif |
38 | |
39 | #else |
40 | # define FMT PRIu32 |
41 | #endif |
42 | |
43 | struct section { |
44 | Elf_Shdr shdr; |
45 | struct section *link; |
46 | Elf_Sym *symtab; |
47 | Elf32_Word *xsymtab; |
48 | Elf_Rel *reltab; |
49 | char *strtab; |
50 | }; |
51 | static struct section *secs; |
52 | |
53 | static const char * const sym_regex_kernel[S_NSYMTYPES] = { |
54 | /* |
55 | * Following symbols have been audited. There values are constant and do |
56 | * not change if bzImage is loaded at a different physical address than |
57 | * the address for which it has been compiled. Don't warn user about |
58 | * absolute relocations present w.r.t these symbols. |
59 | */ |
60 | [S_ABS] = |
61 | "^(xen_irq_disable_direct_reloc$|" |
62 | "xen_save_fl_direct_reloc$|" |
63 | "xen_elfnote_.+_offset$|" |
64 | "VDSO|" |
65 | "__kcfi_typeid_|" |
66 | "__crc_)", |
67 | |
68 | /* |
69 | * These symbols are known to be relative, even if the linker marks them |
70 | * as absolute (typically defined outside any section in the linker script.) |
71 | */ |
72 | [S_REL] = |
73 | "^(__init_(begin|end)|" |
74 | "__x86_cpu_dev_(start|end)|" |
75 | "__alt_instructions(_end)?|" |
76 | "(__iommu_table|__apicdrivers|__smp_locks)(_end)?|" |
77 | "__(start|end)_pci_.*|" |
78 | #if CONFIG_FW_LOADER |
79 | "__(start|end)_builtin_fw|" |
80 | #endif |
81 | "__(start|stop)___ksymtab(_gpl)?|" |
82 | "__(start|stop)___kcrctab(_gpl)?|" |
83 | "__(start|stop)___param|" |
84 | "__(start|stop)___modver|" |
85 | "__(start|stop)___bug_table|" |
86 | "__tracedata_(start|end)|" |
87 | "__(start|stop)_notes|" |
88 | "__end_rodata|" |
89 | "__end_rodata_aligned|" |
90 | "__initramfs_start|" |
91 | "(jiffies|jiffies_64)|" |
92 | #if ELF_BITS == 64 |
93 | "__end_rodata_hpage_align|" |
94 | #endif |
95 | "_end)$" |
96 | }; |
97 | |
98 | |
99 | static const char * const sym_regex_realmode[S_NSYMTYPES] = { |
100 | /* |
101 | * These symbols are known to be relative, even if the linker marks them |
102 | * as absolute (typically defined outside any section in the linker script.) |
103 | */ |
104 | [S_REL] = |
105 | "^pa_", |
106 | |
107 | /* |
108 | * These are 16-bit segment symbols when compiling 16-bit code. |
109 | */ |
110 | [S_SEG] = |
111 | "^real_mode_seg$", |
112 | |
113 | /* |
114 | * These are offsets belonging to segments, as opposed to linear addresses, |
115 | * when compiling 16-bit code. |
116 | */ |
117 | [S_LIN] = |
118 | "^pa_", |
119 | }; |
120 | |
121 | static const char * const *sym_regex; |
122 | |
123 | static regex_t sym_regex_c[S_NSYMTYPES]; |
124 | |
125 | static int is_reloc(enum symtype type, const char *sym_name) |
126 | { |
127 | return sym_regex[type] && !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); |
128 | } |
129 | |
130 | static void regex_init(int use_real_mode) |
131 | { |
132 | char errbuf[128]; |
133 | int err; |
134 | int i; |
135 | |
136 | if (use_real_mode) |
137 | sym_regex = sym_regex_realmode; |
138 | else |
139 | sym_regex = sym_regex_kernel; |
140 | |
141 | for (i = 0; i < S_NSYMTYPES; i++) { |
142 | if (!sym_regex[i]) |
143 | continue; |
144 | |
145 | err = regcomp(&sym_regex_c[i], sym_regex[i], REG_EXTENDED|REG_NOSUB); |
146 | |
147 | if (err) { |
148 | regerror(err, &sym_regex_c[i], errbuf, sizeof(errbuf)); |
149 | die("%s", errbuf); |
150 | } |
151 | } |
152 | } |
153 | |
154 | static const char *sym_type(unsigned type) |
155 | { |
156 | static const char *type_name[] = { |
157 | #define SYM_TYPE(X) [X] = #X |
158 | SYM_TYPE(STT_NOTYPE), |
159 | SYM_TYPE(STT_OBJECT), |
160 | SYM_TYPE(STT_FUNC), |
161 | SYM_TYPE(STT_SECTION), |
162 | SYM_TYPE(STT_FILE), |
163 | SYM_TYPE(STT_COMMON), |
164 | SYM_TYPE(STT_TLS), |
165 | #undef SYM_TYPE |
166 | }; |
167 | const char *name = "unknown sym type name"; |
168 | |
169 | if (type < ARRAY_SIZE(type_name)) |
170 | name = type_name[type]; |
171 | |
172 | return name; |
173 | } |
174 | |
175 | static const char *sym_bind(unsigned bind) |
176 | { |
177 | static const char *bind_name[] = { |
178 | #define SYM_BIND(X) [X] = #X |
179 | SYM_BIND(STB_LOCAL), |
180 | SYM_BIND(STB_GLOBAL), |
181 | SYM_BIND(STB_WEAK), |
182 | #undef SYM_BIND |
183 | }; |
184 | const char *name = "unknown sym bind name"; |
185 | |
186 | if (bind < ARRAY_SIZE(bind_name)) |
187 | name = bind_name[bind]; |
188 | |
189 | return name; |
190 | } |
191 | |
192 | static const char *sym_visibility(unsigned visibility) |
193 | { |
194 | static const char *visibility_name[] = { |
195 | #define SYM_VISIBILITY(X) [X] = #X |
196 | SYM_VISIBILITY(STV_DEFAULT), |
197 | SYM_VISIBILITY(STV_INTERNAL), |
198 | SYM_VISIBILITY(STV_HIDDEN), |
199 | SYM_VISIBILITY(STV_PROTECTED), |
200 | #undef SYM_VISIBILITY |
201 | }; |
202 | const char *name = "unknown sym visibility name"; |
203 | |
204 | if (visibility < ARRAY_SIZE(visibility_name)) |
205 | name = visibility_name[visibility]; |
206 | |
207 | return name; |
208 | } |
209 | |
210 | static const char *rel_type(unsigned type) |
211 | { |
212 | static const char *type_name[] = { |
213 | #define REL_TYPE(X) [X] = #X |
214 | #if ELF_BITS == 64 |
215 | REL_TYPE(R_X86_64_NONE), |
216 | REL_TYPE(R_X86_64_64), |
217 | REL_TYPE(R_X86_64_PC64), |
218 | REL_TYPE(R_X86_64_PC32), |
219 | REL_TYPE(R_X86_64_GOT32), |
220 | REL_TYPE(R_X86_64_PLT32), |
221 | REL_TYPE(R_X86_64_COPY), |
222 | REL_TYPE(R_X86_64_GLOB_DAT), |
223 | REL_TYPE(R_X86_64_JUMP_SLOT), |
224 | REL_TYPE(R_X86_64_RELATIVE), |
225 | REL_TYPE(R_X86_64_GOTPCREL), |
226 | REL_TYPE(R_X86_64_32), |
227 | REL_TYPE(R_X86_64_32S), |
228 | REL_TYPE(R_X86_64_16), |
229 | REL_TYPE(R_X86_64_PC16), |
230 | REL_TYPE(R_X86_64_8), |
231 | REL_TYPE(R_X86_64_PC8), |
232 | REL_TYPE(R_X86_64_REX_GOTPCRELX), |
233 | #else |
234 | REL_TYPE(R_386_NONE), |
235 | REL_TYPE(R_386_32), |
236 | REL_TYPE(R_386_PC32), |
237 | REL_TYPE(R_386_GOT32), |
238 | REL_TYPE(R_386_PLT32), |
239 | REL_TYPE(R_386_COPY), |
240 | REL_TYPE(R_386_GLOB_DAT), |
241 | REL_TYPE(R_386_JMP_SLOT), |
242 | REL_TYPE(R_386_RELATIVE), |
243 | REL_TYPE(R_386_GOTOFF), |
244 | REL_TYPE(R_386_GOTPC), |
245 | REL_TYPE(R_386_8), |
246 | REL_TYPE(R_386_PC8), |
247 | REL_TYPE(R_386_16), |
248 | REL_TYPE(R_386_PC16), |
249 | #endif |
250 | #undef REL_TYPE |
251 | }; |
252 | const char *name = "unknown type rel type name"; |
253 | |
254 | if (type < ARRAY_SIZE(type_name) && type_name[type]) |
255 | name = type_name[type]; |
256 | |
257 | return name; |
258 | } |
259 | |
260 | static const char *sec_name(unsigned shndx) |
261 | { |
262 | const char *sec_strtab; |
263 | const char *name; |
264 | sec_strtab = secs[shstrndx].strtab; |
265 | name = "<noname>"; |
266 | |
267 | if (shndx < shnum) |
268 | name = sec_strtab + secs[shndx].shdr.sh_name; |
269 | else if (shndx == SHN_ABS) |
270 | name = "ABSOLUTE"; |
271 | else if (shndx == SHN_COMMON) |
272 | name = "COMMON"; |
273 | |
274 | return name; |
275 | } |
276 | |
277 | static const char *sym_name(const char *sym_strtab, Elf_Sym *sym) |
278 | { |
279 | const char *name; |
280 | name = "<noname>"; |
281 | |
282 | if (sym->st_name) |
283 | name = sym_strtab + sym->st_name; |
284 | else |
285 | name = sec_name(shndx: sym_index(sym)); |
286 | |
287 | return name; |
288 | } |
289 | |
290 | #if BYTE_ORDER == LITTLE_ENDIAN |
291 | # define le16_to_cpu(val) (val) |
292 | # define le32_to_cpu(val) (val) |
293 | # define le64_to_cpu(val) (val) |
294 | #endif |
295 | |
296 | #if BYTE_ORDER == BIG_ENDIAN |
297 | # define le16_to_cpu(val) bswap_16(val) |
298 | # define le32_to_cpu(val) bswap_32(val) |
299 | # define le64_to_cpu(val) bswap_64(val) |
300 | #endif |
301 | |
302 | static uint16_t elf16_to_cpu(uint16_t val) |
303 | { |
304 | return le16_to_cpu(val); |
305 | } |
306 | |
307 | static uint32_t elf32_to_cpu(uint32_t val) |
308 | { |
309 | return le32_to_cpu(val); |
310 | } |
311 | |
312 | #define elf_half_to_cpu(x) elf16_to_cpu(x) |
313 | #define elf_word_to_cpu(x) elf32_to_cpu(x) |
314 | |
315 | #if ELF_BITS == 64 |
316 | static uint64_t elf64_to_cpu(uint64_t val) |
317 | { |
318 | return le64_to_cpu(val); |
319 | } |
320 | # define elf_addr_to_cpu(x) elf64_to_cpu(x) |
321 | # define elf_off_to_cpu(x) elf64_to_cpu(x) |
322 | # define elf_xword_to_cpu(x) elf64_to_cpu(x) |
323 | #else |
324 | # define elf_addr_to_cpu(x) elf32_to_cpu(x) |
325 | # define elf_off_to_cpu(x) elf32_to_cpu(x) |
326 | # define elf_xword_to_cpu(x) elf32_to_cpu(x) |
327 | #endif |
328 | |
329 | static int sym_index(Elf_Sym *sym) |
330 | { |
331 | Elf_Sym *symtab = secs[shsymtabndx].symtab; |
332 | Elf32_Word *xsymtab = secs[shxsymtabndx].xsymtab; |
333 | unsigned long offset; |
334 | int index; |
335 | |
336 | if (sym->st_shndx != SHN_XINDEX) |
337 | return sym->st_shndx; |
338 | |
339 | /* calculate offset of sym from head of table. */ |
340 | offset = (unsigned long)sym - (unsigned long)symtab; |
341 | index = offset / sizeof(*sym); |
342 | |
343 | return elf32_to_cpu(xsymtab[index]); |
344 | } |
345 | |
346 | static void read_ehdr(FILE *fp) |
347 | { |
348 | if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) |
349 | die("Cannot read ELF header: %s\n", strerror(errno)); |
350 | if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) |
351 | die("No ELF magic\n"); |
352 | if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) |
353 | die("Not a %d bit executable\n", ELF_BITS); |
354 | if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) |
355 | die("Not a LSB ELF executable\n"); |
356 | if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) |
357 | die("Unknown ELF version\n"); |
358 | |
359 | /* Convert the fields to native endian */ |
360 | ehdr.e_type = elf_half_to_cpu(ehdr.e_type); |
361 | ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine); |
362 | ehdr.e_version = elf_word_to_cpu(ehdr.e_version); |
363 | ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry); |
364 | ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff); |
365 | ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff); |
366 | ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags); |
367 | ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize); |
368 | ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize); |
369 | ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum); |
370 | ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize); |
371 | ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum); |
372 | ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx); |
373 | |
374 | shnum = ehdr.e_shnum; |
375 | shstrndx = ehdr.e_shstrndx; |
376 | |
377 | if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) |
378 | die("Unsupported ELF header type\n"); |
379 | if (ehdr.e_machine != ELF_MACHINE) |
380 | die("Not for %s\n", ELF_MACHINE_NAME); |
381 | if (ehdr.e_version != EV_CURRENT) |
382 | die("Unknown ELF version\n"); |
383 | if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) |
384 | die("Bad ELF header size\n"); |
385 | if (ehdr.e_phentsize != sizeof(Elf_Phdr)) |
386 | die("Bad program header entry\n"); |
387 | if (ehdr.e_shentsize != sizeof(Elf_Shdr)) |
388 | die("Bad section header entry\n"); |
389 | |
390 | |
391 | if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) { |
392 | Elf_Shdr shdr; |
393 | |
394 | if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) |
395 | die("Seek to %"FMT " failed: %s\n", ehdr.e_shoff, strerror(errno)); |
396 | |
397 | if (fread(&shdr, sizeof(shdr), 1, fp) != 1) |
398 | die("Cannot read initial ELF section header: %s\n", strerror(errno)); |
399 | |
400 | if (shnum == SHN_UNDEF) |
401 | shnum = elf_xword_to_cpu(shdr.sh_size); |
402 | |
403 | if (shstrndx == SHN_XINDEX) |
404 | shstrndx = elf_word_to_cpu(shdr.sh_link); |
405 | } |
406 | |
407 | if (shstrndx >= shnum) |
408 | die("String table index out of bounds\n"); |
409 | } |
410 | |
411 | static void read_shdrs(FILE *fp) |
412 | { |
413 | int i; |
414 | Elf_Shdr shdr; |
415 | |
416 | secs = calloc(shnum, sizeof(struct section)); |
417 | if (!secs) |
418 | die("Unable to allocate %ld section headers\n", shnum); |
419 | |
420 | if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) |
421 | die("Seek to %"FMT " failed: %s\n", ehdr.e_shoff, strerror(errno)); |
422 | |
423 | for (i = 0; i < shnum; i++) { |
424 | struct section *sec = &secs[i]; |
425 | |
426 | if (fread(&shdr, sizeof(shdr), 1, fp) != 1) |
427 | die("Cannot read ELF section headers %d/%ld: %s\n", i, shnum, strerror(errno)); |
428 | |
429 | sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name); |
430 | sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type); |
431 | sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags); |
432 | sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr); |
433 | sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset); |
434 | sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size); |
435 | sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link); |
436 | sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info); |
437 | sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign); |
438 | sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize); |
439 | if (sec->shdr.sh_link < shnum) |
440 | sec->link = &secs[sec->shdr.sh_link]; |
441 | } |
442 | |
443 | } |
444 | |
445 | static void read_strtabs(FILE *fp) |
446 | { |
447 | int i; |
448 | |
449 | for (i = 0; i < shnum; i++) { |
450 | struct section *sec = &secs[i]; |
451 | |
452 | if (sec->shdr.sh_type != SHT_STRTAB) |
453 | continue; |
454 | |
455 | sec->strtab = malloc(sec->shdr.sh_size); |
456 | if (!sec->strtab) |
457 | die("malloc of %"FMT " bytes for strtab failed\n", sec->shdr.sh_size); |
458 | |
459 | if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) |
460 | die("Seek to %"FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno)); |
461 | |
462 | if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size) |
463 | die("Cannot read symbol table: %s\n", strerror(errno)); |
464 | } |
465 | } |
466 | |
467 | static void read_symtabs(FILE *fp) |
468 | { |
469 | int i, j; |
470 | |
471 | for (i = 0; i < shnum; i++) { |
472 | struct section *sec = &secs[i]; |
473 | int num_syms; |
474 | |
475 | switch (sec->shdr.sh_type) { |
476 | case SHT_SYMTAB_SHNDX: |
477 | sec->xsymtab = malloc(sec->shdr.sh_size); |
478 | if (!sec->xsymtab) |
479 | die("malloc of %"FMT " bytes for xsymtab failed\n", sec->shdr.sh_size); |
480 | |
481 | if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) |
482 | die("Seek to %"FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno)); |
483 | |
484 | if (fread(sec->xsymtab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size) |
485 | die("Cannot read extended symbol table: %s\n", strerror(errno)); |
486 | |
487 | shxsymtabndx = i; |
488 | continue; |
489 | |
490 | case SHT_SYMTAB: |
491 | num_syms = sec->shdr.sh_size / sizeof(Elf_Sym); |
492 | |
493 | sec->symtab = malloc(sec->shdr.sh_size); |
494 | if (!sec->symtab) |
495 | die("malloc of %"FMT " bytes for symtab failed\n", sec->shdr.sh_size); |
496 | |
497 | if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) |
498 | die("Seek to %"FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno)); |
499 | |
500 | if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size) |
501 | die("Cannot read symbol table: %s\n", strerror(errno)); |
502 | |
503 | for (j = 0; j < num_syms; j++) { |
504 | Elf_Sym *sym = &sec->symtab[j]; |
505 | |
506 | sym->st_name = elf_word_to_cpu(sym->st_name); |
507 | sym->st_value = elf_addr_to_cpu(sym->st_value); |
508 | sym->st_size = elf_xword_to_cpu(sym->st_size); |
509 | sym->st_shndx = elf_half_to_cpu(sym->st_shndx); |
510 | } |
511 | shsymtabndx = i; |
512 | continue; |
513 | |
514 | default: |
515 | continue; |
516 | } |
517 | } |
518 | } |
519 | |
520 | |
521 | static void read_relocs(FILE *fp) |
522 | { |
523 | int i, j; |
524 | |
525 | for (i = 0; i < shnum; i++) { |
526 | struct section *sec = &secs[i]; |
527 | |
528 | if (sec->shdr.sh_type != SHT_REL_TYPE) |
529 | continue; |
530 | |
531 | sec->reltab = malloc(sec->shdr.sh_size); |
532 | if (!sec->reltab) |
533 | die("malloc of %"FMT " bytes for relocs failed\n", sec->shdr.sh_size); |
534 | |
535 | if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) |
536 | die("Seek to %"FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno)); |
537 | |
538 | if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size) |
539 | die("Cannot read symbol table: %s\n", strerror(errno)); |
540 | |
541 | for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { |
542 | Elf_Rel *rel = &sec->reltab[j]; |
543 | |
544 | rel->r_offset = elf_addr_to_cpu(rel->r_offset); |
545 | rel->r_info = elf_xword_to_cpu(rel->r_info); |
546 | #if (SHT_REL_TYPE == SHT_RELA) |
547 | rel->r_addend = elf_xword_to_cpu(rel->r_addend); |
548 | #endif |
549 | } |
550 | } |
551 | } |
552 | |
553 | |
554 | static void print_absolute_symbols(void) |
555 | { |
556 | int i; |
557 | const char *format; |
558 | |
559 | if (ELF_BITS == 64) |
560 | format = "%5d %016"PRIx64 " %5"PRId64 " %10s %10s %12s %s\n"; |
561 | else |
562 | format = "%5d %08"PRIx32 " %5"PRId32 " %10s %10s %12s %s\n"; |
563 | |
564 | printf("Absolute symbols\n"); |
565 | printf(" Num: Value Size Type Bind Visibility Name\n"); |
566 | |
567 | for (i = 0; i < shnum; i++) { |
568 | struct section *sec = &secs[i]; |
569 | char *sym_strtab; |
570 | int j; |
571 | |
572 | if (sec->shdr.sh_type != SHT_SYMTAB) |
573 | continue; |
574 | |
575 | sym_strtab = sec->link->strtab; |
576 | |
577 | for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) { |
578 | Elf_Sym *sym; |
579 | const char *name; |
580 | |
581 | sym = &sec->symtab[j]; |
582 | name = sym_name(sym_strtab, sym); |
583 | |
584 | if (sym->st_shndx != SHN_ABS) |
585 | continue; |
586 | |
587 | printf(format, |
588 | j, sym->st_value, sym->st_size, |
589 | sym_type(ELF_ST_TYPE(sym->st_info)), |
590 | sym_bind(ELF_ST_BIND(sym->st_info)), |
591 | sym_visibility(ELF_ST_VISIBILITY(sym->st_other)), |
592 | name); |
593 | } |
594 | } |
595 | printf("\n"); |
596 | } |
597 | |
598 | static void print_absolute_relocs(void) |
599 | { |
600 | int i, printed = 0; |
601 | const char *format; |
602 | |
603 | if (ELF_BITS == 64) |
604 | format = "%016"PRIx64 " %016"PRIx64 " %10s %016"PRIx64 " %s\n"; |
605 | else |
606 | format = "%08"PRIx32 " %08"PRIx32 " %10s %08"PRIx32 " %s\n"; |
607 | |
608 | for (i = 0; i < shnum; i++) { |
609 | struct section *sec = &secs[i]; |
610 | struct section *sec_applies, *sec_symtab; |
611 | char *sym_strtab; |
612 | Elf_Sym *sh_symtab; |
613 | int j; |
614 | |
615 | if (sec->shdr.sh_type != SHT_REL_TYPE) |
616 | continue; |
617 | |
618 | sec_symtab = sec->link; |
619 | sec_applies = &secs[sec->shdr.sh_info]; |
620 | if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) |
621 | continue; |
622 | |
623 | /* |
624 | * Do not perform relocations in .notes section; any |
625 | * values there are meant for pre-boot consumption (e.g. |
626 | * startup_xen). |
627 | */ |
628 | if (sec_applies->shdr.sh_type == SHT_NOTE) |
629 | continue; |
630 | |
631 | sh_symtab = sec_symtab->symtab; |
632 | sym_strtab = sec_symtab->link->strtab; |
633 | |
634 | for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { |
635 | Elf_Rel *rel; |
636 | Elf_Sym *sym; |
637 | const char *name; |
638 | |
639 | rel = &sec->reltab[j]; |
640 | sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; |
641 | name = sym_name(sym_strtab, sym); |
642 | |
643 | if (sym->st_shndx != SHN_ABS) |
644 | continue; |
645 | |
646 | /* Absolute symbols are not relocated if bzImage is |
647 | * loaded at a non-compiled address. Display a warning |
648 | * to user at compile time about the absolute |
649 | * relocations present. |
650 | * |
651 | * User need to audit the code to make sure |
652 | * some symbols which should have been section |
653 | * relative have not become absolute because of some |
654 | * linker optimization or wrong programming usage. |
655 | * |
656 | * Before warning check if this absolute symbol |
657 | * relocation is harmless. |
658 | */ |
659 | if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) |
660 | continue; |
661 | |
662 | if (!printed) { |
663 | printf("WARNING: Absolute relocations present\n"); |
664 | printf("Offset Info Type Sym.Value Sym.Name\n"); |
665 | printed = 1; |
666 | } |
667 | |
668 | printf(format, |
669 | rel->r_offset, |
670 | rel->r_info, |
671 | rel_type(ELF_R_TYPE(rel->r_info)), |
672 | sym->st_value, |
673 | name); |
674 | } |
675 | } |
676 | |
677 | if (printed) |
678 | printf("\n"); |
679 | } |
680 | |
681 | static void add_reloc(struct relocs *r, uint32_t offset) |
682 | { |
683 | if (r->count == r->size) { |
684 | unsigned long newsize = r->size + 50000; |
685 | void *mem = realloc(r->offset, newsize * sizeof(r->offset[0])); |
686 | |
687 | if (!mem) |
688 | die("realloc of %ld entries for relocs failed\n", newsize); |
689 | |
690 | r->offset = mem; |
691 | r->size = newsize; |
692 | } |
693 | r->offset[r->count++] = offset; |
694 | } |
695 | |
696 | static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, |
697 | Elf_Sym *sym, const char *symname)) |
698 | { |
699 | int i; |
700 | |
701 | /* Walk through the relocations */ |
702 | for (i = 0; i < shnum; i++) { |
703 | char *sym_strtab; |
704 | Elf_Sym *sh_symtab; |
705 | struct section *sec_applies, *sec_symtab; |
706 | int j; |
707 | struct section *sec = &secs[i]; |
708 | |
709 | if (sec->shdr.sh_type != SHT_REL_TYPE) |
710 | continue; |
711 | |
712 | sec_symtab = sec->link; |
713 | sec_applies = &secs[sec->shdr.sh_info]; |
714 | if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) |
715 | continue; |
716 | |
717 | /* |
718 | * Do not perform relocations in .notes sections; any |
719 | * values there are meant for pre-boot consumption (e.g. |
720 | * startup_xen). |
721 | */ |
722 | if (sec_applies->shdr.sh_type == SHT_NOTE) |
723 | continue; |
724 | |
725 | sh_symtab = sec_symtab->symtab; |
726 | sym_strtab = sec_symtab->link->strtab; |
727 | |
728 | for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { |
729 | Elf_Rel *rel = &sec->reltab[j]; |
730 | Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; |
731 | const char *symname = sym_name(sym_strtab, sym); |
732 | |
733 | process(sec, rel, sym, symname); |
734 | } |
735 | } |
736 | } |
737 | |
738 | #if ELF_BITS == 64 |
739 | |
740 | static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, |
741 | const char *symname) |
742 | { |
743 | int headtext = !strcmp(sec_name(sec->shdr.sh_info), ".head.text"); |
744 | unsigned r_type = ELF64_R_TYPE(rel->r_info); |
745 | ElfW(Addr) offset = rel->r_offset; |
746 | int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); |
747 | if (sym->st_shndx == SHN_UNDEF) |
748 | return 0; |
749 | |
750 | switch (r_type) { |
751 | case R_X86_64_NONE: |
752 | /* NONE can be ignored. */ |
753 | break; |
754 | |
755 | case R_X86_64_PC32: |
756 | case R_X86_64_PLT32: |
757 | case R_X86_64_REX_GOTPCRELX: |
758 | /* |
759 | * PC relative relocations don't need to be adjusted. |
760 | * |
761 | * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32. |
762 | */ |
763 | break; |
764 | |
765 | case R_X86_64_PC64: |
766 | /* |
767 | * Only used by jump labels |
768 | */ |
769 | break; |
770 | |
771 | case R_X86_64_32: |
772 | case R_X86_64_32S: |
773 | case R_X86_64_64: |
774 | if (shn_abs) { |
775 | /* |
776 | * Whitelisted absolute symbols do not require |
777 | * relocation. |
778 | */ |
779 | if (is_reloc(S_ABS, symname)) |
780 | break; |
781 | |
782 | die("Invalid absolute %s relocation: %s\n", rel_type(r_type), symname); |
783 | break; |
784 | } |
785 | |
786 | if (headtext) { |
787 | die("Absolute reference to symbol '%s' not permitted in .head.text\n", |
788 | symname); |
789 | break; |
790 | } |
791 | |
792 | /* |
793 | * Relocation offsets for 64 bit kernels are output |
794 | * as 32 bits and sign extended back to 64 bits when |
795 | * the relocations are processed. |
796 | * Make sure that the offset will fit. |
797 | */ |
798 | if ((int32_t)offset != (int64_t)offset) |
799 | die("Relocation offset doesn't fit in 32 bits\n"); |
800 | |
801 | if (r_type == R_X86_64_64) |
802 | add_reloc(&relocs64, offset); |
803 | else |
804 | add_reloc(&relocs32, offset); |
805 | break; |
806 | |
807 | default: |
808 | die("Unsupported relocation type: %s (%d)\n", rel_type(r_type), r_type); |
809 | break; |
810 | } |
811 | |
812 | return 0; |
813 | } |
814 | |
815 | #else |
816 | |
817 | static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, |
818 | const char *symname) |
819 | { |
820 | unsigned r_type = ELF32_R_TYPE(rel->r_info); |
821 | int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); |
822 | |
823 | switch (r_type) { |
824 | case R_386_NONE: |
825 | case R_386_PC32: |
826 | case R_386_PC16: |
827 | case R_386_PC8: |
828 | case R_386_PLT32: |
829 | /* |
830 | * NONE can be ignored and PC relative relocations don't need |
831 | * to be adjusted. Because sym must be defined, R_386_PLT32 can |
832 | * be treated the same way as R_386_PC32. |
833 | */ |
834 | break; |
835 | |
836 | case R_386_32: |
837 | if (shn_abs) { |
838 | /* |
839 | * Whitelisted absolute symbols do not require |
840 | * relocation. |
841 | */ |
842 | if (is_reloc(S_ABS, symname)) |
843 | break; |
844 | |
845 | die("Invalid absolute %s relocation: %s\n", rel_type(type: r_type), symname); |
846 | break; |
847 | } |
848 | |
849 | add_reloc(&relocs32, rel->r_offset); |
850 | break; |
851 | |
852 | default: |
853 | die("Unsupported relocation type: %s (%d)\n", rel_type(type: r_type), r_type); |
854 | break; |
855 | } |
856 | |
857 | return 0; |
858 | } |
859 | |
860 | static int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, const char *symname) |
861 | { |
862 | unsigned r_type = ELF32_R_TYPE(rel->r_info); |
863 | int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); |
864 | |
865 | switch (r_type) { |
866 | case R_386_NONE: |
867 | case R_386_PC32: |
868 | case R_386_PC16: |
869 | case R_386_PC8: |
870 | case R_386_PLT32: |
871 | /* |
872 | * NONE can be ignored and PC relative relocations don't need |
873 | * to be adjusted. Because sym must be defined, R_386_PLT32 can |
874 | * be treated the same way as R_386_PC32. |
875 | */ |
876 | break; |
877 | |
878 | case R_386_16: |
879 | if (shn_abs) { |
880 | /* |
881 | * Whitelisted absolute symbols do not require |
882 | * relocation. |
883 | */ |
884 | if (is_reloc(S_ABS, symname)) |
885 | break; |
886 | |
887 | if (is_reloc(S_SEG, symname)) { |
888 | add_reloc(&relocs16, rel->r_offset); |
889 | break; |
890 | } |
891 | } else { |
892 | if (!is_reloc(S_LIN, symname)) |
893 | break; |
894 | } |
895 | die("Invalid %s %s relocation: %s\n", shn_abs ? "absolute": "relative", rel_type(type: r_type), symname); |
896 | break; |
897 | |
898 | case R_386_32: |
899 | if (shn_abs) { |
900 | /* |
901 | * Whitelisted absolute symbols do not require |
902 | * relocation. |
903 | */ |
904 | if (is_reloc(S_ABS, symname)) |
905 | break; |
906 | |
907 | if (is_reloc(S_REL, symname)) { |
908 | add_reloc(&relocs32, rel->r_offset); |
909 | break; |
910 | } |
911 | } else { |
912 | if (is_reloc(S_LIN, symname)) |
913 | add_reloc(&relocs32, rel->r_offset); |
914 | break; |
915 | } |
916 | die("Invalid %s %s relocation: %s\n", shn_abs ? "absolute": "relative", rel_type(type: r_type), symname); |
917 | break; |
918 | |
919 | default: |
920 | die("Unsupported relocation type: %s (%d)\n", rel_type(type: r_type), r_type); |
921 | break; |
922 | } |
923 | |
924 | return 0; |
925 | } |
926 | |
927 | #endif |
928 | |
929 | static int cmp_relocs(const void *va, const void *vb) |
930 | { |
931 | const uint32_t *a, *b; |
932 | |
933 | a = va; |
934 | b = vb; |
935 | |
936 | return (*a == *b)? 0 : (*a > *b)? 1 : -1; |
937 | } |
938 | |
939 | static void sort_relocs(struct relocs *r) |
940 | { |
941 | if (r->count) |
942 | qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs); |
943 | } |
944 | |
945 | static int write32(uint32_t v, FILE *f) |
946 | { |
947 | unsigned char buf[4]; |
948 | |
949 | put_unaligned_le32(v, buf); |
950 | |
951 | return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; |
952 | } |
953 | |
954 | static int write32_as_text(uint32_t v, FILE *f) |
955 | { |
956 | return fprintf(f, "\t.long 0x%08"PRIx32 "\n", v) > 0 ? 0 : -1; |
957 | } |
958 | |
959 | static void emit_relocs(int as_text, int use_real_mode) |
960 | { |
961 | int i; |
962 | int (*write_reloc)(uint32_t, FILE *) = write32; |
963 | int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, const char *symname); |
964 | |
965 | #if ELF_BITS == 64 |
966 | if (!use_real_mode) |
967 | do_reloc = do_reloc64; |
968 | else |
969 | die("--realmode not valid for a 64-bit ELF file"); |
970 | #else |
971 | if (!use_real_mode) |
972 | do_reloc = do_reloc32; |
973 | else |
974 | do_reloc = do_reloc_real; |
975 | #endif |
976 | |
977 | /* Collect up the relocations */ |
978 | walk_relocs(process: do_reloc); |
979 | |
980 | if (relocs16.count && !use_real_mode) |
981 | die("Segment relocations found but --realmode not specified\n"); |
982 | |
983 | /* Order the relocations for more efficient processing */ |
984 | sort_relocs(r: &relocs32); |
985 | #if ELF_BITS == 64 |
986 | sort_relocs(&relocs64); |
987 | #else |
988 | sort_relocs(r: &relocs16); |
989 | #endif |
990 | |
991 | /* Print the relocations */ |
992 | if (as_text) { |
993 | /* Print the relocations in a form suitable that |
994 | * gas will like. |
995 | */ |
996 | printf(".section \".data.reloc\",\"a\"\n"); |
997 | printf(".balign 4\n"); |
998 | write_reloc = write32_as_text; |
999 | } |
1000 | |
1001 | if (use_real_mode) { |
1002 | write_reloc(relocs16.count, stdout); |
1003 | for (i = 0; i < relocs16.count; i++) |
1004 | write_reloc(relocs16.offset[i], stdout); |
1005 | |
1006 | write_reloc(relocs32.count, stdout); |
1007 | for (i = 0; i < relocs32.count; i++) |
1008 | write_reloc(relocs32.offset[i], stdout); |
1009 | } else { |
1010 | #if ELF_BITS == 64 |
1011 | /* Print a stop */ |
1012 | write_reloc(0, stdout); |
1013 | |
1014 | /* Now print each relocation */ |
1015 | for (i = 0; i < relocs64.count; i++) |
1016 | write_reloc(relocs64.offset[i], stdout); |
1017 | #endif |
1018 | |
1019 | /* Print a stop */ |
1020 | write_reloc(0, stdout); |
1021 | |
1022 | /* Now print each relocation */ |
1023 | for (i = 0; i < relocs32.count; i++) |
1024 | write_reloc(relocs32.offset[i], stdout); |
1025 | } |
1026 | } |
1027 | |
1028 | /* |
1029 | * As an aid to debugging problems with different linkers |
1030 | * print summary information about the relocs. |
1031 | * Since different linkers tend to emit the sections in |
1032 | * different orders we use the section names in the output. |
1033 | */ |
1034 | static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, |
1035 | const char *symname) |
1036 | { |
1037 | printf("%s\t%s\t%s\t%s\n", |
1038 | sec_name(shndx: sec->shdr.sh_info), |
1039 | rel_type(type: ELF_R_TYPE(rel->r_info)), |
1040 | symname, |
1041 | sec_name(shndx: sym_index(sym))); |
1042 | |
1043 | return 0; |
1044 | } |
1045 | |
1046 | static void print_reloc_info(void) |
1047 | { |
1048 | printf("reloc section\treloc type\tsymbol\tsymbol section\n"); |
1049 | walk_relocs(process: do_reloc_info); |
1050 | } |
1051 | |
1052 | #if ELF_BITS == 64 |
1053 | # define process process_64 |
1054 | #else |
1055 | # define process process_32 |
1056 | #endif |
1057 | |
1058 | void process(FILE *fp, int use_real_mode, int as_text, |
1059 | int show_absolute_syms, int show_absolute_relocs, |
1060 | int show_reloc_info) |
1061 | { |
1062 | regex_init(use_real_mode); |
1063 | read_ehdr(fp); |
1064 | read_shdrs(fp); |
1065 | read_strtabs(fp); |
1066 | read_symtabs(fp); |
1067 | read_relocs(fp); |
1068 | |
1069 | if (show_absolute_syms) { |
1070 | print_absolute_symbols(); |
1071 | return; |
1072 | } |
1073 | |
1074 | if (show_absolute_relocs) { |
1075 | print_absolute_relocs(); |
1076 | return; |
1077 | } |
1078 | |
1079 | if (show_reloc_info) { |
1080 | print_reloc_info(); |
1081 | return; |
1082 | } |
1083 | |
1084 | emit_relocs(as_text, use_real_mode); |
1085 | } |
1086 |
Definitions
- ehdr
- shnum
- shstrndx
- shsymtabndx
- shxsymtabndx
- relocs
- relocs16
- relocs32
- section
- secs
- sym_regex_kernel
- sym_regex_realmode
- sym_regex
- sym_regex_c
- is_reloc
- regex_init
- sym_type
- sym_bind
- sym_visibility
- rel_type
- sec_name
- sym_name
- elf16_to_cpu
- elf32_to_cpu
- sym_index
- read_ehdr
- read_shdrs
- read_strtabs
- read_symtabs
- read_relocs
- print_absolute_symbols
- print_absolute_relocs
- add_reloc
- walk_relocs
- do_reloc32
- do_reloc_real
- cmp_relocs
- sort_relocs
- write32
- write32_as_text
- emit_relocs
- do_reloc_info
- print_reloc_info
Improve your Profiling and Debugging skills
Find out more