1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2c889ba80SH. Peter Anvin /* This is included from relocs_32/64.c */ 36520fe55SH. Peter Anvin 4bf11655cSKees Cook #define ElfW(type) _ElfW(ELF_BITS, type) 5bf11655cSKees Cook #define _ElfW(bits, type) __ElfW(bits, type) 6bf11655cSKees Cook #define __ElfW(bits, type) Elf##bits##_##type 7bf11655cSKees Cook 8946166afSKees Cook #define Elf_Addr ElfW(Addr) 9bf11655cSKees Cook #define Elf_Ehdr ElfW(Ehdr) 10bf11655cSKees Cook #define Elf_Phdr ElfW(Phdr) 11bf11655cSKees Cook #define Elf_Shdr ElfW(Shdr) 12bf11655cSKees Cook #define Elf_Sym ElfW(Sym) 13bf11655cSKees Cook 14bf11655cSKees Cook static Elf_Ehdr ehdr; 15f36e7495SArtem Savkov static unsigned long shnum; 16f36e7495SArtem Savkov static unsigned int shstrndx; 17a54c401aSKristen Carlson Accardi static unsigned int shsymtabndx; 18a54c401aSKristen Carlson Accardi static unsigned int shxsymtabndx; 19a54c401aSKristen Carlson Accardi 20a54c401aSKristen Carlson Accardi static int sym_index(Elf_Sym *sym); 215d442e63SKees Cook 225d442e63SKees Cook struct relocs { 235d442e63SKees Cook uint32_t *offset; 245d442e63SKees Cook unsigned long count; 255d442e63SKees Cook unsigned long size; 265d442e63SKees Cook }; 275d442e63SKees Cook 285d442e63SKees Cook static struct relocs relocs16; 295d442e63SKees Cook static struct relocs relocs32; 306d24c5f7SJan Beulich #if ELF_BITS == 64 316d24c5f7SJan Beulich static struct relocs relocs32neg; 32946166afSKees Cook static struct relocs relocs64; 3303dca99eSBorislav Petkov #define FMT PRIu64 3403dca99eSBorislav Petkov #else 3503dca99eSBorislav Petkov #define FMT PRIu32 366d24c5f7SJan Beulich #endif 376520fe55SH. Peter Anvin 386520fe55SH. Peter Anvin struct section { 39bf11655cSKees Cook Elf_Shdr shdr; 406520fe55SH. Peter Anvin struct section *link; 41bf11655cSKees Cook Elf_Sym *symtab; 42a54c401aSKristen Carlson Accardi Elf32_Word *xsymtab; 43bf11655cSKees Cook Elf_Rel *reltab; 446520fe55SH. Peter Anvin char *strtab; 456520fe55SH. Peter Anvin }; 466520fe55SH. Peter Anvin static struct section *secs; 476520fe55SH. Peter Anvin 486520fe55SH. Peter Anvin static const char * const sym_regex_kernel[S_NSYMTYPES] = { 496520fe55SH. Peter Anvin /* 506520fe55SH. Peter Anvin * Following symbols have been audited. There values are constant and do 516520fe55SH. Peter Anvin * not change if bzImage is loaded at a different physical address than 526520fe55SH. Peter Anvin * the address for which it has been compiled. Don't warn user about 536520fe55SH. Peter Anvin * absolute relocations present w.r.t these symbols. 546520fe55SH. Peter Anvin */ 556520fe55SH. Peter Anvin [S_ABS] = 566520fe55SH. Peter Anvin "^(xen_irq_disable_direct_reloc$|" 576520fe55SH. Peter Anvin "xen_save_fl_direct_reloc$|" 586520fe55SH. Peter Anvin "VDSO|" 59*ca7e10bfSSami Tolvanen "__kcfi_typeid_|" 606520fe55SH. Peter Anvin "__crc_)", 616520fe55SH. Peter Anvin 626520fe55SH. Peter Anvin /* 636520fe55SH. Peter Anvin * These symbols are known to be relative, even if the linker marks them 646520fe55SH. Peter Anvin * as absolute (typically defined outside any section in the linker script.) 656520fe55SH. Peter Anvin */ 666520fe55SH. Peter Anvin [S_REL] = 67a3e854d9SH. Peter Anvin "^(__init_(begin|end)|" 68a3e854d9SH. Peter Anvin "__x86_cpu_dev_(start|end)|" 69fa953adfSH. Nikolaus Schaller "(__parainstructions|__alt_instructions)(_end)?|" 70fa953adfSH. Nikolaus Schaller "(__iommu_table|__apicdrivers|__smp_locks)(_end)?|" 71fd952815SH. Peter Anvin "__(start|end)_pci_.*|" 72d6f12f83SLukas Bulwahn #if CONFIG_FW_LOADER 73fd952815SH. Peter Anvin "__(start|end)_builtin_fw|" 74c8dcf655SLuis Chamberlain #endif 75fa953adfSH. Nikolaus Schaller "__(start|stop)___ksymtab(_gpl)?|" 76fa953adfSH. Nikolaus Schaller "__(start|stop)___kcrctab(_gpl)?|" 77fd952815SH. Peter Anvin "__(start|stop)___param|" 78fd952815SH. Peter Anvin "__(start|stop)___modver|" 79fd952815SH. Peter Anvin "__(start|stop)___bug_table|" 80fd952815SH. Peter Anvin "__tracedata_(start|end)|" 81fd952815SH. Peter Anvin "__(start|stop)_notes|" 82fd952815SH. Peter Anvin "__end_rodata|" 83a29dba16SJoerg Roedel "__end_rodata_aligned|" 84fd952815SH. Peter Anvin "__initramfs_start|" 85ea17e741SH. Peter Anvin "(jiffies|jiffies_64)|" 86c889ba80SH. Peter Anvin #if ELF_BITS == 64 87946166afSKees Cook "__per_cpu_load|" 88946166afSKees Cook "init_per_cpu__.*|" 89946166afSKees Cook "__end_rodata_hpage_align|" 90946166afSKees Cook #endif 91d2312e33SStefani Seibold "__vvar_page|" 92a3e854d9SH. Peter Anvin "_end)$" 936520fe55SH. Peter Anvin }; 946520fe55SH. Peter Anvin 956520fe55SH. Peter Anvin 966520fe55SH. Peter Anvin static const char * const sym_regex_realmode[S_NSYMTYPES] = { 976520fe55SH. Peter Anvin /* 98f2604c14SJarkko Sakkinen * These symbols are known to be relative, even if the linker marks them 99f2604c14SJarkko Sakkinen * as absolute (typically defined outside any section in the linker script.) 100f2604c14SJarkko Sakkinen */ 101f2604c14SJarkko Sakkinen [S_REL] = 102f2604c14SJarkko Sakkinen "^pa_", 103f2604c14SJarkko Sakkinen 104f2604c14SJarkko Sakkinen /* 1056520fe55SH. Peter Anvin * These are 16-bit segment symbols when compiling 16-bit code. 1066520fe55SH. Peter Anvin */ 1076520fe55SH. Peter Anvin [S_SEG] = 1086520fe55SH. Peter Anvin "^real_mode_seg$", 1096520fe55SH. Peter Anvin 1106520fe55SH. Peter Anvin /* 1116520fe55SH. Peter Anvin * These are offsets belonging to segments, as opposed to linear addresses, 1126520fe55SH. Peter Anvin * when compiling 16-bit code. 1136520fe55SH. Peter Anvin */ 1146520fe55SH. Peter Anvin [S_LIN] = 1156520fe55SH. Peter Anvin "^pa_", 1166520fe55SH. Peter Anvin }; 1176520fe55SH. Peter Anvin 1186520fe55SH. Peter Anvin static const char * const *sym_regex; 1196520fe55SH. Peter Anvin 1206520fe55SH. Peter Anvin static regex_t sym_regex_c[S_NSYMTYPES]; 1216520fe55SH. Peter Anvin static int is_reloc(enum symtype type, const char *sym_name) 1226520fe55SH. Peter Anvin { 1236520fe55SH. Peter Anvin return sym_regex[type] && 1246520fe55SH. Peter Anvin !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); 1256520fe55SH. Peter Anvin } 1266520fe55SH. Peter Anvin 1276520fe55SH. Peter Anvin static void regex_init(int use_real_mode) 1286520fe55SH. Peter Anvin { 1296520fe55SH. Peter Anvin char errbuf[128]; 1306520fe55SH. Peter Anvin int err; 1316520fe55SH. Peter Anvin int i; 1326520fe55SH. Peter Anvin 1336520fe55SH. Peter Anvin if (use_real_mode) 1346520fe55SH. Peter Anvin sym_regex = sym_regex_realmode; 1356520fe55SH. Peter Anvin else 1366520fe55SH. Peter Anvin sym_regex = sym_regex_kernel; 1376520fe55SH. Peter Anvin 1386520fe55SH. Peter Anvin for (i = 0; i < S_NSYMTYPES; i++) { 1396520fe55SH. Peter Anvin if (!sym_regex[i]) 1406520fe55SH. Peter Anvin continue; 1416520fe55SH. Peter Anvin 1426520fe55SH. Peter Anvin err = regcomp(&sym_regex_c[i], sym_regex[i], 1436520fe55SH. Peter Anvin REG_EXTENDED|REG_NOSUB); 1446520fe55SH. Peter Anvin 1456520fe55SH. Peter Anvin if (err) { 1460e96f31eSJordan Borgner regerror(err, &sym_regex_c[i], errbuf, sizeof(errbuf)); 1476520fe55SH. Peter Anvin die("%s", errbuf); 1486520fe55SH. Peter Anvin } 1496520fe55SH. Peter Anvin } 1506520fe55SH. Peter Anvin } 1516520fe55SH. Peter Anvin 1526520fe55SH. Peter Anvin static const char *sym_type(unsigned type) 1536520fe55SH. Peter Anvin { 1546520fe55SH. Peter Anvin static const char *type_name[] = { 1556520fe55SH. Peter Anvin #define SYM_TYPE(X) [X] = #X 1566520fe55SH. Peter Anvin SYM_TYPE(STT_NOTYPE), 1576520fe55SH. Peter Anvin SYM_TYPE(STT_OBJECT), 1586520fe55SH. Peter Anvin SYM_TYPE(STT_FUNC), 1596520fe55SH. Peter Anvin SYM_TYPE(STT_SECTION), 1606520fe55SH. Peter Anvin SYM_TYPE(STT_FILE), 1616520fe55SH. Peter Anvin SYM_TYPE(STT_COMMON), 1626520fe55SH. Peter Anvin SYM_TYPE(STT_TLS), 1636520fe55SH. Peter Anvin #undef SYM_TYPE 1646520fe55SH. Peter Anvin }; 1656520fe55SH. Peter Anvin const char *name = "unknown sym type name"; 1666520fe55SH. Peter Anvin if (type < ARRAY_SIZE(type_name)) { 1676520fe55SH. Peter Anvin name = type_name[type]; 1686520fe55SH. Peter Anvin } 1696520fe55SH. Peter Anvin return name; 1706520fe55SH. Peter Anvin } 1716520fe55SH. Peter Anvin 1726520fe55SH. Peter Anvin static const char *sym_bind(unsigned bind) 1736520fe55SH. Peter Anvin { 1746520fe55SH. Peter Anvin static const char *bind_name[] = { 1756520fe55SH. Peter Anvin #define SYM_BIND(X) [X] = #X 1766520fe55SH. Peter Anvin SYM_BIND(STB_LOCAL), 1776520fe55SH. Peter Anvin SYM_BIND(STB_GLOBAL), 1786520fe55SH. Peter Anvin SYM_BIND(STB_WEAK), 1796520fe55SH. Peter Anvin #undef SYM_BIND 1806520fe55SH. Peter Anvin }; 1816520fe55SH. Peter Anvin const char *name = "unknown sym bind name"; 1826520fe55SH. Peter Anvin if (bind < ARRAY_SIZE(bind_name)) { 1836520fe55SH. Peter Anvin name = bind_name[bind]; 1846520fe55SH. Peter Anvin } 1856520fe55SH. Peter Anvin return name; 1866520fe55SH. Peter Anvin } 1876520fe55SH. Peter Anvin 1886520fe55SH. Peter Anvin static const char *sym_visibility(unsigned visibility) 1896520fe55SH. Peter Anvin { 1906520fe55SH. Peter Anvin static const char *visibility_name[] = { 1916520fe55SH. Peter Anvin #define SYM_VISIBILITY(X) [X] = #X 1926520fe55SH. Peter Anvin SYM_VISIBILITY(STV_DEFAULT), 1936520fe55SH. Peter Anvin SYM_VISIBILITY(STV_INTERNAL), 1946520fe55SH. Peter Anvin SYM_VISIBILITY(STV_HIDDEN), 1956520fe55SH. Peter Anvin SYM_VISIBILITY(STV_PROTECTED), 1966520fe55SH. Peter Anvin #undef SYM_VISIBILITY 1976520fe55SH. Peter Anvin }; 1986520fe55SH. Peter Anvin const char *name = "unknown sym visibility name"; 1996520fe55SH. Peter Anvin if (visibility < ARRAY_SIZE(visibility_name)) { 2006520fe55SH. Peter Anvin name = visibility_name[visibility]; 2016520fe55SH. Peter Anvin } 2026520fe55SH. Peter Anvin return name; 2036520fe55SH. Peter Anvin } 2046520fe55SH. Peter Anvin 2056520fe55SH. Peter Anvin static const char *rel_type(unsigned type) 2066520fe55SH. Peter Anvin { 2076520fe55SH. Peter Anvin static const char *type_name[] = { 2086520fe55SH. Peter Anvin #define REL_TYPE(X) [X] = #X 209c889ba80SH. Peter Anvin #if ELF_BITS == 64 210946166afSKees Cook REL_TYPE(R_X86_64_NONE), 211946166afSKees Cook REL_TYPE(R_X86_64_64), 212b40a142bSArd Biesheuvel REL_TYPE(R_X86_64_PC64), 213946166afSKees Cook REL_TYPE(R_X86_64_PC32), 214946166afSKees Cook REL_TYPE(R_X86_64_GOT32), 215946166afSKees Cook REL_TYPE(R_X86_64_PLT32), 216946166afSKees Cook REL_TYPE(R_X86_64_COPY), 217946166afSKees Cook REL_TYPE(R_X86_64_GLOB_DAT), 218946166afSKees Cook REL_TYPE(R_X86_64_JUMP_SLOT), 219946166afSKees Cook REL_TYPE(R_X86_64_RELATIVE), 220946166afSKees Cook REL_TYPE(R_X86_64_GOTPCREL), 221946166afSKees Cook REL_TYPE(R_X86_64_32), 222946166afSKees Cook REL_TYPE(R_X86_64_32S), 223946166afSKees Cook REL_TYPE(R_X86_64_16), 224946166afSKees Cook REL_TYPE(R_X86_64_PC16), 225946166afSKees Cook REL_TYPE(R_X86_64_8), 226946166afSKees Cook REL_TYPE(R_X86_64_PC8), 227946166afSKees Cook #else 2286520fe55SH. Peter Anvin REL_TYPE(R_386_NONE), 2296520fe55SH. Peter Anvin REL_TYPE(R_386_32), 2306520fe55SH. Peter Anvin REL_TYPE(R_386_PC32), 2316520fe55SH. Peter Anvin REL_TYPE(R_386_GOT32), 2326520fe55SH. Peter Anvin REL_TYPE(R_386_PLT32), 2336520fe55SH. Peter Anvin REL_TYPE(R_386_COPY), 2346520fe55SH. Peter Anvin REL_TYPE(R_386_GLOB_DAT), 2356520fe55SH. Peter Anvin REL_TYPE(R_386_JMP_SLOT), 2366520fe55SH. Peter Anvin REL_TYPE(R_386_RELATIVE), 2376520fe55SH. Peter Anvin REL_TYPE(R_386_GOTOFF), 2386520fe55SH. Peter Anvin REL_TYPE(R_386_GOTPC), 2396520fe55SH. Peter Anvin REL_TYPE(R_386_8), 2406520fe55SH. Peter Anvin REL_TYPE(R_386_PC8), 2416520fe55SH. Peter Anvin REL_TYPE(R_386_16), 2426520fe55SH. Peter Anvin REL_TYPE(R_386_PC16), 243946166afSKees Cook #endif 2446520fe55SH. Peter Anvin #undef REL_TYPE 2456520fe55SH. Peter Anvin }; 2466520fe55SH. Peter Anvin const char *name = "unknown type rel type name"; 2476520fe55SH. Peter Anvin if (type < ARRAY_SIZE(type_name) && type_name[type]) { 2486520fe55SH. Peter Anvin name = type_name[type]; 2496520fe55SH. Peter Anvin } 2506520fe55SH. Peter Anvin return name; 2516520fe55SH. Peter Anvin } 2526520fe55SH. Peter Anvin 2536520fe55SH. Peter Anvin static const char *sec_name(unsigned shndx) 2546520fe55SH. Peter Anvin { 2556520fe55SH. Peter Anvin const char *sec_strtab; 2566520fe55SH. Peter Anvin const char *name; 257f36e7495SArtem Savkov sec_strtab = secs[shstrndx].strtab; 2586520fe55SH. Peter Anvin name = "<noname>"; 259f36e7495SArtem Savkov if (shndx < shnum) { 2606520fe55SH. Peter Anvin name = sec_strtab + secs[shndx].shdr.sh_name; 2616520fe55SH. Peter Anvin } 2626520fe55SH. Peter Anvin else if (shndx == SHN_ABS) { 2636520fe55SH. Peter Anvin name = "ABSOLUTE"; 2646520fe55SH. Peter Anvin } 2656520fe55SH. Peter Anvin else if (shndx == SHN_COMMON) { 2666520fe55SH. Peter Anvin name = "COMMON"; 2676520fe55SH. Peter Anvin } 2686520fe55SH. Peter Anvin return name; 2696520fe55SH. Peter Anvin } 2706520fe55SH. Peter Anvin 271bf11655cSKees Cook static const char *sym_name(const char *sym_strtab, Elf_Sym *sym) 2726520fe55SH. Peter Anvin { 2736520fe55SH. Peter Anvin const char *name; 2746520fe55SH. Peter Anvin name = "<noname>"; 2756520fe55SH. Peter Anvin if (sym->st_name) { 2766520fe55SH. Peter Anvin name = sym_strtab + sym->st_name; 2776520fe55SH. Peter Anvin } 2786520fe55SH. Peter Anvin else { 279a54c401aSKristen Carlson Accardi name = sec_name(sym_index(sym)); 2806520fe55SH. Peter Anvin } 2816520fe55SH. Peter Anvin return name; 2826520fe55SH. Peter Anvin } 2836520fe55SH. Peter Anvin 284946166afSKees Cook static Elf_Sym *sym_lookup(const char *symname) 285946166afSKees Cook { 286946166afSKees Cook int i; 287f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 288946166afSKees Cook struct section *sec = &secs[i]; 289946166afSKees Cook long nsyms; 290946166afSKees Cook char *strtab; 291946166afSKees Cook Elf_Sym *symtab; 292946166afSKees Cook Elf_Sym *sym; 2936520fe55SH. Peter Anvin 294946166afSKees Cook if (sec->shdr.sh_type != SHT_SYMTAB) 295946166afSKees Cook continue; 296946166afSKees Cook 297946166afSKees Cook nsyms = sec->shdr.sh_size/sizeof(Elf_Sym); 298946166afSKees Cook symtab = sec->symtab; 299946166afSKees Cook strtab = sec->link->strtab; 300946166afSKees Cook 301946166afSKees Cook for (sym = symtab; --nsyms >= 0; sym++) { 302946166afSKees Cook if (!sym->st_name) 303946166afSKees Cook continue; 304946166afSKees Cook if (strcmp(symname, strtab + sym->st_name) == 0) 305946166afSKees Cook return sym; 306946166afSKees Cook } 307946166afSKees Cook } 308946166afSKees Cook return 0; 309946166afSKees Cook } 3106520fe55SH. Peter Anvin 3116520fe55SH. Peter Anvin #if BYTE_ORDER == LITTLE_ENDIAN 3126520fe55SH. Peter Anvin #define le16_to_cpu(val) (val) 3136520fe55SH. Peter Anvin #define le32_to_cpu(val) (val) 314946166afSKees Cook #define le64_to_cpu(val) (val) 3156520fe55SH. Peter Anvin #endif 3166520fe55SH. Peter Anvin #if BYTE_ORDER == BIG_ENDIAN 3176520fe55SH. Peter Anvin #define le16_to_cpu(val) bswap_16(val) 3186520fe55SH. Peter Anvin #define le32_to_cpu(val) bswap_32(val) 319946166afSKees Cook #define le64_to_cpu(val) bswap_64(val) 3206520fe55SH. Peter Anvin #endif 3216520fe55SH. Peter Anvin 3226520fe55SH. Peter Anvin static uint16_t elf16_to_cpu(uint16_t val) 3236520fe55SH. Peter Anvin { 3246520fe55SH. Peter Anvin return le16_to_cpu(val); 3256520fe55SH. Peter Anvin } 3266520fe55SH. Peter Anvin 3276520fe55SH. Peter Anvin static uint32_t elf32_to_cpu(uint32_t val) 3286520fe55SH. Peter Anvin { 3296520fe55SH. Peter Anvin return le32_to_cpu(val); 3306520fe55SH. Peter Anvin } 3316520fe55SH. Peter Anvin 332bf11655cSKees Cook #define elf_half_to_cpu(x) elf16_to_cpu(x) 333bf11655cSKees Cook #define elf_word_to_cpu(x) elf32_to_cpu(x) 334946166afSKees Cook 335c889ba80SH. Peter Anvin #if ELF_BITS == 64 336946166afSKees Cook static uint64_t elf64_to_cpu(uint64_t val) 337946166afSKees Cook { 338946166afSKees Cook return le64_to_cpu(val); 339946166afSKees Cook } 340946166afSKees Cook #define elf_addr_to_cpu(x) elf64_to_cpu(x) 341946166afSKees Cook #define elf_off_to_cpu(x) elf64_to_cpu(x) 342946166afSKees Cook #define elf_xword_to_cpu(x) elf64_to_cpu(x) 343946166afSKees Cook #else 344bf11655cSKees Cook #define elf_addr_to_cpu(x) elf32_to_cpu(x) 345bf11655cSKees Cook #define elf_off_to_cpu(x) elf32_to_cpu(x) 346bf11655cSKees Cook #define elf_xword_to_cpu(x) elf32_to_cpu(x) 347946166afSKees Cook #endif 348bf11655cSKees Cook 349a54c401aSKristen Carlson Accardi static int sym_index(Elf_Sym *sym) 350a54c401aSKristen Carlson Accardi { 351a54c401aSKristen Carlson Accardi Elf_Sym *symtab = secs[shsymtabndx].symtab; 352a54c401aSKristen Carlson Accardi Elf32_Word *xsymtab = secs[shxsymtabndx].xsymtab; 353a54c401aSKristen Carlson Accardi unsigned long offset; 354a54c401aSKristen Carlson Accardi int index; 355a54c401aSKristen Carlson Accardi 356a54c401aSKristen Carlson Accardi if (sym->st_shndx != SHN_XINDEX) 357a54c401aSKristen Carlson Accardi return sym->st_shndx; 358a54c401aSKristen Carlson Accardi 359a54c401aSKristen Carlson Accardi /* calculate offset of sym from head of table. */ 360a54c401aSKristen Carlson Accardi offset = (unsigned long)sym - (unsigned long)symtab; 361a54c401aSKristen Carlson Accardi index = offset / sizeof(*sym); 362a54c401aSKristen Carlson Accardi 363a54c401aSKristen Carlson Accardi return elf32_to_cpu(xsymtab[index]); 364a54c401aSKristen Carlson Accardi } 365a54c401aSKristen Carlson Accardi 3666520fe55SH. Peter Anvin static void read_ehdr(FILE *fp) 3676520fe55SH. Peter Anvin { 3686520fe55SH. Peter Anvin if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { 3696520fe55SH. Peter Anvin die("Cannot read ELF header: %s\n", 3706520fe55SH. Peter Anvin strerror(errno)); 3716520fe55SH. Peter Anvin } 3726520fe55SH. Peter Anvin if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { 3736520fe55SH. Peter Anvin die("No ELF magic\n"); 3746520fe55SH. Peter Anvin } 375bf11655cSKees Cook if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) { 376bf11655cSKees Cook die("Not a %d bit executable\n", ELF_BITS); 3776520fe55SH. Peter Anvin } 3786520fe55SH. Peter Anvin if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { 3796520fe55SH. Peter Anvin die("Not a LSB ELF executable\n"); 3806520fe55SH. Peter Anvin } 3816520fe55SH. Peter Anvin if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { 3826520fe55SH. Peter Anvin die("Unknown ELF version\n"); 3836520fe55SH. Peter Anvin } 3846520fe55SH. Peter Anvin /* Convert the fields to native endian */ 385bf11655cSKees Cook ehdr.e_type = elf_half_to_cpu(ehdr.e_type); 386bf11655cSKees Cook ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine); 387bf11655cSKees Cook ehdr.e_version = elf_word_to_cpu(ehdr.e_version); 388bf11655cSKees Cook ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry); 389bf11655cSKees Cook ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff); 390bf11655cSKees Cook ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff); 391bf11655cSKees Cook ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags); 392bf11655cSKees Cook ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize); 393bf11655cSKees Cook ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize); 394bf11655cSKees Cook ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum); 395bf11655cSKees Cook ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize); 396bf11655cSKees Cook ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum); 397bf11655cSKees Cook ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx); 3986520fe55SH. Peter Anvin 399f36e7495SArtem Savkov shnum = ehdr.e_shnum; 400f36e7495SArtem Savkov shstrndx = ehdr.e_shstrndx; 401f36e7495SArtem Savkov 402f36e7495SArtem Savkov if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) 4036520fe55SH. Peter Anvin die("Unsupported ELF header type\n"); 404f36e7495SArtem Savkov if (ehdr.e_machine != ELF_MACHINE) 405bf11655cSKees Cook die("Not for %s\n", ELF_MACHINE_NAME); 406f36e7495SArtem Savkov if (ehdr.e_version != EV_CURRENT) 4076520fe55SH. Peter Anvin die("Unknown ELF version\n"); 408f36e7495SArtem Savkov if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) 4096520fe55SH. Peter Anvin die("Bad Elf header size\n"); 410f36e7495SArtem Savkov if (ehdr.e_phentsize != sizeof(Elf_Phdr)) 4116520fe55SH. Peter Anvin die("Bad program header entry\n"); 412f36e7495SArtem Savkov if (ehdr.e_shentsize != sizeof(Elf_Shdr)) 4136520fe55SH. Peter Anvin die("Bad section header entry\n"); 414f36e7495SArtem Savkov 415f36e7495SArtem Savkov 416f36e7495SArtem Savkov if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) { 417f36e7495SArtem Savkov Elf_Shdr shdr; 418f36e7495SArtem Savkov 419f36e7495SArtem Savkov if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) 42003dca99eSBorislav Petkov die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno)); 421f36e7495SArtem Savkov 422f36e7495SArtem Savkov if (fread(&shdr, sizeof(shdr), 1, fp) != 1) 423f36e7495SArtem Savkov die("Cannot read initial ELF section header: %s\n", strerror(errno)); 424f36e7495SArtem Savkov 425f36e7495SArtem Savkov if (shnum == SHN_UNDEF) 426f36e7495SArtem Savkov shnum = elf_xword_to_cpu(shdr.sh_size); 427f36e7495SArtem Savkov 428f36e7495SArtem Savkov if (shstrndx == SHN_XINDEX) 429f36e7495SArtem Savkov shstrndx = elf_word_to_cpu(shdr.sh_link); 4306520fe55SH. Peter Anvin } 431f36e7495SArtem Savkov 432f36e7495SArtem Savkov if (shstrndx >= shnum) 4336520fe55SH. Peter Anvin die("String table index out of bounds\n"); 4346520fe55SH. Peter Anvin } 4356520fe55SH. Peter Anvin 4366520fe55SH. Peter Anvin static void read_shdrs(FILE *fp) 4376520fe55SH. Peter Anvin { 4386520fe55SH. Peter Anvin int i; 439bf11655cSKees Cook Elf_Shdr shdr; 4406520fe55SH. Peter Anvin 441f36e7495SArtem Savkov secs = calloc(shnum, sizeof(struct section)); 4426520fe55SH. Peter Anvin if (!secs) { 44303dca99eSBorislav Petkov die("Unable to allocate %ld section headers\n", 444f36e7495SArtem Savkov shnum); 4456520fe55SH. Peter Anvin } 4466520fe55SH. Peter Anvin if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { 44703dca99eSBorislav Petkov die("Seek to %" FMT " failed: %s\n", 4486520fe55SH. Peter Anvin ehdr.e_shoff, strerror(errno)); 4496520fe55SH. Peter Anvin } 450f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 4516520fe55SH. Peter Anvin struct section *sec = &secs[i]; 4520e96f31eSJordan Borgner if (fread(&shdr, sizeof(shdr), 1, fp) != 1) 45303dca99eSBorislav Petkov die("Cannot read ELF section headers %d/%ld: %s\n", 454f36e7495SArtem Savkov i, shnum, strerror(errno)); 455bf11655cSKees Cook sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name); 456bf11655cSKees Cook sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type); 457bf11655cSKees Cook sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags); 458bf11655cSKees Cook sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr); 459bf11655cSKees Cook sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset); 460bf11655cSKees Cook sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size); 461bf11655cSKees Cook sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link); 462bf11655cSKees Cook sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info); 463bf11655cSKees Cook sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign); 464bf11655cSKees Cook sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize); 465f36e7495SArtem Savkov if (sec->shdr.sh_link < shnum) 4666520fe55SH. Peter Anvin sec->link = &secs[sec->shdr.sh_link]; 4676520fe55SH. Peter Anvin } 4686520fe55SH. Peter Anvin 4696520fe55SH. Peter Anvin } 4706520fe55SH. Peter Anvin 4716520fe55SH. Peter Anvin static void read_strtabs(FILE *fp) 4726520fe55SH. Peter Anvin { 4736520fe55SH. Peter Anvin int i; 474f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 4756520fe55SH. Peter Anvin struct section *sec = &secs[i]; 4766520fe55SH. Peter Anvin if (sec->shdr.sh_type != SHT_STRTAB) { 4776520fe55SH. Peter Anvin continue; 4786520fe55SH. Peter Anvin } 4796520fe55SH. Peter Anvin sec->strtab = malloc(sec->shdr.sh_size); 4806520fe55SH. Peter Anvin if (!sec->strtab) { 48103dca99eSBorislav Petkov die("malloc of %" FMT " bytes for strtab failed\n", 4826520fe55SH. Peter Anvin sec->shdr.sh_size); 4836520fe55SH. Peter Anvin } 4846520fe55SH. Peter Anvin if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 48503dca99eSBorislav Petkov die("Seek to %" FMT " failed: %s\n", 4866520fe55SH. Peter Anvin sec->shdr.sh_offset, strerror(errno)); 4876520fe55SH. Peter Anvin } 4886520fe55SH. Peter Anvin if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) 4896520fe55SH. Peter Anvin != sec->shdr.sh_size) { 4906520fe55SH. Peter Anvin die("Cannot read symbol table: %s\n", 4916520fe55SH. Peter Anvin strerror(errno)); 4926520fe55SH. Peter Anvin } 4936520fe55SH. Peter Anvin } 4946520fe55SH. Peter Anvin } 4956520fe55SH. Peter Anvin 4966520fe55SH. Peter Anvin static void read_symtabs(FILE *fp) 4976520fe55SH. Peter Anvin { 4986520fe55SH. Peter Anvin int i,j; 499a54c401aSKristen Carlson Accardi 500f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 5016520fe55SH. Peter Anvin struct section *sec = &secs[i]; 502a54c401aSKristen Carlson Accardi int num_syms; 503a54c401aSKristen Carlson Accardi 504a54c401aSKristen Carlson Accardi switch (sec->shdr.sh_type) { 505a54c401aSKristen Carlson Accardi case SHT_SYMTAB_SHNDX: 506a54c401aSKristen Carlson Accardi sec->xsymtab = malloc(sec->shdr.sh_size); 507a54c401aSKristen Carlson Accardi if (!sec->xsymtab) { 508a54c401aSKristen Carlson Accardi die("malloc of %" FMT " bytes for xsymtab failed\n", 509a54c401aSKristen Carlson Accardi sec->shdr.sh_size); 5106520fe55SH. Peter Anvin } 511a54c401aSKristen Carlson Accardi if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 512a54c401aSKristen Carlson Accardi die("Seek to %" FMT " failed: %s\n", 513a54c401aSKristen Carlson Accardi sec->shdr.sh_offset, strerror(errno)); 514a54c401aSKristen Carlson Accardi } 515a54c401aSKristen Carlson Accardi if (fread(sec->xsymtab, 1, sec->shdr.sh_size, fp) 516a54c401aSKristen Carlson Accardi != sec->shdr.sh_size) { 517a54c401aSKristen Carlson Accardi die("Cannot read extended symbol table: %s\n", 518a54c401aSKristen Carlson Accardi strerror(errno)); 519a54c401aSKristen Carlson Accardi } 520a54c401aSKristen Carlson Accardi shxsymtabndx = i; 521a54c401aSKristen Carlson Accardi continue; 522a54c401aSKristen Carlson Accardi 523a54c401aSKristen Carlson Accardi case SHT_SYMTAB: 524a54c401aSKristen Carlson Accardi num_syms = sec->shdr.sh_size / sizeof(Elf_Sym); 525a54c401aSKristen Carlson Accardi 5266520fe55SH. Peter Anvin sec->symtab = malloc(sec->shdr.sh_size); 5276520fe55SH. Peter Anvin if (!sec->symtab) { 52803dca99eSBorislav Petkov die("malloc of %" FMT " bytes for symtab failed\n", 5296520fe55SH. Peter Anvin sec->shdr.sh_size); 5306520fe55SH. Peter Anvin } 5316520fe55SH. Peter Anvin if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 53203dca99eSBorislav Petkov die("Seek to %" FMT " failed: %s\n", 5336520fe55SH. Peter Anvin sec->shdr.sh_offset, strerror(errno)); 5346520fe55SH. Peter Anvin } 5356520fe55SH. Peter Anvin if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) 5366520fe55SH. Peter Anvin != sec->shdr.sh_size) { 5376520fe55SH. Peter Anvin die("Cannot read symbol table: %s\n", 5386520fe55SH. Peter Anvin strerror(errno)); 5396520fe55SH. Peter Anvin } 540a54c401aSKristen Carlson Accardi for (j = 0; j < num_syms; j++) { 541bf11655cSKees Cook Elf_Sym *sym = &sec->symtab[j]; 542a54c401aSKristen Carlson Accardi 543bf11655cSKees Cook sym->st_name = elf_word_to_cpu(sym->st_name); 544bf11655cSKees Cook sym->st_value = elf_addr_to_cpu(sym->st_value); 545bf11655cSKees Cook sym->st_size = elf_xword_to_cpu(sym->st_size); 546bf11655cSKees Cook sym->st_shndx = elf_half_to_cpu(sym->st_shndx); 5476520fe55SH. Peter Anvin } 548a54c401aSKristen Carlson Accardi shsymtabndx = i; 549a54c401aSKristen Carlson Accardi continue; 550a54c401aSKristen Carlson Accardi 551a54c401aSKristen Carlson Accardi default: 552a54c401aSKristen Carlson Accardi continue; 553a54c401aSKristen Carlson Accardi } 5546520fe55SH. Peter Anvin } 5556520fe55SH. Peter Anvin } 5566520fe55SH. Peter Anvin 5576520fe55SH. Peter Anvin 5586520fe55SH. Peter Anvin static void read_relocs(FILE *fp) 5596520fe55SH. Peter Anvin { 5606520fe55SH. Peter Anvin int i,j; 561f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 5626520fe55SH. Peter Anvin struct section *sec = &secs[i]; 563bf11655cSKees Cook if (sec->shdr.sh_type != SHT_REL_TYPE) { 5646520fe55SH. Peter Anvin continue; 5656520fe55SH. Peter Anvin } 5666520fe55SH. Peter Anvin sec->reltab = malloc(sec->shdr.sh_size); 5676520fe55SH. Peter Anvin if (!sec->reltab) { 56803dca99eSBorislav Petkov die("malloc of %" FMT " bytes for relocs failed\n", 5696520fe55SH. Peter Anvin sec->shdr.sh_size); 5706520fe55SH. Peter Anvin } 5716520fe55SH. Peter Anvin if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 57203dca99eSBorislav Petkov die("Seek to %" FMT " failed: %s\n", 5736520fe55SH. Peter Anvin sec->shdr.sh_offset, strerror(errno)); 5746520fe55SH. Peter Anvin } 5756520fe55SH. Peter Anvin if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) 5766520fe55SH. Peter Anvin != sec->shdr.sh_size) { 5776520fe55SH. Peter Anvin die("Cannot read symbol table: %s\n", 5786520fe55SH. Peter Anvin strerror(errno)); 5796520fe55SH. Peter Anvin } 580bf11655cSKees Cook for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 581bf11655cSKees Cook Elf_Rel *rel = &sec->reltab[j]; 582bf11655cSKees Cook rel->r_offset = elf_addr_to_cpu(rel->r_offset); 583bf11655cSKees Cook rel->r_info = elf_xword_to_cpu(rel->r_info); 584946166afSKees Cook #if (SHT_REL_TYPE == SHT_RELA) 585946166afSKees Cook rel->r_addend = elf_xword_to_cpu(rel->r_addend); 586946166afSKees Cook #endif 5876520fe55SH. Peter Anvin } 5886520fe55SH. Peter Anvin } 5896520fe55SH. Peter Anvin } 5906520fe55SH. Peter Anvin 5916520fe55SH. Peter Anvin 5926520fe55SH. Peter Anvin static void print_absolute_symbols(void) 5936520fe55SH. Peter Anvin { 5946520fe55SH. Peter Anvin int i; 595946166afSKees Cook const char *format; 596946166afSKees Cook 597c889ba80SH. Peter Anvin if (ELF_BITS == 64) 598946166afSKees Cook format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n"; 599946166afSKees Cook else 600946166afSKees Cook format = "%5d %08"PRIx32" %5"PRId32" %10s %10s %12s %s\n"; 601946166afSKees Cook 6026520fe55SH. Peter Anvin printf("Absolute symbols\n"); 6036520fe55SH. Peter Anvin printf(" Num: Value Size Type Bind Visibility Name\n"); 604f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 6056520fe55SH. Peter Anvin struct section *sec = &secs[i]; 6066520fe55SH. Peter Anvin char *sym_strtab; 6076520fe55SH. Peter Anvin int j; 6086520fe55SH. Peter Anvin 6096520fe55SH. Peter Anvin if (sec->shdr.sh_type != SHT_SYMTAB) { 6106520fe55SH. Peter Anvin continue; 6116520fe55SH. Peter Anvin } 6126520fe55SH. Peter Anvin sym_strtab = sec->link->strtab; 613bf11655cSKees Cook for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) { 614bf11655cSKees Cook Elf_Sym *sym; 6156520fe55SH. Peter Anvin const char *name; 6166520fe55SH. Peter Anvin sym = &sec->symtab[j]; 6176520fe55SH. Peter Anvin name = sym_name(sym_strtab, sym); 6186520fe55SH. Peter Anvin if (sym->st_shndx != SHN_ABS) { 6196520fe55SH. Peter Anvin continue; 6206520fe55SH. Peter Anvin } 621946166afSKees Cook printf(format, 6226520fe55SH. Peter Anvin j, sym->st_value, sym->st_size, 623bf11655cSKees Cook sym_type(ELF_ST_TYPE(sym->st_info)), 624bf11655cSKees Cook sym_bind(ELF_ST_BIND(sym->st_info)), 625bf11655cSKees Cook sym_visibility(ELF_ST_VISIBILITY(sym->st_other)), 6266520fe55SH. Peter Anvin name); 6276520fe55SH. Peter Anvin } 6286520fe55SH. Peter Anvin } 6296520fe55SH. Peter Anvin printf("\n"); 6306520fe55SH. Peter Anvin } 6316520fe55SH. Peter Anvin 6326520fe55SH. Peter Anvin static void print_absolute_relocs(void) 6336520fe55SH. Peter Anvin { 6346520fe55SH. Peter Anvin int i, printed = 0; 635946166afSKees Cook const char *format; 636946166afSKees Cook 637c889ba80SH. Peter Anvin if (ELF_BITS == 64) 638946166afSKees Cook format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64" %s\n"; 639946166afSKees Cook else 640946166afSKees Cook format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32" %s\n"; 6416520fe55SH. Peter Anvin 642f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 6436520fe55SH. Peter Anvin struct section *sec = &secs[i]; 6446520fe55SH. Peter Anvin struct section *sec_applies, *sec_symtab; 6456520fe55SH. Peter Anvin char *sym_strtab; 646bf11655cSKees Cook Elf_Sym *sh_symtab; 6476520fe55SH. Peter Anvin int j; 648bf11655cSKees Cook if (sec->shdr.sh_type != SHT_REL_TYPE) { 6496520fe55SH. Peter Anvin continue; 6506520fe55SH. Peter Anvin } 6516520fe55SH. Peter Anvin sec_symtab = sec->link; 6526520fe55SH. Peter Anvin sec_applies = &secs[sec->shdr.sh_info]; 6536520fe55SH. Peter Anvin if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 6546520fe55SH. Peter Anvin continue; 6556520fe55SH. Peter Anvin } 6566520fe55SH. Peter Anvin sh_symtab = sec_symtab->symtab; 6576520fe55SH. Peter Anvin sym_strtab = sec_symtab->link->strtab; 658bf11655cSKees Cook for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 659bf11655cSKees Cook Elf_Rel *rel; 660bf11655cSKees Cook Elf_Sym *sym; 6616520fe55SH. Peter Anvin const char *name; 6626520fe55SH. Peter Anvin rel = &sec->reltab[j]; 663bf11655cSKees Cook sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; 6646520fe55SH. Peter Anvin name = sym_name(sym_strtab, sym); 6656520fe55SH. Peter Anvin if (sym->st_shndx != SHN_ABS) { 6666520fe55SH. Peter Anvin continue; 6676520fe55SH. Peter Anvin } 6686520fe55SH. Peter Anvin 6696520fe55SH. Peter Anvin /* Absolute symbols are not relocated if bzImage is 6706520fe55SH. Peter Anvin * loaded at a non-compiled address. Display a warning 6716520fe55SH. Peter Anvin * to user at compile time about the absolute 6726520fe55SH. Peter Anvin * relocations present. 6736520fe55SH. Peter Anvin * 6746520fe55SH. Peter Anvin * User need to audit the code to make sure 6756520fe55SH. Peter Anvin * some symbols which should have been section 6766520fe55SH. Peter Anvin * relative have not become absolute because of some 6776520fe55SH. Peter Anvin * linker optimization or wrong programming usage. 6786520fe55SH. Peter Anvin * 6796520fe55SH. Peter Anvin * Before warning check if this absolute symbol 6806520fe55SH. Peter Anvin * relocation is harmless. 6816520fe55SH. Peter Anvin */ 6826520fe55SH. Peter Anvin if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) 6836520fe55SH. Peter Anvin continue; 6846520fe55SH. Peter Anvin 6856520fe55SH. Peter Anvin if (!printed) { 6866520fe55SH. Peter Anvin printf("WARNING: Absolute relocations" 6876520fe55SH. Peter Anvin " present\n"); 6886520fe55SH. Peter Anvin printf("Offset Info Type Sym.Value " 6896520fe55SH. Peter Anvin "Sym.Name\n"); 6906520fe55SH. Peter Anvin printed = 1; 6916520fe55SH. Peter Anvin } 6926520fe55SH. Peter Anvin 693946166afSKees Cook printf(format, 6946520fe55SH. Peter Anvin rel->r_offset, 6956520fe55SH. Peter Anvin rel->r_info, 696bf11655cSKees Cook rel_type(ELF_R_TYPE(rel->r_info)), 6976520fe55SH. Peter Anvin sym->st_value, 6986520fe55SH. Peter Anvin name); 6996520fe55SH. Peter Anvin } 7006520fe55SH. Peter Anvin } 7016520fe55SH. Peter Anvin 7026520fe55SH. Peter Anvin if (printed) 7036520fe55SH. Peter Anvin printf("\n"); 7046520fe55SH. Peter Anvin } 7056520fe55SH. Peter Anvin 7065d442e63SKees Cook static void add_reloc(struct relocs *r, uint32_t offset) 7075d442e63SKees Cook { 7085d442e63SKees Cook if (r->count == r->size) { 7095d442e63SKees Cook unsigned long newsize = r->size + 50000; 7105d442e63SKees Cook void *mem = realloc(r->offset, newsize * sizeof(r->offset[0])); 7115d442e63SKees Cook 7125d442e63SKees Cook if (!mem) 7135d442e63SKees Cook die("realloc of %ld entries for relocs failed\n", 7145d442e63SKees Cook newsize); 7155d442e63SKees Cook r->offset = mem; 7165d442e63SKees Cook r->size = newsize; 7175d442e63SKees Cook } 7185d442e63SKees Cook r->offset[r->count++] = offset; 7195d442e63SKees Cook } 7205d442e63SKees Cook 7215d442e63SKees Cook static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, 7225d442e63SKees Cook Elf_Sym *sym, const char *symname)) 7236520fe55SH. Peter Anvin { 7246520fe55SH. Peter Anvin int i; 7256520fe55SH. Peter Anvin /* Walk through the relocations */ 726f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 7276520fe55SH. Peter Anvin char *sym_strtab; 728bf11655cSKees Cook Elf_Sym *sh_symtab; 7296520fe55SH. Peter Anvin struct section *sec_applies, *sec_symtab; 7306520fe55SH. Peter Anvin int j; 7316520fe55SH. Peter Anvin struct section *sec = &secs[i]; 7326520fe55SH. Peter Anvin 733bf11655cSKees Cook if (sec->shdr.sh_type != SHT_REL_TYPE) { 7346520fe55SH. Peter Anvin continue; 7356520fe55SH. Peter Anvin } 7366520fe55SH. Peter Anvin sec_symtab = sec->link; 7376520fe55SH. Peter Anvin sec_applies = &secs[sec->shdr.sh_info]; 7386520fe55SH. Peter Anvin if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 7396520fe55SH. Peter Anvin continue; 7406520fe55SH. Peter Anvin } 7416520fe55SH. Peter Anvin sh_symtab = sec_symtab->symtab; 7426520fe55SH. Peter Anvin sym_strtab = sec_symtab->link->strtab; 743bf11655cSKees Cook for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 7445d442e63SKees Cook Elf_Rel *rel = &sec->reltab[j]; 7455d442e63SKees Cook Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; 7465d442e63SKees Cook const char *symname = sym_name(sym_strtab, sym); 74724ab82bdSH. Peter Anvin 7485d442e63SKees Cook process(sec, rel, sym, symname); 7495d442e63SKees Cook } 7505d442e63SKees Cook } 7515d442e63SKees Cook } 7526520fe55SH. Peter Anvin 753946166afSKees Cook /* 754946166afSKees Cook * The .data..percpu section is a special case for x86_64 SMP kernels. 755946166afSKees Cook * It is used to initialize the actual per_cpu areas and to provide 756946166afSKees Cook * definitions for the per_cpu variables that correspond to their offsets 757946166afSKees Cook * within the percpu area. Since the values of all of the symbols need 758946166afSKees Cook * to be offsets from the start of the per_cpu area the virtual address 759946166afSKees Cook * (sh_addr) of .data..percpu is 0 in SMP kernels. 760946166afSKees Cook * 761946166afSKees Cook * This means that: 762946166afSKees Cook * 763946166afSKees Cook * Relocations that reference symbols in the per_cpu area do not 764946166afSKees Cook * need further relocation (since the value is an offset relative 765946166afSKees Cook * to the start of the per_cpu area that does not change). 766946166afSKees Cook * 767946166afSKees Cook * Relocations that apply to the per_cpu area need to have their 768946166afSKees Cook * offset adjusted by by the value of __per_cpu_load to make them 769946166afSKees Cook * point to the correct place in the loaded image (because the 770946166afSKees Cook * virtual address of .data..percpu is 0). 771946166afSKees Cook * 772946166afSKees Cook * For non SMP kernels .data..percpu is linked as part of the normal 773946166afSKees Cook * kernel data and does not require special treatment. 774946166afSKees Cook * 775946166afSKees Cook */ 776946166afSKees Cook static int per_cpu_shndx = -1; 777eeeda4cdSBen Hutchings static Elf_Addr per_cpu_load_addr; 778946166afSKees Cook 779946166afSKees Cook static void percpu_init(void) 780946166afSKees Cook { 781946166afSKees Cook int i; 782f36e7495SArtem Savkov for (i = 0; i < shnum; i++) { 783946166afSKees Cook ElfW(Sym) *sym; 784946166afSKees Cook if (strcmp(sec_name(i), ".data..percpu")) 785946166afSKees Cook continue; 786946166afSKees Cook 787946166afSKees Cook if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */ 788946166afSKees Cook return; 789946166afSKees Cook 790946166afSKees Cook sym = sym_lookup("__per_cpu_load"); 791946166afSKees Cook if (!sym) 792946166afSKees Cook die("can't find __per_cpu_load\n"); 793946166afSKees Cook 794946166afSKees Cook per_cpu_shndx = i; 795946166afSKees Cook per_cpu_load_addr = sym->st_value; 796946166afSKees Cook return; 797946166afSKees Cook } 798946166afSKees Cook } 799946166afSKees Cook 800c889ba80SH. Peter Anvin #if ELF_BITS == 64 801c889ba80SH. Peter Anvin 802946166afSKees Cook /* 803946166afSKees Cook * Check to see if a symbol lies in the .data..percpu section. 804d751c169SMichael Davidson * 805d751c169SMichael Davidson * The linker incorrectly associates some symbols with the 806d751c169SMichael Davidson * .data..percpu section so we also need to check the symbol 807d751c169SMichael Davidson * name to make sure that we classify the symbol correctly. 808d751c169SMichael Davidson * 809d751c169SMichael Davidson * The GNU linker incorrectly associates: 810d751c169SMichael Davidson * __init_begin 811aec58bafSKees Cook * __per_cpu_load 812d751c169SMichael Davidson * 813d751c169SMichael Davidson * The "gold" linker incorrectly associates: 814e6401c13SAndy Lutomirski * init_per_cpu__fixed_percpu_data 815d751c169SMichael Davidson * init_per_cpu__gdt_page 816946166afSKees Cook */ 817946166afSKees Cook static int is_percpu_sym(ElfW(Sym) *sym, const char *symname) 818946166afSKees Cook { 819a54c401aSKristen Carlson Accardi int shndx = sym_index(sym); 820a54c401aSKristen Carlson Accardi 821a54c401aSKristen Carlson Accardi return (shndx == per_cpu_shndx) && 822d751c169SMichael Davidson strcmp(symname, "__init_begin") && 823aec58bafSKees Cook strcmp(symname, "__per_cpu_load") && 824d751c169SMichael Davidson strncmp(symname, "init_per_cpu_", 13); 825946166afSKees Cook } 826946166afSKees Cook 827c889ba80SH. Peter Anvin 828946166afSKees Cook static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, 829946166afSKees Cook const char *symname) 830946166afSKees Cook { 831946166afSKees Cook unsigned r_type = ELF64_R_TYPE(rel->r_info); 832946166afSKees Cook ElfW(Addr) offset = rel->r_offset; 833946166afSKees Cook int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); 834946166afSKees Cook 835946166afSKees Cook if (sym->st_shndx == SHN_UNDEF) 836946166afSKees Cook return 0; 837946166afSKees Cook 838946166afSKees Cook /* 839946166afSKees Cook * Adjust the offset if this reloc applies to the percpu section. 840946166afSKees Cook */ 841946166afSKees Cook if (sec->shdr.sh_info == per_cpu_shndx) 842946166afSKees Cook offset += per_cpu_load_addr; 843946166afSKees Cook 844946166afSKees Cook switch (r_type) { 845946166afSKees Cook case R_X86_64_NONE: 8466d24c5f7SJan Beulich /* NONE can be ignored. */ 8476d24c5f7SJan Beulich break; 8486d24c5f7SJan Beulich 849946166afSKees Cook case R_X86_64_PC32: 850b21ebf2fSH.J. Lu case R_X86_64_PLT32: 851946166afSKees Cook /* 8526d24c5f7SJan Beulich * PC relative relocations don't need to be adjusted unless 8536d24c5f7SJan Beulich * referencing a percpu symbol. 854b21ebf2fSH.J. Lu * 855b21ebf2fSH.J. Lu * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32. 856946166afSKees Cook */ 8576d24c5f7SJan Beulich if (is_percpu_sym(sym, symname)) 8586d24c5f7SJan Beulich add_reloc(&relocs32neg, offset); 859946166afSKees Cook break; 860946166afSKees Cook 861b40a142bSArd Biesheuvel case R_X86_64_PC64: 862b40a142bSArd Biesheuvel /* 863b40a142bSArd Biesheuvel * Only used by jump labels 864b40a142bSArd Biesheuvel */ 865b40a142bSArd Biesheuvel if (is_percpu_sym(sym, symname)) 866b40a142bSArd Biesheuvel die("Invalid R_X86_64_PC64 relocation against per-CPU symbol %s\n", 867b40a142bSArd Biesheuvel symname); 868b40a142bSArd Biesheuvel break; 869b40a142bSArd Biesheuvel 870946166afSKees Cook case R_X86_64_32: 871946166afSKees Cook case R_X86_64_32S: 872946166afSKees Cook case R_X86_64_64: 873946166afSKees Cook /* 874946166afSKees Cook * References to the percpu area don't need to be adjusted. 875946166afSKees Cook */ 876946166afSKees Cook if (is_percpu_sym(sym, symname)) 877946166afSKees Cook break; 878946166afSKees Cook 879946166afSKees Cook if (shn_abs) { 880946166afSKees Cook /* 881946166afSKees Cook * Whitelisted absolute symbols do not require 882946166afSKees Cook * relocation. 883946166afSKees Cook */ 884946166afSKees Cook if (is_reloc(S_ABS, symname)) 885946166afSKees Cook break; 886946166afSKees Cook 887946166afSKees Cook die("Invalid absolute %s relocation: %s\n", 888946166afSKees Cook rel_type(r_type), symname); 889946166afSKees Cook break; 890946166afSKees Cook } 891946166afSKees Cook 892946166afSKees Cook /* 893946166afSKees Cook * Relocation offsets for 64 bit kernels are output 894946166afSKees Cook * as 32 bits and sign extended back to 64 bits when 895946166afSKees Cook * the relocations are processed. 896946166afSKees Cook * Make sure that the offset will fit. 897946166afSKees Cook */ 898946166afSKees Cook if ((int32_t)offset != (int64_t)offset) 899946166afSKees Cook die("Relocation offset doesn't fit in 32 bits\n"); 900946166afSKees Cook 901946166afSKees Cook if (r_type == R_X86_64_64) 902946166afSKees Cook add_reloc(&relocs64, offset); 903946166afSKees Cook else 904946166afSKees Cook add_reloc(&relocs32, offset); 905946166afSKees Cook break; 906946166afSKees Cook 907946166afSKees Cook default: 908946166afSKees Cook die("Unsupported relocation type: %s (%d)\n", 909946166afSKees Cook rel_type(r_type), r_type); 910946166afSKees Cook break; 911946166afSKees Cook } 912946166afSKees Cook 913946166afSKees Cook return 0; 914946166afSKees Cook } 915946166afSKees Cook 916c889ba80SH. Peter Anvin #else 917946166afSKees Cook 918946166afSKees Cook static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, 9195d442e63SKees Cook const char *symname) 9205d442e63SKees Cook { 9215d442e63SKees Cook unsigned r_type = ELF32_R_TYPE(rel->r_info); 9225d442e63SKees Cook int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); 92324ab82bdSH. Peter Anvin 9246520fe55SH. Peter Anvin switch (r_type) { 9256520fe55SH. Peter Anvin case R_386_NONE: 9266520fe55SH. Peter Anvin case R_386_PC32: 9276520fe55SH. Peter Anvin case R_386_PC16: 9286520fe55SH. Peter Anvin case R_386_PC8: 929bb73d071SFangrui Song case R_386_PLT32: 9306520fe55SH. Peter Anvin /* 931bb73d071SFangrui Song * NONE can be ignored and PC relative relocations don't need 932bb73d071SFangrui Song * to be adjusted. Because sym must be defined, R_386_PLT32 can 933bb73d071SFangrui Song * be treated the same way as R_386_PC32. 9346520fe55SH. Peter Anvin */ 9356520fe55SH. Peter Anvin break; 9366520fe55SH. Peter Anvin 9375d442e63SKees Cook case R_386_32: 93824ab82bdSH. Peter Anvin if (shn_abs) { 9395d442e63SKees Cook /* 9405d442e63SKees Cook * Whitelisted absolute symbols do not require 9415d442e63SKees Cook * relocation. 9425d442e63SKees Cook */ 9436520fe55SH. Peter Anvin if (is_reloc(S_ABS, symname)) 9446520fe55SH. Peter Anvin break; 9456520fe55SH. Peter Anvin 9465d442e63SKees Cook die("Invalid absolute %s relocation: %s\n", 9475d442e63SKees Cook rel_type(r_type), symname); 9486520fe55SH. Peter Anvin break; 9496520fe55SH. Peter Anvin } 9505d442e63SKees Cook 9515d442e63SKees Cook add_reloc(&relocs32, rel->r_offset); 9526520fe55SH. Peter Anvin break; 9535d442e63SKees Cook 9546520fe55SH. Peter Anvin default: 9556520fe55SH. Peter Anvin die("Unsupported relocation type: %s (%d)\n", 9566520fe55SH. Peter Anvin rel_type(r_type), r_type); 9576520fe55SH. Peter Anvin break; 9585d442e63SKees Cook } 9595d442e63SKees Cook 9605d442e63SKees Cook return 0; 9615d442e63SKees Cook } 9625d442e63SKees Cook 9635d442e63SKees Cook static int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, 9645d442e63SKees Cook const char *symname) 9655d442e63SKees Cook { 9665d442e63SKees Cook unsigned r_type = ELF32_R_TYPE(rel->r_info); 9675d442e63SKees Cook int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); 9685d442e63SKees Cook 9695d442e63SKees Cook switch (r_type) { 9705d442e63SKees Cook case R_386_NONE: 9715d442e63SKees Cook case R_386_PC32: 9725d442e63SKees Cook case R_386_PC16: 9735d442e63SKees Cook case R_386_PC8: 974bb73d071SFangrui Song case R_386_PLT32: 9755d442e63SKees Cook /* 976bb73d071SFangrui Song * NONE can be ignored and PC relative relocations don't need 977bb73d071SFangrui Song * to be adjusted. Because sym must be defined, R_386_PLT32 can 978bb73d071SFangrui Song * be treated the same way as R_386_PC32. 9795d442e63SKees Cook */ 9805d442e63SKees Cook break; 9815d442e63SKees Cook 9825d442e63SKees Cook case R_386_16: 9835d442e63SKees Cook if (shn_abs) { 9845d442e63SKees Cook /* 9855d442e63SKees Cook * Whitelisted absolute symbols do not require 9865d442e63SKees Cook * relocation. 9875d442e63SKees Cook */ 9885d442e63SKees Cook if (is_reloc(S_ABS, symname)) 9895d442e63SKees Cook break; 9905d442e63SKees Cook 9915d442e63SKees Cook if (is_reloc(S_SEG, symname)) { 9925d442e63SKees Cook add_reloc(&relocs16, rel->r_offset); 9935d442e63SKees Cook break; 9945d442e63SKees Cook } 9955d442e63SKees Cook } else { 9965d442e63SKees Cook if (!is_reloc(S_LIN, symname)) 9975d442e63SKees Cook break; 9985d442e63SKees Cook } 99924ab82bdSH. Peter Anvin die("Invalid %s %s relocation: %s\n", 100024ab82bdSH. Peter Anvin shn_abs ? "absolute" : "relative", 10016520fe55SH. Peter Anvin rel_type(r_type), symname); 10025d442e63SKees Cook break; 10035d442e63SKees Cook 10045d442e63SKees Cook case R_386_32: 10055d442e63SKees Cook if (shn_abs) { 10065d442e63SKees Cook /* 10075d442e63SKees Cook * Whitelisted absolute symbols do not require 10085d442e63SKees Cook * relocation. 10095d442e63SKees Cook */ 10105d442e63SKees Cook if (is_reloc(S_ABS, symname)) 10115d442e63SKees Cook break; 10125d442e63SKees Cook 10135d442e63SKees Cook if (is_reloc(S_REL, symname)) { 10145d442e63SKees Cook add_reloc(&relocs32, rel->r_offset); 10155d442e63SKees Cook break; 10166520fe55SH. Peter Anvin } 10175d442e63SKees Cook } else { 10185d442e63SKees Cook if (is_reloc(S_LIN, symname)) 10195d442e63SKees Cook add_reloc(&relocs32, rel->r_offset); 10205d442e63SKees Cook break; 10216520fe55SH. Peter Anvin } 10225d442e63SKees Cook die("Invalid %s %s relocation: %s\n", 10235d442e63SKees Cook shn_abs ? "absolute" : "relative", 10245d442e63SKees Cook rel_type(r_type), symname); 10255d442e63SKees Cook break; 10265d442e63SKees Cook 10275d442e63SKees Cook default: 10285d442e63SKees Cook die("Unsupported relocation type: %s (%d)\n", 10295d442e63SKees Cook rel_type(r_type), r_type); 10305d442e63SKees Cook break; 10316520fe55SH. Peter Anvin } 10326520fe55SH. Peter Anvin 10335d442e63SKees Cook return 0; 10346520fe55SH. Peter Anvin } 10356520fe55SH. Peter Anvin 1036c889ba80SH. Peter Anvin #endif 1037c889ba80SH. Peter Anvin 10386520fe55SH. Peter Anvin static int cmp_relocs(const void *va, const void *vb) 10396520fe55SH. Peter Anvin { 10405d442e63SKees Cook const uint32_t *a, *b; 10416520fe55SH. Peter Anvin a = va; b = vb; 10426520fe55SH. Peter Anvin return (*a == *b)? 0 : (*a > *b)? 1 : -1; 10436520fe55SH. Peter Anvin } 10446520fe55SH. Peter Anvin 10455d442e63SKees Cook static void sort_relocs(struct relocs *r) 10465d442e63SKees Cook { 10475d442e63SKees Cook qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs); 10485d442e63SKees Cook } 10495d442e63SKees Cook 10505d442e63SKees Cook static int write32(uint32_t v, FILE *f) 10516520fe55SH. Peter Anvin { 10526520fe55SH. Peter Anvin unsigned char buf[4]; 10536520fe55SH. Peter Anvin 10546520fe55SH. Peter Anvin put_unaligned_le32(v, buf); 10556520fe55SH. Peter Anvin return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; 10566520fe55SH. Peter Anvin } 10576520fe55SH. Peter Anvin 10585d442e63SKees Cook static int write32_as_text(uint32_t v, FILE *f) 10595d442e63SKees Cook { 10605d442e63SKees Cook return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1; 10615d442e63SKees Cook } 10625d442e63SKees Cook 10636520fe55SH. Peter Anvin static void emit_relocs(int as_text, int use_real_mode) 10646520fe55SH. Peter Anvin { 10656520fe55SH. Peter Anvin int i; 10665d442e63SKees Cook int (*write_reloc)(uint32_t, FILE *) = write32; 1067946166afSKees Cook int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, 1068946166afSKees Cook const char *symname); 1069946166afSKees Cook 1070c889ba80SH. Peter Anvin #if ELF_BITS == 64 1071c889ba80SH. Peter Anvin if (!use_real_mode) 1072946166afSKees Cook do_reloc = do_reloc64; 1073c889ba80SH. Peter Anvin else 1074c889ba80SH. Peter Anvin die("--realmode not valid for a 64-bit ELF file"); 1075c889ba80SH. Peter Anvin #else 1076c889ba80SH. Peter Anvin if (!use_real_mode) 1077946166afSKees Cook do_reloc = do_reloc32; 1078946166afSKees Cook else 1079946166afSKees Cook do_reloc = do_reloc_real; 1080c889ba80SH. Peter Anvin #endif 10816520fe55SH. Peter Anvin 10826520fe55SH. Peter Anvin /* Collect up the relocations */ 1083946166afSKees Cook walk_relocs(do_reloc); 10846520fe55SH. Peter Anvin 10855d442e63SKees Cook if (relocs16.count && !use_real_mode) 10866520fe55SH. Peter Anvin die("Segment relocations found but --realmode not specified\n"); 10876520fe55SH. Peter Anvin 10886520fe55SH. Peter Anvin /* Order the relocations for more efficient processing */ 10895d442e63SKees Cook sort_relocs(&relocs32); 10906d24c5f7SJan Beulich #if ELF_BITS == 64 10916d24c5f7SJan Beulich sort_relocs(&relocs32neg); 1092946166afSKees Cook sort_relocs(&relocs64); 10937ebb9167SMarkus Trippelsdorf #else 10947ebb9167SMarkus Trippelsdorf sort_relocs(&relocs16); 10956d24c5f7SJan Beulich #endif 10966520fe55SH. Peter Anvin 10976520fe55SH. Peter Anvin /* Print the relocations */ 10986520fe55SH. Peter Anvin if (as_text) { 10996520fe55SH. Peter Anvin /* Print the relocations in a form suitable that 11006520fe55SH. Peter Anvin * gas will like. 11016520fe55SH. Peter Anvin */ 11026520fe55SH. Peter Anvin printf(".section \".data.reloc\",\"a\"\n"); 11036520fe55SH. Peter Anvin printf(".balign 4\n"); 11045d442e63SKees Cook write_reloc = write32_as_text; 11056520fe55SH. Peter Anvin } 11065d442e63SKees Cook 11075d442e63SKees Cook if (use_real_mode) { 11085d442e63SKees Cook write_reloc(relocs16.count, stdout); 11095d442e63SKees Cook for (i = 0; i < relocs16.count; i++) 11105d442e63SKees Cook write_reloc(relocs16.offset[i], stdout); 11115d442e63SKees Cook 11125d442e63SKees Cook write_reloc(relocs32.count, stdout); 11135d442e63SKees Cook for (i = 0; i < relocs32.count; i++) 11145d442e63SKees Cook write_reloc(relocs32.offset[i], stdout); 11156520fe55SH. Peter Anvin } else { 11166d24c5f7SJan Beulich #if ELF_BITS == 64 1117946166afSKees Cook /* Print a stop */ 1118946166afSKees Cook write_reloc(0, stdout); 1119946166afSKees Cook 1120946166afSKees Cook /* Now print each relocation */ 1121946166afSKees Cook for (i = 0; i < relocs64.count; i++) 1122946166afSKees Cook write_reloc(relocs64.offset[i], stdout); 11236d24c5f7SJan Beulich 11246d24c5f7SJan Beulich /* Print a stop */ 11256d24c5f7SJan Beulich write_reloc(0, stdout); 11266d24c5f7SJan Beulich 11276d24c5f7SJan Beulich /* Now print each inverse 32-bit relocation */ 11286d24c5f7SJan Beulich for (i = 0; i < relocs32neg.count; i++) 11296d24c5f7SJan Beulich write_reloc(relocs32neg.offset[i], stdout); 11306d24c5f7SJan Beulich #endif 1131946166afSKees Cook 11326520fe55SH. Peter Anvin /* Print a stop */ 11335d442e63SKees Cook write_reloc(0, stdout); 11346520fe55SH. Peter Anvin 11356520fe55SH. Peter Anvin /* Now print each relocation */ 11365d442e63SKees Cook for (i = 0; i < relocs32.count; i++) 11375d442e63SKees Cook write_reloc(relocs32.offset[i], stdout); 11386520fe55SH. Peter Anvin } 11396520fe55SH. Peter Anvin } 11406520fe55SH. Peter Anvin 1141214a8876SMichael Davidson /* 1142214a8876SMichael Davidson * As an aid to debugging problems with different linkers 1143214a8876SMichael Davidson * print summary information about the relocs. 1144214a8876SMichael Davidson * Since different linkers tend to emit the sections in 1145214a8876SMichael Davidson * different orders we use the section names in the output. 1146214a8876SMichael Davidson */ 1147214a8876SMichael Davidson static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, 1148214a8876SMichael Davidson const char *symname) 1149214a8876SMichael Davidson { 1150214a8876SMichael Davidson printf("%s\t%s\t%s\t%s\n", 1151214a8876SMichael Davidson sec_name(sec->shdr.sh_info), 1152214a8876SMichael Davidson rel_type(ELF_R_TYPE(rel->r_info)), 1153214a8876SMichael Davidson symname, 1154a54c401aSKristen Carlson Accardi sec_name(sym_index(sym))); 1155214a8876SMichael Davidson return 0; 1156214a8876SMichael Davidson } 1157214a8876SMichael Davidson 1158214a8876SMichael Davidson static void print_reloc_info(void) 1159214a8876SMichael Davidson { 1160214a8876SMichael Davidson printf("reloc section\treloc type\tsymbol\tsymbol section\n"); 1161214a8876SMichael Davidson walk_relocs(do_reloc_info); 1162214a8876SMichael Davidson } 1163214a8876SMichael Davidson 1164c889ba80SH. Peter Anvin #if ELF_BITS == 64 1165c889ba80SH. Peter Anvin # define process process_64 1166c889ba80SH. Peter Anvin #else 1167c889ba80SH. Peter Anvin # define process process_32 1168c889ba80SH. Peter Anvin #endif 11696520fe55SH. Peter Anvin 1170c889ba80SH. Peter Anvin void process(FILE *fp, int use_real_mode, int as_text, 1171214a8876SMichael Davidson int show_absolute_syms, int show_absolute_relocs, 1172214a8876SMichael Davidson int show_reloc_info) 11736520fe55SH. Peter Anvin { 11746520fe55SH. Peter Anvin regex_init(use_real_mode); 11756520fe55SH. Peter Anvin read_ehdr(fp); 11766520fe55SH. Peter Anvin read_shdrs(fp); 11776520fe55SH. Peter Anvin read_strtabs(fp); 11786520fe55SH. Peter Anvin read_symtabs(fp); 11796520fe55SH. Peter Anvin read_relocs(fp); 1180c889ba80SH. Peter Anvin if (ELF_BITS == 64) 1181946166afSKees Cook percpu_init(); 11826520fe55SH. Peter Anvin if (show_absolute_syms) { 11836520fe55SH. Peter Anvin print_absolute_symbols(); 1184c889ba80SH. Peter Anvin return; 11856520fe55SH. Peter Anvin } 11866520fe55SH. Peter Anvin if (show_absolute_relocs) { 11876520fe55SH. Peter Anvin print_absolute_relocs(); 1188c889ba80SH. Peter Anvin return; 11896520fe55SH. Peter Anvin } 1190214a8876SMichael Davidson if (show_reloc_info) { 1191214a8876SMichael Davidson print_reloc_info(); 1192214a8876SMichael Davidson return; 1193214a8876SMichael Davidson } 11946520fe55SH. Peter Anvin emit_relocs(as_text, use_real_mode); 11956520fe55SH. Peter Anvin } 1196