1#include <stdio.h> 2#include <stdarg.h> 3#include <stdlib.h> 4#include <stdint.h> 5#include <string.h> 6#include <errno.h> 7#include <unistd.h> 8#include <elf.h> 9#include <byteswap.h> 10#define USE_BSD 11#include <endian.h> 12#include <regex.h> 13 14static void die(char *fmt, ...); 15 16#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 17static Elf32_Ehdr ehdr; 18static unsigned long reloc_count, reloc_idx; 19static unsigned long *relocs; 20 21struct section { 22 Elf32_Shdr shdr; 23 struct section *link; 24 Elf32_Sym *symtab; 25 Elf32_Rel *reltab; 26 char *strtab; 27}; 28static struct section *secs; 29 30/* 31 * Following symbols have been audited. There values are constant and do 32 * not change if bzImage is loaded at a different physical address than 33 * the address for which it has been compiled. Don't warn user about 34 * absolute relocations present w.r.t these symbols. 35 */ 36static const char abs_sym_regex[] = 37 "^(xen_irq_disable_direct_reloc$|" 38 "xen_save_fl_direct_reloc$|" 39 "VDSO|" 40 "__crc_)"; 41static regex_t abs_sym_regex_c; 42static int is_abs_reloc(const char *sym_name) 43{ 44 return !regexec(&abs_sym_regex_c, sym_name, 0, NULL, 0); 45} 46 47/* 48 * These symbols are known to be relative, even if the linker marks them 49 * as absolute (typically defined outside any section in the linker script.) 50 */ 51static const char rel_sym_regex[] = 52 "^_end$"; 53static regex_t rel_sym_regex_c; 54static int is_rel_reloc(const char *sym_name) 55{ 56 return !regexec(&rel_sym_regex_c, sym_name, 0, NULL, 0); 57} 58 59static void regex_init(void) 60{ 61 char errbuf[128]; 62 int err; 63 64 err = regcomp(&abs_sym_regex_c, abs_sym_regex, 65 REG_EXTENDED|REG_NOSUB); 66 if (err) { 67 regerror(err, &abs_sym_regex_c, errbuf, sizeof errbuf); 68 die("%s", errbuf); 69 } 70 71 err = regcomp(&rel_sym_regex_c, rel_sym_regex, 72 REG_EXTENDED|REG_NOSUB); 73 if (err) { 74 regerror(err, &rel_sym_regex_c, errbuf, sizeof errbuf); 75 die("%s", errbuf); 76 } 77} 78 79static void die(char *fmt, ...) 80{ 81 va_list ap; 82 va_start(ap, fmt); 83 vfprintf(stderr, fmt, ap); 84 va_end(ap); 85 exit(1); 86} 87 88static const char *sym_type(unsigned type) 89{ 90 static const char *type_name[] = { 91#define SYM_TYPE(X) [X] = #X 92 SYM_TYPE(STT_NOTYPE), 93 SYM_TYPE(STT_OBJECT), 94 SYM_TYPE(STT_FUNC), 95 SYM_TYPE(STT_SECTION), 96 SYM_TYPE(STT_FILE), 97 SYM_TYPE(STT_COMMON), 98 SYM_TYPE(STT_TLS), 99#undef SYM_TYPE 100 }; 101 const char *name = "unknown sym type name"; 102 if (type < ARRAY_SIZE(type_name)) { 103 name = type_name[type]; 104 } 105 return name; 106} 107 108static const char *sym_bind(unsigned bind) 109{ 110 static const char *bind_name[] = { 111#define SYM_BIND(X) [X] = #X 112 SYM_BIND(STB_LOCAL), 113 SYM_BIND(STB_GLOBAL), 114 SYM_BIND(STB_WEAK), 115#undef SYM_BIND 116 }; 117 const char *name = "unknown sym bind name"; 118 if (bind < ARRAY_SIZE(bind_name)) { 119 name = bind_name[bind]; 120 } 121 return name; 122} 123 124static const char *sym_visibility(unsigned visibility) 125{ 126 static const char *visibility_name[] = { 127#define SYM_VISIBILITY(X) [X] = #X 128 SYM_VISIBILITY(STV_DEFAULT), 129 SYM_VISIBILITY(STV_INTERNAL), 130 SYM_VISIBILITY(STV_HIDDEN), 131 SYM_VISIBILITY(STV_PROTECTED), 132#undef SYM_VISIBILITY 133 }; 134 const char *name = "unknown sym visibility name"; 135 if (visibility < ARRAY_SIZE(visibility_name)) { 136 name = visibility_name[visibility]; 137 } 138 return name; 139} 140 141static const char *rel_type(unsigned type) 142{ 143 static const char *type_name[] = { 144#define REL_TYPE(X) [X] = #X 145 REL_TYPE(R_386_NONE), 146 REL_TYPE(R_386_32), 147 REL_TYPE(R_386_PC32), 148 REL_TYPE(R_386_GOT32), 149 REL_TYPE(R_386_PLT32), 150 REL_TYPE(R_386_COPY), 151 REL_TYPE(R_386_GLOB_DAT), 152 REL_TYPE(R_386_JMP_SLOT), 153 REL_TYPE(R_386_RELATIVE), 154 REL_TYPE(R_386_GOTOFF), 155 REL_TYPE(R_386_GOTPC), 156#undef REL_TYPE 157 }; 158 const char *name = "unknown type rel type name"; 159 if (type < ARRAY_SIZE(type_name) && type_name[type]) { 160 name = type_name[type]; 161 } 162 return name; 163} 164 165static const char *sec_name(unsigned shndx) 166{ 167 const char *sec_strtab; 168 const char *name; 169 sec_strtab = secs[ehdr.e_shstrndx].strtab; 170 name = "<noname>"; 171 if (shndx < ehdr.e_shnum) { 172 name = sec_strtab + secs[shndx].shdr.sh_name; 173 } 174 else if (shndx == SHN_ABS) { 175 name = "ABSOLUTE"; 176 } 177 else if (shndx == SHN_COMMON) { 178 name = "COMMON"; 179 } 180 return name; 181} 182 183static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) 184{ 185 const char *name; 186 name = "<noname>"; 187 if (sym->st_name) { 188 name = sym_strtab + sym->st_name; 189 } 190 else { 191 name = sec_name(secs[sym->st_shndx].shdr.sh_name); 192 } 193 return name; 194} 195 196 197 198#if BYTE_ORDER == LITTLE_ENDIAN 199#define le16_to_cpu(val) (val) 200#define le32_to_cpu(val) (val) 201#endif 202#if BYTE_ORDER == BIG_ENDIAN 203#define le16_to_cpu(val) bswap_16(val) 204#define le32_to_cpu(val) bswap_32(val) 205#endif 206 207static uint16_t elf16_to_cpu(uint16_t val) 208{ 209 return le16_to_cpu(val); 210} 211 212static uint32_t elf32_to_cpu(uint32_t val) 213{ 214 return le32_to_cpu(val); 215} 216 217static void read_ehdr(FILE *fp) 218{ 219 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { 220 die("Cannot read ELF header: %s\n", 221 strerror(errno)); 222 } 223 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { 224 die("No ELF magic\n"); 225 } 226 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { 227 die("Not a 32 bit executable\n"); 228 } 229 if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { 230 die("Not a LSB ELF executable\n"); 231 } 232 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { 233 die("Unknown ELF version\n"); 234 } 235 /* Convert the fields to native endian */ 236 ehdr.e_type = elf16_to_cpu(ehdr.e_type); 237 ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); 238 ehdr.e_version = elf32_to_cpu(ehdr.e_version); 239 ehdr.e_entry = elf32_to_cpu(ehdr.e_entry); 240 ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff); 241 ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff); 242 ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); 243 ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); 244 ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); 245 ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); 246 ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); 247 ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); 248 ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); 249 250 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { 251 die("Unsupported ELF header type\n"); 252 } 253 if (ehdr.e_machine != EM_386) { 254 die("Not for x86\n"); 255 } 256 if (ehdr.e_version != EV_CURRENT) { 257 die("Unknown ELF version\n"); 258 } 259 if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) { 260 die("Bad Elf header size\n"); 261 } 262 if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) { 263 die("Bad program header entry\n"); 264 } 265 if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) { 266 die("Bad section header entry\n"); 267 } 268 if (ehdr.e_shstrndx >= ehdr.e_shnum) { 269 die("String table index out of bounds\n"); 270 } 271} 272 273static void read_shdrs(FILE *fp) 274{ 275 int i; 276 Elf32_Shdr shdr; 277 278 secs = calloc(ehdr.e_shnum, sizeof(struct section)); 279 if (!secs) { 280 die("Unable to allocate %d section headers\n", 281 ehdr.e_shnum); 282 } 283 if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { 284 die("Seek to %d failed: %s\n", 285 ehdr.e_shoff, strerror(errno)); 286 } 287 for (i = 0; i < ehdr.e_shnum; i++) { 288 struct section *sec = &secs[i]; 289 if (fread(&shdr, sizeof shdr, 1, fp) != 1) 290 die("Cannot read ELF section headers %d/%d: %s\n", 291 i, ehdr.e_shnum, strerror(errno)); 292 sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name); 293 sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type); 294 sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags); 295 sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr); 296 sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset); 297 sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size); 298 sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link); 299 sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info); 300 sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign); 301 sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize); 302 if (sec->shdr.sh_link < ehdr.e_shnum) 303 sec->link = &secs[sec->shdr.sh_link]; 304 } 305 306} 307 308static void read_strtabs(FILE *fp) 309{ 310 int i; 311 for (i = 0; i < ehdr.e_shnum; i++) { 312 struct section *sec = &secs[i]; 313 if (sec->shdr.sh_type != SHT_STRTAB) { 314 continue; 315 } 316 sec->strtab = malloc(sec->shdr.sh_size); 317 if (!sec->strtab) { 318 die("malloc of %d bytes for strtab failed\n", 319 sec->shdr.sh_size); 320 } 321 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 322 die("Seek to %d failed: %s\n", 323 sec->shdr.sh_offset, strerror(errno)); 324 } 325 if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) 326 != sec->shdr.sh_size) { 327 die("Cannot read symbol table: %s\n", 328 strerror(errno)); 329 } 330 } 331} 332 333static void read_symtabs(FILE *fp) 334{ 335 int i,j; 336 for (i = 0; i < ehdr.e_shnum; i++) { 337 struct section *sec = &secs[i]; 338 if (sec->shdr.sh_type != SHT_SYMTAB) { 339 continue; 340 } 341 sec->symtab = malloc(sec->shdr.sh_size); 342 if (!sec->symtab) { 343 die("malloc of %d bytes for symtab failed\n", 344 sec->shdr.sh_size); 345 } 346 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 347 die("Seek to %d failed: %s\n", 348 sec->shdr.sh_offset, strerror(errno)); 349 } 350 if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) 351 != sec->shdr.sh_size) { 352 die("Cannot read symbol table: %s\n", 353 strerror(errno)); 354 } 355 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { 356 Elf32_Sym *sym = &sec->symtab[j]; 357 sym->st_name = elf32_to_cpu(sym->st_name); 358 sym->st_value = elf32_to_cpu(sym->st_value); 359 sym->st_size = elf32_to_cpu(sym->st_size); 360 sym->st_shndx = elf16_to_cpu(sym->st_shndx); 361 } 362 } 363} 364 365 366static void read_relocs(FILE *fp) 367{ 368 int i,j; 369 for (i = 0; i < ehdr.e_shnum; i++) { 370 struct section *sec = &secs[i]; 371 if (sec->shdr.sh_type != SHT_REL) { 372 continue; 373 } 374 sec->reltab = malloc(sec->shdr.sh_size); 375 if (!sec->reltab) { 376 die("malloc of %d bytes for relocs failed\n", 377 sec->shdr.sh_size); 378 } 379 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 380 die("Seek to %d failed: %s\n", 381 sec->shdr.sh_offset, strerror(errno)); 382 } 383 if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) 384 != sec->shdr.sh_size) { 385 die("Cannot read symbol table: %s\n", 386 strerror(errno)); 387 } 388 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 389 Elf32_Rel *rel = &sec->reltab[j]; 390 rel->r_offset = elf32_to_cpu(rel->r_offset); 391 rel->r_info = elf32_to_cpu(rel->r_info); 392 } 393 } 394} 395 396 397static void print_absolute_symbols(void) 398{ 399 int i; 400 printf("Absolute symbols\n"); 401 printf(" Num: Value Size Type Bind Visibility Name\n"); 402 for (i = 0; i < ehdr.e_shnum; i++) { 403 struct section *sec = &secs[i]; 404 char *sym_strtab; 405 Elf32_Sym *sh_symtab; 406 int j; 407 408 if (sec->shdr.sh_type != SHT_SYMTAB) { 409 continue; 410 } 411 sh_symtab = sec->symtab; 412 sym_strtab = sec->link->strtab; 413 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { 414 Elf32_Sym *sym; 415 const char *name; 416 sym = &sec->symtab[j]; 417 name = sym_name(sym_strtab, sym); 418 if (sym->st_shndx != SHN_ABS) { 419 continue; 420 } 421 printf("%5d %08x %5d %10s %10s %12s %s\n", 422 j, sym->st_value, sym->st_size, 423 sym_type(ELF32_ST_TYPE(sym->st_info)), 424 sym_bind(ELF32_ST_BIND(sym->st_info)), 425 sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)), 426 name); 427 } 428 } 429 printf("\n"); 430} 431 432static void print_absolute_relocs(void) 433{ 434 int i, printed = 0; 435 436 for (i = 0; i < ehdr.e_shnum; i++) { 437 struct section *sec = &secs[i]; 438 struct section *sec_applies, *sec_symtab; 439 char *sym_strtab; 440 Elf32_Sym *sh_symtab; 441 int j; 442 if (sec->shdr.sh_type != SHT_REL) { 443 continue; 444 } 445 sec_symtab = sec->link; 446 sec_applies = &secs[sec->shdr.sh_info]; 447 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 448 continue; 449 } 450 sh_symtab = sec_symtab->symtab; 451 sym_strtab = sec_symtab->link->strtab; 452 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 453 Elf32_Rel *rel; 454 Elf32_Sym *sym; 455 const char *name; 456 rel = &sec->reltab[j]; 457 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; 458 name = sym_name(sym_strtab, sym); 459 if (sym->st_shndx != SHN_ABS) { 460 continue; 461 } 462 463 /* Absolute symbols are not relocated if bzImage is 464 * loaded at a non-compiled address. Display a warning 465 * to user at compile time about the absolute 466 * relocations present. 467 * 468 * User need to audit the code to make sure 469 * some symbols which should have been section 470 * relative have not become absolute because of some 471 * linker optimization or wrong programming usage. 472 * 473 * Before warning check if this absolute symbol 474 * relocation is harmless. 475 */ 476 if (is_abs_reloc(name) || is_rel_reloc(name)) 477 continue; 478 479 if (!printed) { 480 printf("WARNING: Absolute relocations" 481 " present\n"); 482 printf("Offset Info Type Sym.Value " 483 "Sym.Name\n"); 484 printed = 1; 485 } 486 487 printf("%08x %08x %10s %08x %s\n", 488 rel->r_offset, 489 rel->r_info, 490 rel_type(ELF32_R_TYPE(rel->r_info)), 491 sym->st_value, 492 name); 493 } 494 } 495 496 if (printed) 497 printf("\n"); 498} 499 500static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) 501{ 502 int i; 503 /* Walk through the relocations */ 504 for (i = 0; i < ehdr.e_shnum; i++) { 505 char *sym_strtab; 506 Elf32_Sym *sh_symtab; 507 struct section *sec_applies, *sec_symtab; 508 int j; 509 struct section *sec = &secs[i]; 510 511 if (sec->shdr.sh_type != SHT_REL) { 512 continue; 513 } 514 sec_symtab = sec->link; 515 sec_applies = &secs[sec->shdr.sh_info]; 516 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 517 continue; 518 } 519 sh_symtab = sec_symtab->symtab; 520 sym_strtab = sec_symtab->link->strtab; 521 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 522 Elf32_Rel *rel; 523 Elf32_Sym *sym; 524 unsigned r_type; 525 rel = &sec->reltab[j]; 526 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; 527 r_type = ELF32_R_TYPE(rel->r_info); 528 /* Don't visit relocations to absolute symbols */ 529 if (sym->st_shndx == SHN_ABS && 530 !is_rel_reloc(sym_name(sym_strtab, sym))) { 531 continue; 532 } 533 switch (r_type) { 534 case R_386_NONE: 535 case R_386_PC32: 536 /* 537 * NONE can be ignored and and PC relative 538 * relocations don't need to be adjusted. 539 */ 540 break; 541 case R_386_32: 542 /* Visit relocations that need to be adjusted */ 543 visit(rel, sym); 544 break; 545 default: 546 die("Unsupported relocation type: %s (%d)\n", 547 rel_type(r_type), r_type); 548 break; 549 } 550 } 551 } 552} 553 554static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 555{ 556 reloc_count += 1; 557} 558 559static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 560{ 561 /* Remember the address that needs to be adjusted. */ 562 relocs[reloc_idx++] = rel->r_offset; 563} 564 565static int cmp_relocs(const void *va, const void *vb) 566{ 567 const unsigned long *a, *b; 568 a = va; b = vb; 569 return (*a == *b)? 0 : (*a > *b)? 1 : -1; 570} 571 572static void emit_relocs(int as_text) 573{ 574 int i; 575 /* Count how many relocations I have and allocate space for them. */ 576 reloc_count = 0; 577 walk_relocs(count_reloc); 578 relocs = malloc(reloc_count * sizeof(relocs[0])); 579 if (!relocs) { 580 die("malloc of %d entries for relocs failed\n", 581 reloc_count); 582 } 583 /* Collect up the relocations */ 584 reloc_idx = 0; 585 walk_relocs(collect_reloc); 586 587 /* Order the relocations for more efficient processing */ 588 qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); 589 590 /* Print the relocations */ 591 if (as_text) { 592 /* Print the relocations in a form suitable that 593 * gas will like. 594 */ 595 printf(".section \".data.reloc\",\"a\"\n"); 596 printf(".balign 4\n"); 597 for (i = 0; i < reloc_count; i++) { 598 printf("\t .long 0x%08lx\n", relocs[i]); 599 } 600 printf("\n"); 601 } 602 else { 603 unsigned char buf[4]; 604 /* Print a stop */ 605 fwrite("\0\0\0\0", 4, 1, stdout); 606 /* Now print each relocation */ 607 for (i = 0; i < reloc_count; i++) { 608 buf[0] = (relocs[i] >> 0) & 0xff; 609 buf[1] = (relocs[i] >> 8) & 0xff; 610 buf[2] = (relocs[i] >> 16) & 0xff; 611 buf[3] = (relocs[i] >> 24) & 0xff; 612 fwrite(buf, 4, 1, stdout); 613 } 614 } 615} 616 617static void usage(void) 618{ 619 die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n"); 620} 621 622int main(int argc, char **argv) 623{ 624 int show_absolute_syms, show_absolute_relocs; 625 int as_text; 626 const char *fname; 627 FILE *fp; 628 int i; 629 630 regex_init(); 631 632 show_absolute_syms = 0; 633 show_absolute_relocs = 0; 634 as_text = 0; 635 fname = NULL; 636 for (i = 1; i < argc; i++) { 637 char *arg = argv[i]; 638 if (*arg == '-') { 639 if (strcmp(argv[1], "--abs-syms") == 0) { 640 show_absolute_syms = 1; 641 continue; 642 } 643 644 if (strcmp(argv[1], "--abs-relocs") == 0) { 645 show_absolute_relocs = 1; 646 continue; 647 } 648 else if (strcmp(argv[1], "--text") == 0) { 649 as_text = 1; 650 continue; 651 } 652 } 653 else if (!fname) { 654 fname = arg; 655 continue; 656 } 657 usage(); 658 } 659 if (!fname) { 660 usage(); 661 } 662 fp = fopen(fname, "r"); 663 if (!fp) { 664 die("Cannot open %s: %s\n", 665 fname, strerror(errno)); 666 } 667 read_ehdr(fp); 668 read_shdrs(fp); 669 read_strtabs(fp); 670 read_symtabs(fp); 671 read_relocs(fp); 672 if (show_absolute_syms) { 673 print_absolute_symbols(); 674 return 0; 675 } 676 if (show_absolute_relocs) { 677 print_absolute_relocs(); 678 return 0; 679 } 680 emit_relocs(as_text); 681 return 0; 682} 683