18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* This is included from relocs_32/64.c */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#define ElfW(type) _ElfW(ELF_BITS, type) 58c2ecf20Sopenharmony_ci#define _ElfW(bits, type) __ElfW(bits, type) 68c2ecf20Sopenharmony_ci#define __ElfW(bits, type) Elf##bits##_##type 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define Elf_Addr ElfW(Addr) 98c2ecf20Sopenharmony_ci#define Elf_Ehdr ElfW(Ehdr) 108c2ecf20Sopenharmony_ci#define Elf_Phdr ElfW(Phdr) 118c2ecf20Sopenharmony_ci#define Elf_Shdr ElfW(Shdr) 128c2ecf20Sopenharmony_ci#define Elf_Sym ElfW(Sym) 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic Elf_Ehdr ehdr; 158c2ecf20Sopenharmony_cistatic unsigned long shnum; 168c2ecf20Sopenharmony_cistatic unsigned int shstrndx; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct relocs { 198c2ecf20Sopenharmony_ci uint32_t *offset; 208c2ecf20Sopenharmony_ci unsigned long count; 218c2ecf20Sopenharmony_ci unsigned long size; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic struct relocs relocs16; 258c2ecf20Sopenharmony_cistatic struct relocs relocs32; 268c2ecf20Sopenharmony_ci#if ELF_BITS == 64 278c2ecf20Sopenharmony_cistatic struct relocs relocs32neg; 288c2ecf20Sopenharmony_cistatic struct relocs relocs64; 298c2ecf20Sopenharmony_ci#endif 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct section { 328c2ecf20Sopenharmony_ci Elf_Shdr shdr; 338c2ecf20Sopenharmony_ci struct section *link; 348c2ecf20Sopenharmony_ci Elf_Sym *symtab; 358c2ecf20Sopenharmony_ci Elf_Rel *reltab; 368c2ecf20Sopenharmony_ci char *strtab; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_cistatic struct section *secs; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic const char * const sym_regex_kernel[S_NSYMTYPES] = { 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Following symbols have been audited. There values are constant and do 438c2ecf20Sopenharmony_ci * not change if bzImage is loaded at a different physical address than 448c2ecf20Sopenharmony_ci * the address for which it has been compiled. Don't warn user about 458c2ecf20Sopenharmony_ci * absolute relocations present w.r.t these symbols. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci [S_ABS] = 488c2ecf20Sopenharmony_ci "^(xen_irq_disable_direct_reloc$|" 498c2ecf20Sopenharmony_ci "xen_save_fl_direct_reloc$|" 508c2ecf20Sopenharmony_ci "VDSO|" 518c2ecf20Sopenharmony_ci "__crc_)", 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * These symbols are known to be relative, even if the linker marks them 558c2ecf20Sopenharmony_ci * as absolute (typically defined outside any section in the linker script.) 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci [S_REL] = 588c2ecf20Sopenharmony_ci "^(__init_(begin|end)|" 598c2ecf20Sopenharmony_ci "__x86_cpu_dev_(start|end)|" 608c2ecf20Sopenharmony_ci "(__parainstructions|__alt_instructions)(|_end)|" 618c2ecf20Sopenharmony_ci "(__iommu_table|__apicdrivers|__smp_locks)(|_end)|" 628c2ecf20Sopenharmony_ci "__(start|end)_pci_.*|" 638c2ecf20Sopenharmony_ci "__(start|end)_builtin_fw|" 648c2ecf20Sopenharmony_ci "__(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)|" 658c2ecf20Sopenharmony_ci "__(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)|" 668c2ecf20Sopenharmony_ci "__(start|stop)___param|" 678c2ecf20Sopenharmony_ci "__(start|stop)___modver|" 688c2ecf20Sopenharmony_ci "__(start|stop)___bug_table|" 698c2ecf20Sopenharmony_ci "__tracedata_(start|end)|" 708c2ecf20Sopenharmony_ci "__(start|stop)_notes|" 718c2ecf20Sopenharmony_ci "__end_rodata|" 728c2ecf20Sopenharmony_ci "__end_rodata_aligned|" 738c2ecf20Sopenharmony_ci "__initramfs_start|" 748c2ecf20Sopenharmony_ci "(jiffies|jiffies_64)|" 758c2ecf20Sopenharmony_ci#if ELF_BITS == 64 768c2ecf20Sopenharmony_ci "__per_cpu_load|" 778c2ecf20Sopenharmony_ci "init_per_cpu__.*|" 788c2ecf20Sopenharmony_ci "__end_rodata_hpage_align|" 798c2ecf20Sopenharmony_ci#endif 808c2ecf20Sopenharmony_ci "__vvar_page|" 818c2ecf20Sopenharmony_ci "_end)$" 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic const char * const sym_regex_realmode[S_NSYMTYPES] = { 868c2ecf20Sopenharmony_ci/* 878c2ecf20Sopenharmony_ci * These symbols are known to be relative, even if the linker marks them 888c2ecf20Sopenharmony_ci * as absolute (typically defined outside any section in the linker script.) 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci [S_REL] = 918c2ecf20Sopenharmony_ci "^pa_", 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * These are 16-bit segment symbols when compiling 16-bit code. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci [S_SEG] = 978c2ecf20Sopenharmony_ci "^real_mode_seg$", 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * These are offsets belonging to segments, as opposed to linear addresses, 1018c2ecf20Sopenharmony_ci * when compiling 16-bit code. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci [S_LIN] = 1048c2ecf20Sopenharmony_ci "^pa_", 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic const char * const *sym_regex; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic regex_t sym_regex_c[S_NSYMTYPES]; 1108c2ecf20Sopenharmony_cistatic int is_reloc(enum symtype type, const char *sym_name) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci return sym_regex[type] && 1138c2ecf20Sopenharmony_ci !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void regex_init(int use_real_mode) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci char errbuf[128]; 1198c2ecf20Sopenharmony_ci int err; 1208c2ecf20Sopenharmony_ci int i; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (use_real_mode) 1238c2ecf20Sopenharmony_ci sym_regex = sym_regex_realmode; 1248c2ecf20Sopenharmony_ci else 1258c2ecf20Sopenharmony_ci sym_regex = sym_regex_kernel; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci for (i = 0; i < S_NSYMTYPES; i++) { 1288c2ecf20Sopenharmony_ci if (!sym_regex[i]) 1298c2ecf20Sopenharmony_ci continue; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci err = regcomp(&sym_regex_c[i], sym_regex[i], 1328c2ecf20Sopenharmony_ci REG_EXTENDED|REG_NOSUB); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (err) { 1358c2ecf20Sopenharmony_ci regerror(err, &sym_regex_c[i], errbuf, sizeof(errbuf)); 1368c2ecf20Sopenharmony_ci die("%s", errbuf); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const char *sym_type(unsigned type) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci static const char *type_name[] = { 1448c2ecf20Sopenharmony_ci#define SYM_TYPE(X) [X] = #X 1458c2ecf20Sopenharmony_ci SYM_TYPE(STT_NOTYPE), 1468c2ecf20Sopenharmony_ci SYM_TYPE(STT_OBJECT), 1478c2ecf20Sopenharmony_ci SYM_TYPE(STT_FUNC), 1488c2ecf20Sopenharmony_ci SYM_TYPE(STT_SECTION), 1498c2ecf20Sopenharmony_ci SYM_TYPE(STT_FILE), 1508c2ecf20Sopenharmony_ci SYM_TYPE(STT_COMMON), 1518c2ecf20Sopenharmony_ci SYM_TYPE(STT_TLS), 1528c2ecf20Sopenharmony_ci#undef SYM_TYPE 1538c2ecf20Sopenharmony_ci }; 1548c2ecf20Sopenharmony_ci const char *name = "unknown sym type name"; 1558c2ecf20Sopenharmony_ci if (type < ARRAY_SIZE(type_name)) { 1568c2ecf20Sopenharmony_ci name = type_name[type]; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci return name; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic const char *sym_bind(unsigned bind) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci static const char *bind_name[] = { 1648c2ecf20Sopenharmony_ci#define SYM_BIND(X) [X] = #X 1658c2ecf20Sopenharmony_ci SYM_BIND(STB_LOCAL), 1668c2ecf20Sopenharmony_ci SYM_BIND(STB_GLOBAL), 1678c2ecf20Sopenharmony_ci SYM_BIND(STB_WEAK), 1688c2ecf20Sopenharmony_ci#undef SYM_BIND 1698c2ecf20Sopenharmony_ci }; 1708c2ecf20Sopenharmony_ci const char *name = "unknown sym bind name"; 1718c2ecf20Sopenharmony_ci if (bind < ARRAY_SIZE(bind_name)) { 1728c2ecf20Sopenharmony_ci name = bind_name[bind]; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci return name; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const char *sym_visibility(unsigned visibility) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci static const char *visibility_name[] = { 1808c2ecf20Sopenharmony_ci#define SYM_VISIBILITY(X) [X] = #X 1818c2ecf20Sopenharmony_ci SYM_VISIBILITY(STV_DEFAULT), 1828c2ecf20Sopenharmony_ci SYM_VISIBILITY(STV_INTERNAL), 1838c2ecf20Sopenharmony_ci SYM_VISIBILITY(STV_HIDDEN), 1848c2ecf20Sopenharmony_ci SYM_VISIBILITY(STV_PROTECTED), 1858c2ecf20Sopenharmony_ci#undef SYM_VISIBILITY 1868c2ecf20Sopenharmony_ci }; 1878c2ecf20Sopenharmony_ci const char *name = "unknown sym visibility name"; 1888c2ecf20Sopenharmony_ci if (visibility < ARRAY_SIZE(visibility_name)) { 1898c2ecf20Sopenharmony_ci name = visibility_name[visibility]; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci return name; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const char *rel_type(unsigned type) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci static const char *type_name[] = { 1978c2ecf20Sopenharmony_ci#define REL_TYPE(X) [X] = #X 1988c2ecf20Sopenharmony_ci#if ELF_BITS == 64 1998c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_NONE), 2008c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_64), 2018c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_PC64), 2028c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_PC32), 2038c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_GOT32), 2048c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_PLT32), 2058c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_COPY), 2068c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_GLOB_DAT), 2078c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_JUMP_SLOT), 2088c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_RELATIVE), 2098c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_GOTPCREL), 2108c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_32), 2118c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_32S), 2128c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_16), 2138c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_PC16), 2148c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_8), 2158c2ecf20Sopenharmony_ci REL_TYPE(R_X86_64_PC8), 2168c2ecf20Sopenharmony_ci#else 2178c2ecf20Sopenharmony_ci REL_TYPE(R_386_NONE), 2188c2ecf20Sopenharmony_ci REL_TYPE(R_386_32), 2198c2ecf20Sopenharmony_ci REL_TYPE(R_386_PC32), 2208c2ecf20Sopenharmony_ci REL_TYPE(R_386_GOT32), 2218c2ecf20Sopenharmony_ci REL_TYPE(R_386_PLT32), 2228c2ecf20Sopenharmony_ci REL_TYPE(R_386_COPY), 2238c2ecf20Sopenharmony_ci REL_TYPE(R_386_GLOB_DAT), 2248c2ecf20Sopenharmony_ci REL_TYPE(R_386_JMP_SLOT), 2258c2ecf20Sopenharmony_ci REL_TYPE(R_386_RELATIVE), 2268c2ecf20Sopenharmony_ci REL_TYPE(R_386_GOTOFF), 2278c2ecf20Sopenharmony_ci REL_TYPE(R_386_GOTPC), 2288c2ecf20Sopenharmony_ci REL_TYPE(R_386_8), 2298c2ecf20Sopenharmony_ci REL_TYPE(R_386_PC8), 2308c2ecf20Sopenharmony_ci REL_TYPE(R_386_16), 2318c2ecf20Sopenharmony_ci REL_TYPE(R_386_PC16), 2328c2ecf20Sopenharmony_ci#endif 2338c2ecf20Sopenharmony_ci#undef REL_TYPE 2348c2ecf20Sopenharmony_ci }; 2358c2ecf20Sopenharmony_ci const char *name = "unknown type rel type name"; 2368c2ecf20Sopenharmony_ci if (type < ARRAY_SIZE(type_name) && type_name[type]) { 2378c2ecf20Sopenharmony_ci name = type_name[type]; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci return name; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic const char *sec_name(unsigned shndx) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci const char *sec_strtab; 2458c2ecf20Sopenharmony_ci const char *name; 2468c2ecf20Sopenharmony_ci sec_strtab = secs[shstrndx].strtab; 2478c2ecf20Sopenharmony_ci name = "<noname>"; 2488c2ecf20Sopenharmony_ci if (shndx < shnum) { 2498c2ecf20Sopenharmony_ci name = sec_strtab + secs[shndx].shdr.sh_name; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci else if (shndx == SHN_ABS) { 2528c2ecf20Sopenharmony_ci name = "ABSOLUTE"; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci else if (shndx == SHN_COMMON) { 2558c2ecf20Sopenharmony_ci name = "COMMON"; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci return name; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic const char *sym_name(const char *sym_strtab, Elf_Sym *sym) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci const char *name; 2638c2ecf20Sopenharmony_ci name = "<noname>"; 2648c2ecf20Sopenharmony_ci if (sym->st_name) { 2658c2ecf20Sopenharmony_ci name = sym_strtab + sym->st_name; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci else { 2688c2ecf20Sopenharmony_ci name = sec_name(sym->st_shndx); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci return name; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic Elf_Sym *sym_lookup(const char *symname) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci int i; 2768c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 2778c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 2788c2ecf20Sopenharmony_ci long nsyms; 2798c2ecf20Sopenharmony_ci char *strtab; 2808c2ecf20Sopenharmony_ci Elf_Sym *symtab; 2818c2ecf20Sopenharmony_ci Elf_Sym *sym; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_SYMTAB) 2848c2ecf20Sopenharmony_ci continue; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci nsyms = sec->shdr.sh_size/sizeof(Elf_Sym); 2878c2ecf20Sopenharmony_ci symtab = sec->symtab; 2888c2ecf20Sopenharmony_ci strtab = sec->link->strtab; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for (sym = symtab; --nsyms >= 0; sym++) { 2918c2ecf20Sopenharmony_ci if (!sym->st_name) 2928c2ecf20Sopenharmony_ci continue; 2938c2ecf20Sopenharmony_ci if (strcmp(symname, strtab + sym->st_name) == 0) 2948c2ecf20Sopenharmony_ci return sym; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci#if BYTE_ORDER == LITTLE_ENDIAN 3018c2ecf20Sopenharmony_ci#define le16_to_cpu(val) (val) 3028c2ecf20Sopenharmony_ci#define le32_to_cpu(val) (val) 3038c2ecf20Sopenharmony_ci#define le64_to_cpu(val) (val) 3048c2ecf20Sopenharmony_ci#endif 3058c2ecf20Sopenharmony_ci#if BYTE_ORDER == BIG_ENDIAN 3068c2ecf20Sopenharmony_ci#define le16_to_cpu(val) bswap_16(val) 3078c2ecf20Sopenharmony_ci#define le32_to_cpu(val) bswap_32(val) 3088c2ecf20Sopenharmony_ci#define le64_to_cpu(val) bswap_64(val) 3098c2ecf20Sopenharmony_ci#endif 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic uint16_t elf16_to_cpu(uint16_t val) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci return le16_to_cpu(val); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic uint32_t elf32_to_cpu(uint32_t val) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci return le32_to_cpu(val); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci#define elf_half_to_cpu(x) elf16_to_cpu(x) 3228c2ecf20Sopenharmony_ci#define elf_word_to_cpu(x) elf32_to_cpu(x) 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci#if ELF_BITS == 64 3258c2ecf20Sopenharmony_cistatic uint64_t elf64_to_cpu(uint64_t val) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci return le64_to_cpu(val); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci#define elf_addr_to_cpu(x) elf64_to_cpu(x) 3308c2ecf20Sopenharmony_ci#define elf_off_to_cpu(x) elf64_to_cpu(x) 3318c2ecf20Sopenharmony_ci#define elf_xword_to_cpu(x) elf64_to_cpu(x) 3328c2ecf20Sopenharmony_ci#else 3338c2ecf20Sopenharmony_ci#define elf_addr_to_cpu(x) elf32_to_cpu(x) 3348c2ecf20Sopenharmony_ci#define elf_off_to_cpu(x) elf32_to_cpu(x) 3358c2ecf20Sopenharmony_ci#define elf_xword_to_cpu(x) elf32_to_cpu(x) 3368c2ecf20Sopenharmony_ci#endif 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic void read_ehdr(FILE *fp) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { 3418c2ecf20Sopenharmony_ci die("Cannot read ELF header: %s\n", 3428c2ecf20Sopenharmony_ci strerror(errno)); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { 3458c2ecf20Sopenharmony_ci die("No ELF magic\n"); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) { 3488c2ecf20Sopenharmony_ci die("Not a %d bit executable\n", ELF_BITS); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { 3518c2ecf20Sopenharmony_ci die("Not a LSB ELF executable\n"); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { 3548c2ecf20Sopenharmony_ci die("Unknown ELF version\n"); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci /* Convert the fields to native endian */ 3578c2ecf20Sopenharmony_ci ehdr.e_type = elf_half_to_cpu(ehdr.e_type); 3588c2ecf20Sopenharmony_ci ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine); 3598c2ecf20Sopenharmony_ci ehdr.e_version = elf_word_to_cpu(ehdr.e_version); 3608c2ecf20Sopenharmony_ci ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry); 3618c2ecf20Sopenharmony_ci ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff); 3628c2ecf20Sopenharmony_ci ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff); 3638c2ecf20Sopenharmony_ci ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags); 3648c2ecf20Sopenharmony_ci ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize); 3658c2ecf20Sopenharmony_ci ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize); 3668c2ecf20Sopenharmony_ci ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum); 3678c2ecf20Sopenharmony_ci ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize); 3688c2ecf20Sopenharmony_ci ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum); 3698c2ecf20Sopenharmony_ci ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci shnum = ehdr.e_shnum; 3728c2ecf20Sopenharmony_ci shstrndx = ehdr.e_shstrndx; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) 3758c2ecf20Sopenharmony_ci die("Unsupported ELF header type\n"); 3768c2ecf20Sopenharmony_ci if (ehdr.e_machine != ELF_MACHINE) 3778c2ecf20Sopenharmony_ci die("Not for %s\n", ELF_MACHINE_NAME); 3788c2ecf20Sopenharmony_ci if (ehdr.e_version != EV_CURRENT) 3798c2ecf20Sopenharmony_ci die("Unknown ELF version\n"); 3808c2ecf20Sopenharmony_ci if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) 3818c2ecf20Sopenharmony_ci die("Bad Elf header size\n"); 3828c2ecf20Sopenharmony_ci if (ehdr.e_phentsize != sizeof(Elf_Phdr)) 3838c2ecf20Sopenharmony_ci die("Bad program header entry\n"); 3848c2ecf20Sopenharmony_ci if (ehdr.e_shentsize != sizeof(Elf_Shdr)) 3858c2ecf20Sopenharmony_ci die("Bad section header entry\n"); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) { 3898c2ecf20Sopenharmony_ci Elf_Shdr shdr; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) 3928c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", ehdr.e_shoff, strerror(errno)); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (fread(&shdr, sizeof(shdr), 1, fp) != 1) 3958c2ecf20Sopenharmony_ci die("Cannot read initial ELF section header: %s\n", strerror(errno)); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (shnum == SHN_UNDEF) 3988c2ecf20Sopenharmony_ci shnum = elf_xword_to_cpu(shdr.sh_size); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (shstrndx == SHN_XINDEX) 4018c2ecf20Sopenharmony_ci shstrndx = elf_word_to_cpu(shdr.sh_link); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (shstrndx >= shnum) 4058c2ecf20Sopenharmony_ci die("String table index out of bounds\n"); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void read_shdrs(FILE *fp) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci int i; 4118c2ecf20Sopenharmony_ci Elf_Shdr shdr; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci secs = calloc(shnum, sizeof(struct section)); 4148c2ecf20Sopenharmony_ci if (!secs) { 4158c2ecf20Sopenharmony_ci die("Unable to allocate %d section headers\n", 4168c2ecf20Sopenharmony_ci shnum); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { 4198c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 4208c2ecf20Sopenharmony_ci ehdr.e_shoff, strerror(errno)); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 4238c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 4248c2ecf20Sopenharmony_ci if (fread(&shdr, sizeof(shdr), 1, fp) != 1) 4258c2ecf20Sopenharmony_ci die("Cannot read ELF section headers %d/%d: %s\n", 4268c2ecf20Sopenharmony_ci i, shnum, strerror(errno)); 4278c2ecf20Sopenharmony_ci sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name); 4288c2ecf20Sopenharmony_ci sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type); 4298c2ecf20Sopenharmony_ci sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags); 4308c2ecf20Sopenharmony_ci sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr); 4318c2ecf20Sopenharmony_ci sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset); 4328c2ecf20Sopenharmony_ci sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size); 4338c2ecf20Sopenharmony_ci sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link); 4348c2ecf20Sopenharmony_ci sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info); 4358c2ecf20Sopenharmony_ci sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign); 4368c2ecf20Sopenharmony_ci sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize); 4378c2ecf20Sopenharmony_ci if (sec->shdr.sh_link < shnum) 4388c2ecf20Sopenharmony_ci sec->link = &secs[sec->shdr.sh_link]; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void read_strtabs(FILE *fp) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci int i; 4468c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 4478c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 4488c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_STRTAB) { 4498c2ecf20Sopenharmony_ci continue; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci sec->strtab = malloc(sec->shdr.sh_size); 4528c2ecf20Sopenharmony_ci if (!sec->strtab) { 4538c2ecf20Sopenharmony_ci die("malloc of %d bytes for strtab failed\n", 4548c2ecf20Sopenharmony_ci sec->shdr.sh_size); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 4578c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 4588c2ecf20Sopenharmony_ci sec->shdr.sh_offset, strerror(errno)); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) 4618c2ecf20Sopenharmony_ci != sec->shdr.sh_size) { 4628c2ecf20Sopenharmony_ci die("Cannot read symbol table: %s\n", 4638c2ecf20Sopenharmony_ci strerror(errno)); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic void read_symtabs(FILE *fp) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci int i,j; 4718c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 4728c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 4738c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_SYMTAB) { 4748c2ecf20Sopenharmony_ci continue; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci sec->symtab = malloc(sec->shdr.sh_size); 4778c2ecf20Sopenharmony_ci if (!sec->symtab) { 4788c2ecf20Sopenharmony_ci die("malloc of %d bytes for symtab failed\n", 4798c2ecf20Sopenharmony_ci sec->shdr.sh_size); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 4828c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 4838c2ecf20Sopenharmony_ci sec->shdr.sh_offset, strerror(errno)); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) 4868c2ecf20Sopenharmony_ci != sec->shdr.sh_size) { 4878c2ecf20Sopenharmony_ci die("Cannot read symbol table: %s\n", 4888c2ecf20Sopenharmony_ci strerror(errno)); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) { 4918c2ecf20Sopenharmony_ci Elf_Sym *sym = &sec->symtab[j]; 4928c2ecf20Sopenharmony_ci sym->st_name = elf_word_to_cpu(sym->st_name); 4938c2ecf20Sopenharmony_ci sym->st_value = elf_addr_to_cpu(sym->st_value); 4948c2ecf20Sopenharmony_ci sym->st_size = elf_xword_to_cpu(sym->st_size); 4958c2ecf20Sopenharmony_ci sym->st_shndx = elf_half_to_cpu(sym->st_shndx); 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic void read_relocs(FILE *fp) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci int i,j; 5048c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 5058c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 5068c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_REL_TYPE) { 5078c2ecf20Sopenharmony_ci continue; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci sec->reltab = malloc(sec->shdr.sh_size); 5108c2ecf20Sopenharmony_ci if (!sec->reltab) { 5118c2ecf20Sopenharmony_ci die("malloc of %d bytes for relocs failed\n", 5128c2ecf20Sopenharmony_ci sec->shdr.sh_size); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 5158c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 5168c2ecf20Sopenharmony_ci sec->shdr.sh_offset, strerror(errno)); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) 5198c2ecf20Sopenharmony_ci != sec->shdr.sh_size) { 5208c2ecf20Sopenharmony_ci die("Cannot read symbol table: %s\n", 5218c2ecf20Sopenharmony_ci strerror(errno)); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 5248c2ecf20Sopenharmony_ci Elf_Rel *rel = &sec->reltab[j]; 5258c2ecf20Sopenharmony_ci rel->r_offset = elf_addr_to_cpu(rel->r_offset); 5268c2ecf20Sopenharmony_ci rel->r_info = elf_xword_to_cpu(rel->r_info); 5278c2ecf20Sopenharmony_ci#if (SHT_REL_TYPE == SHT_RELA) 5288c2ecf20Sopenharmony_ci rel->r_addend = elf_xword_to_cpu(rel->r_addend); 5298c2ecf20Sopenharmony_ci#endif 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic void print_absolute_symbols(void) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci int i; 5388c2ecf20Sopenharmony_ci const char *format; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (ELF_BITS == 64) 5418c2ecf20Sopenharmony_ci format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n"; 5428c2ecf20Sopenharmony_ci else 5438c2ecf20Sopenharmony_ci format = "%5d %08"PRIx32" %5"PRId32" %10s %10s %12s %s\n"; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci printf("Absolute symbols\n"); 5468c2ecf20Sopenharmony_ci printf(" Num: Value Size Type Bind Visibility Name\n"); 5478c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 5488c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 5498c2ecf20Sopenharmony_ci char *sym_strtab; 5508c2ecf20Sopenharmony_ci int j; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_SYMTAB) { 5538c2ecf20Sopenharmony_ci continue; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci sym_strtab = sec->link->strtab; 5568c2ecf20Sopenharmony_ci for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) { 5578c2ecf20Sopenharmony_ci Elf_Sym *sym; 5588c2ecf20Sopenharmony_ci const char *name; 5598c2ecf20Sopenharmony_ci sym = &sec->symtab[j]; 5608c2ecf20Sopenharmony_ci name = sym_name(sym_strtab, sym); 5618c2ecf20Sopenharmony_ci if (sym->st_shndx != SHN_ABS) { 5628c2ecf20Sopenharmony_ci continue; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci printf(format, 5658c2ecf20Sopenharmony_ci j, sym->st_value, sym->st_size, 5668c2ecf20Sopenharmony_ci sym_type(ELF_ST_TYPE(sym->st_info)), 5678c2ecf20Sopenharmony_ci sym_bind(ELF_ST_BIND(sym->st_info)), 5688c2ecf20Sopenharmony_ci sym_visibility(ELF_ST_VISIBILITY(sym->st_other)), 5698c2ecf20Sopenharmony_ci name); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci printf("\n"); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic void print_absolute_relocs(void) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci int i, printed = 0; 5788c2ecf20Sopenharmony_ci const char *format; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (ELF_BITS == 64) 5818c2ecf20Sopenharmony_ci format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64" %s\n"; 5828c2ecf20Sopenharmony_ci else 5838c2ecf20Sopenharmony_ci format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32" %s\n"; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 5868c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 5878c2ecf20Sopenharmony_ci struct section *sec_applies, *sec_symtab; 5888c2ecf20Sopenharmony_ci char *sym_strtab; 5898c2ecf20Sopenharmony_ci Elf_Sym *sh_symtab; 5908c2ecf20Sopenharmony_ci int j; 5918c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_REL_TYPE) { 5928c2ecf20Sopenharmony_ci continue; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci sec_symtab = sec->link; 5958c2ecf20Sopenharmony_ci sec_applies = &secs[sec->shdr.sh_info]; 5968c2ecf20Sopenharmony_ci if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 5978c2ecf20Sopenharmony_ci continue; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci sh_symtab = sec_symtab->symtab; 6008c2ecf20Sopenharmony_ci sym_strtab = sec_symtab->link->strtab; 6018c2ecf20Sopenharmony_ci for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 6028c2ecf20Sopenharmony_ci Elf_Rel *rel; 6038c2ecf20Sopenharmony_ci Elf_Sym *sym; 6048c2ecf20Sopenharmony_ci const char *name; 6058c2ecf20Sopenharmony_ci rel = &sec->reltab[j]; 6068c2ecf20Sopenharmony_ci sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; 6078c2ecf20Sopenharmony_ci name = sym_name(sym_strtab, sym); 6088c2ecf20Sopenharmony_ci if (sym->st_shndx != SHN_ABS) { 6098c2ecf20Sopenharmony_ci continue; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* Absolute symbols are not relocated if bzImage is 6138c2ecf20Sopenharmony_ci * loaded at a non-compiled address. Display a warning 6148c2ecf20Sopenharmony_ci * to user at compile time about the absolute 6158c2ecf20Sopenharmony_ci * relocations present. 6168c2ecf20Sopenharmony_ci * 6178c2ecf20Sopenharmony_ci * User need to audit the code to make sure 6188c2ecf20Sopenharmony_ci * some symbols which should have been section 6198c2ecf20Sopenharmony_ci * relative have not become absolute because of some 6208c2ecf20Sopenharmony_ci * linker optimization or wrong programming usage. 6218c2ecf20Sopenharmony_ci * 6228c2ecf20Sopenharmony_ci * Before warning check if this absolute symbol 6238c2ecf20Sopenharmony_ci * relocation is harmless. 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_ci if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) 6268c2ecf20Sopenharmony_ci continue; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (!printed) { 6298c2ecf20Sopenharmony_ci printf("WARNING: Absolute relocations" 6308c2ecf20Sopenharmony_ci " present\n"); 6318c2ecf20Sopenharmony_ci printf("Offset Info Type Sym.Value " 6328c2ecf20Sopenharmony_ci "Sym.Name\n"); 6338c2ecf20Sopenharmony_ci printed = 1; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci printf(format, 6378c2ecf20Sopenharmony_ci rel->r_offset, 6388c2ecf20Sopenharmony_ci rel->r_info, 6398c2ecf20Sopenharmony_ci rel_type(ELF_R_TYPE(rel->r_info)), 6408c2ecf20Sopenharmony_ci sym->st_value, 6418c2ecf20Sopenharmony_ci name); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (printed) 6468c2ecf20Sopenharmony_ci printf("\n"); 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic void add_reloc(struct relocs *r, uint32_t offset) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci if (r->count == r->size) { 6528c2ecf20Sopenharmony_ci unsigned long newsize = r->size + 50000; 6538c2ecf20Sopenharmony_ci void *mem = realloc(r->offset, newsize * sizeof(r->offset[0])); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (!mem) 6568c2ecf20Sopenharmony_ci die("realloc of %ld entries for relocs failed\n", 6578c2ecf20Sopenharmony_ci newsize); 6588c2ecf20Sopenharmony_ci r->offset = mem; 6598c2ecf20Sopenharmony_ci r->size = newsize; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci r->offset[r->count++] = offset; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, 6658c2ecf20Sopenharmony_ci Elf_Sym *sym, const char *symname)) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci int i; 6688c2ecf20Sopenharmony_ci /* Walk through the relocations */ 6698c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 6708c2ecf20Sopenharmony_ci char *sym_strtab; 6718c2ecf20Sopenharmony_ci Elf_Sym *sh_symtab; 6728c2ecf20Sopenharmony_ci struct section *sec_applies, *sec_symtab; 6738c2ecf20Sopenharmony_ci int j; 6748c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_REL_TYPE) { 6778c2ecf20Sopenharmony_ci continue; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci sec_symtab = sec->link; 6808c2ecf20Sopenharmony_ci sec_applies = &secs[sec->shdr.sh_info]; 6818c2ecf20Sopenharmony_ci if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 6828c2ecf20Sopenharmony_ci continue; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci sh_symtab = sec_symtab->symtab; 6858c2ecf20Sopenharmony_ci sym_strtab = sec_symtab->link->strtab; 6868c2ecf20Sopenharmony_ci for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 6878c2ecf20Sopenharmony_ci Elf_Rel *rel = &sec->reltab[j]; 6888c2ecf20Sopenharmony_ci Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; 6898c2ecf20Sopenharmony_ci const char *symname = sym_name(sym_strtab, sym); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci process(sec, rel, sym, symname); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/* 6978c2ecf20Sopenharmony_ci * The .data..percpu section is a special case for x86_64 SMP kernels. 6988c2ecf20Sopenharmony_ci * It is used to initialize the actual per_cpu areas and to provide 6998c2ecf20Sopenharmony_ci * definitions for the per_cpu variables that correspond to their offsets 7008c2ecf20Sopenharmony_ci * within the percpu area. Since the values of all of the symbols need 7018c2ecf20Sopenharmony_ci * to be offsets from the start of the per_cpu area the virtual address 7028c2ecf20Sopenharmony_ci * (sh_addr) of .data..percpu is 0 in SMP kernels. 7038c2ecf20Sopenharmony_ci * 7048c2ecf20Sopenharmony_ci * This means that: 7058c2ecf20Sopenharmony_ci * 7068c2ecf20Sopenharmony_ci * Relocations that reference symbols in the per_cpu area do not 7078c2ecf20Sopenharmony_ci * need further relocation (since the value is an offset relative 7088c2ecf20Sopenharmony_ci * to the start of the per_cpu area that does not change). 7098c2ecf20Sopenharmony_ci * 7108c2ecf20Sopenharmony_ci * Relocations that apply to the per_cpu area need to have their 7118c2ecf20Sopenharmony_ci * offset adjusted by by the value of __per_cpu_load to make them 7128c2ecf20Sopenharmony_ci * point to the correct place in the loaded image (because the 7138c2ecf20Sopenharmony_ci * virtual address of .data..percpu is 0). 7148c2ecf20Sopenharmony_ci * 7158c2ecf20Sopenharmony_ci * For non SMP kernels .data..percpu is linked as part of the normal 7168c2ecf20Sopenharmony_ci * kernel data and does not require special treatment. 7178c2ecf20Sopenharmony_ci * 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_cistatic int per_cpu_shndx = -1; 7208c2ecf20Sopenharmony_cistatic Elf_Addr per_cpu_load_addr; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic void percpu_init(void) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci int i; 7258c2ecf20Sopenharmony_ci for (i = 0; i < shnum; i++) { 7268c2ecf20Sopenharmony_ci ElfW(Sym) *sym; 7278c2ecf20Sopenharmony_ci if (strcmp(sec_name(i), ".data..percpu")) 7288c2ecf20Sopenharmony_ci continue; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */ 7318c2ecf20Sopenharmony_ci return; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci sym = sym_lookup("__per_cpu_load"); 7348c2ecf20Sopenharmony_ci if (!sym) 7358c2ecf20Sopenharmony_ci die("can't find __per_cpu_load\n"); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci per_cpu_shndx = i; 7388c2ecf20Sopenharmony_ci per_cpu_load_addr = sym->st_value; 7398c2ecf20Sopenharmony_ci return; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci#if ELF_BITS == 64 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci/* 7468c2ecf20Sopenharmony_ci * Check to see if a symbol lies in the .data..percpu section. 7478c2ecf20Sopenharmony_ci * 7488c2ecf20Sopenharmony_ci * The linker incorrectly associates some symbols with the 7498c2ecf20Sopenharmony_ci * .data..percpu section so we also need to check the symbol 7508c2ecf20Sopenharmony_ci * name to make sure that we classify the symbol correctly. 7518c2ecf20Sopenharmony_ci * 7528c2ecf20Sopenharmony_ci * The GNU linker incorrectly associates: 7538c2ecf20Sopenharmony_ci * __init_begin 7548c2ecf20Sopenharmony_ci * __per_cpu_load 7558c2ecf20Sopenharmony_ci * 7568c2ecf20Sopenharmony_ci * The "gold" linker incorrectly associates: 7578c2ecf20Sopenharmony_ci * init_per_cpu__fixed_percpu_data 7588c2ecf20Sopenharmony_ci * init_per_cpu__gdt_page 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_cistatic int is_percpu_sym(ElfW(Sym) *sym, const char *symname) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci return (sym->st_shndx == per_cpu_shndx) && 7638c2ecf20Sopenharmony_ci strcmp(symname, "__init_begin") && 7648c2ecf20Sopenharmony_ci strcmp(symname, "__per_cpu_load") && 7658c2ecf20Sopenharmony_ci strncmp(symname, "init_per_cpu_", 13); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, 7708c2ecf20Sopenharmony_ci const char *symname) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci unsigned r_type = ELF64_R_TYPE(rel->r_info); 7738c2ecf20Sopenharmony_ci ElfW(Addr) offset = rel->r_offset; 7748c2ecf20Sopenharmony_ci int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (sym->st_shndx == SHN_UNDEF) 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* 7808c2ecf20Sopenharmony_ci * Adjust the offset if this reloc applies to the percpu section. 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_ci if (sec->shdr.sh_info == per_cpu_shndx) 7838c2ecf20Sopenharmony_ci offset += per_cpu_load_addr; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci switch (r_type) { 7868c2ecf20Sopenharmony_ci case R_X86_64_NONE: 7878c2ecf20Sopenharmony_ci /* NONE can be ignored. */ 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci case R_X86_64_PC32: 7918c2ecf20Sopenharmony_ci case R_X86_64_PLT32: 7928c2ecf20Sopenharmony_ci /* 7938c2ecf20Sopenharmony_ci * PC relative relocations don't need to be adjusted unless 7948c2ecf20Sopenharmony_ci * referencing a percpu symbol. 7958c2ecf20Sopenharmony_ci * 7968c2ecf20Sopenharmony_ci * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32. 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci if (is_percpu_sym(sym, symname)) 7998c2ecf20Sopenharmony_ci add_reloc(&relocs32neg, offset); 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci case R_X86_64_PC64: 8038c2ecf20Sopenharmony_ci /* 8048c2ecf20Sopenharmony_ci * Only used by jump labels 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_ci if (is_percpu_sym(sym, symname)) 8078c2ecf20Sopenharmony_ci die("Invalid R_X86_64_PC64 relocation against per-CPU symbol %s\n", 8088c2ecf20Sopenharmony_ci symname); 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci case R_X86_64_32: 8128c2ecf20Sopenharmony_ci case R_X86_64_32S: 8138c2ecf20Sopenharmony_ci case R_X86_64_64: 8148c2ecf20Sopenharmony_ci /* 8158c2ecf20Sopenharmony_ci * References to the percpu area don't need to be adjusted. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci if (is_percpu_sym(sym, symname)) 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (shn_abs) { 8218c2ecf20Sopenharmony_ci /* 8228c2ecf20Sopenharmony_ci * Whitelisted absolute symbols do not require 8238c2ecf20Sopenharmony_ci * relocation. 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_ci if (is_reloc(S_ABS, symname)) 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci die("Invalid absolute %s relocation: %s\n", 8298c2ecf20Sopenharmony_ci rel_type(r_type), symname); 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* 8348c2ecf20Sopenharmony_ci * Relocation offsets for 64 bit kernels are output 8358c2ecf20Sopenharmony_ci * as 32 bits and sign extended back to 64 bits when 8368c2ecf20Sopenharmony_ci * the relocations are processed. 8378c2ecf20Sopenharmony_ci * Make sure that the offset will fit. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci if ((int32_t)offset != (int64_t)offset) 8408c2ecf20Sopenharmony_ci die("Relocation offset doesn't fit in 32 bits\n"); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (r_type == R_X86_64_64) 8438c2ecf20Sopenharmony_ci add_reloc(&relocs64, offset); 8448c2ecf20Sopenharmony_ci else 8458c2ecf20Sopenharmony_ci add_reloc(&relocs32, offset); 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci default: 8498c2ecf20Sopenharmony_ci die("Unsupported relocation type: %s (%d)\n", 8508c2ecf20Sopenharmony_ci rel_type(r_type), r_type); 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci return 0; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci#else 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, 8608c2ecf20Sopenharmony_ci const char *symname) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci unsigned r_type = ELF32_R_TYPE(rel->r_info); 8638c2ecf20Sopenharmony_ci int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci switch (r_type) { 8668c2ecf20Sopenharmony_ci case R_386_NONE: 8678c2ecf20Sopenharmony_ci case R_386_PC32: 8688c2ecf20Sopenharmony_ci case R_386_PC16: 8698c2ecf20Sopenharmony_ci case R_386_PC8: 8708c2ecf20Sopenharmony_ci case R_386_PLT32: 8718c2ecf20Sopenharmony_ci /* 8728c2ecf20Sopenharmony_ci * NONE can be ignored and PC relative relocations don't need 8738c2ecf20Sopenharmony_ci * to be adjusted. Because sym must be defined, R_386_PLT32 can 8748c2ecf20Sopenharmony_ci * be treated the same way as R_386_PC32. 8758c2ecf20Sopenharmony_ci */ 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci case R_386_32: 8798c2ecf20Sopenharmony_ci if (shn_abs) { 8808c2ecf20Sopenharmony_ci /* 8818c2ecf20Sopenharmony_ci * Whitelisted absolute symbols do not require 8828c2ecf20Sopenharmony_ci * relocation. 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_ci if (is_reloc(S_ABS, symname)) 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci die("Invalid absolute %s relocation: %s\n", 8888c2ecf20Sopenharmony_ci rel_type(r_type), symname); 8898c2ecf20Sopenharmony_ci break; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci add_reloc(&relocs32, rel->r_offset); 8938c2ecf20Sopenharmony_ci break; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci default: 8968c2ecf20Sopenharmony_ci die("Unsupported relocation type: %s (%d)\n", 8978c2ecf20Sopenharmony_ci rel_type(r_type), r_type); 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return 0; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, 9058c2ecf20Sopenharmony_ci const char *symname) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci unsigned r_type = ELF32_R_TYPE(rel->r_info); 9088c2ecf20Sopenharmony_ci int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci switch (r_type) { 9118c2ecf20Sopenharmony_ci case R_386_NONE: 9128c2ecf20Sopenharmony_ci case R_386_PC32: 9138c2ecf20Sopenharmony_ci case R_386_PC16: 9148c2ecf20Sopenharmony_ci case R_386_PC8: 9158c2ecf20Sopenharmony_ci case R_386_PLT32: 9168c2ecf20Sopenharmony_ci /* 9178c2ecf20Sopenharmony_ci * NONE can be ignored and PC relative relocations don't need 9188c2ecf20Sopenharmony_ci * to be adjusted. Because sym must be defined, R_386_PLT32 can 9198c2ecf20Sopenharmony_ci * be treated the same way as R_386_PC32. 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_ci break; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci case R_386_16: 9248c2ecf20Sopenharmony_ci if (shn_abs) { 9258c2ecf20Sopenharmony_ci /* 9268c2ecf20Sopenharmony_ci * Whitelisted absolute symbols do not require 9278c2ecf20Sopenharmony_ci * relocation. 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_ci if (is_reloc(S_ABS, symname)) 9308c2ecf20Sopenharmony_ci break; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (is_reloc(S_SEG, symname)) { 9338c2ecf20Sopenharmony_ci add_reloc(&relocs16, rel->r_offset); 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci } else { 9378c2ecf20Sopenharmony_ci if (!is_reloc(S_LIN, symname)) 9388c2ecf20Sopenharmony_ci break; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci die("Invalid %s %s relocation: %s\n", 9418c2ecf20Sopenharmony_ci shn_abs ? "absolute" : "relative", 9428c2ecf20Sopenharmony_ci rel_type(r_type), symname); 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci case R_386_32: 9468c2ecf20Sopenharmony_ci if (shn_abs) { 9478c2ecf20Sopenharmony_ci /* 9488c2ecf20Sopenharmony_ci * Whitelisted absolute symbols do not require 9498c2ecf20Sopenharmony_ci * relocation. 9508c2ecf20Sopenharmony_ci */ 9518c2ecf20Sopenharmony_ci if (is_reloc(S_ABS, symname)) 9528c2ecf20Sopenharmony_ci break; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (is_reloc(S_REL, symname)) { 9558c2ecf20Sopenharmony_ci add_reloc(&relocs32, rel->r_offset); 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci } else { 9598c2ecf20Sopenharmony_ci if (is_reloc(S_LIN, symname)) 9608c2ecf20Sopenharmony_ci add_reloc(&relocs32, rel->r_offset); 9618c2ecf20Sopenharmony_ci break; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci die("Invalid %s %s relocation: %s\n", 9648c2ecf20Sopenharmony_ci shn_abs ? "absolute" : "relative", 9658c2ecf20Sopenharmony_ci rel_type(r_type), symname); 9668c2ecf20Sopenharmony_ci break; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci default: 9698c2ecf20Sopenharmony_ci die("Unsupported relocation type: %s (%d)\n", 9708c2ecf20Sopenharmony_ci rel_type(r_type), r_type); 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci return 0; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci#endif 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic int cmp_relocs(const void *va, const void *vb) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci const uint32_t *a, *b; 9828c2ecf20Sopenharmony_ci a = va; b = vb; 9838c2ecf20Sopenharmony_ci return (*a == *b)? 0 : (*a > *b)? 1 : -1; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic void sort_relocs(struct relocs *r) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic int write32(uint32_t v, FILE *f) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci unsigned char buf[4]; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci put_unaligned_le32(v, buf); 9968c2ecf20Sopenharmony_ci return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic int write32_as_text(uint32_t v, FILE *f) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic void emit_relocs(int as_text, int use_real_mode) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci int i; 10078c2ecf20Sopenharmony_ci int (*write_reloc)(uint32_t, FILE *) = write32; 10088c2ecf20Sopenharmony_ci int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, 10098c2ecf20Sopenharmony_ci const char *symname); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci#if ELF_BITS == 64 10128c2ecf20Sopenharmony_ci if (!use_real_mode) 10138c2ecf20Sopenharmony_ci do_reloc = do_reloc64; 10148c2ecf20Sopenharmony_ci else 10158c2ecf20Sopenharmony_ci die("--realmode not valid for a 64-bit ELF file"); 10168c2ecf20Sopenharmony_ci#else 10178c2ecf20Sopenharmony_ci if (!use_real_mode) 10188c2ecf20Sopenharmony_ci do_reloc = do_reloc32; 10198c2ecf20Sopenharmony_ci else 10208c2ecf20Sopenharmony_ci do_reloc = do_reloc_real; 10218c2ecf20Sopenharmony_ci#endif 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci /* Collect up the relocations */ 10248c2ecf20Sopenharmony_ci walk_relocs(do_reloc); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (relocs16.count && !use_real_mode) 10278c2ecf20Sopenharmony_ci die("Segment relocations found but --realmode not specified\n"); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci /* Order the relocations for more efficient processing */ 10308c2ecf20Sopenharmony_ci sort_relocs(&relocs32); 10318c2ecf20Sopenharmony_ci#if ELF_BITS == 64 10328c2ecf20Sopenharmony_ci sort_relocs(&relocs32neg); 10338c2ecf20Sopenharmony_ci sort_relocs(&relocs64); 10348c2ecf20Sopenharmony_ci#else 10358c2ecf20Sopenharmony_ci sort_relocs(&relocs16); 10368c2ecf20Sopenharmony_ci#endif 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Print the relocations */ 10398c2ecf20Sopenharmony_ci if (as_text) { 10408c2ecf20Sopenharmony_ci /* Print the relocations in a form suitable that 10418c2ecf20Sopenharmony_ci * gas will like. 10428c2ecf20Sopenharmony_ci */ 10438c2ecf20Sopenharmony_ci printf(".section \".data.reloc\",\"a\"\n"); 10448c2ecf20Sopenharmony_ci printf(".balign 4\n"); 10458c2ecf20Sopenharmony_ci write_reloc = write32_as_text; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (use_real_mode) { 10498c2ecf20Sopenharmony_ci write_reloc(relocs16.count, stdout); 10508c2ecf20Sopenharmony_ci for (i = 0; i < relocs16.count; i++) 10518c2ecf20Sopenharmony_ci write_reloc(relocs16.offset[i], stdout); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci write_reloc(relocs32.count, stdout); 10548c2ecf20Sopenharmony_ci for (i = 0; i < relocs32.count; i++) 10558c2ecf20Sopenharmony_ci write_reloc(relocs32.offset[i], stdout); 10568c2ecf20Sopenharmony_ci } else { 10578c2ecf20Sopenharmony_ci#if ELF_BITS == 64 10588c2ecf20Sopenharmony_ci /* Print a stop */ 10598c2ecf20Sopenharmony_ci write_reloc(0, stdout); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci /* Now print each relocation */ 10628c2ecf20Sopenharmony_ci for (i = 0; i < relocs64.count; i++) 10638c2ecf20Sopenharmony_ci write_reloc(relocs64.offset[i], stdout); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* Print a stop */ 10668c2ecf20Sopenharmony_ci write_reloc(0, stdout); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* Now print each inverse 32-bit relocation */ 10698c2ecf20Sopenharmony_ci for (i = 0; i < relocs32neg.count; i++) 10708c2ecf20Sopenharmony_ci write_reloc(relocs32neg.offset[i], stdout); 10718c2ecf20Sopenharmony_ci#endif 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Print a stop */ 10748c2ecf20Sopenharmony_ci write_reloc(0, stdout); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci /* Now print each relocation */ 10778c2ecf20Sopenharmony_ci for (i = 0; i < relocs32.count; i++) 10788c2ecf20Sopenharmony_ci write_reloc(relocs32.offset[i], stdout); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* 10838c2ecf20Sopenharmony_ci * As an aid to debugging problems with different linkers 10848c2ecf20Sopenharmony_ci * print summary information about the relocs. 10858c2ecf20Sopenharmony_ci * Since different linkers tend to emit the sections in 10868c2ecf20Sopenharmony_ci * different orders we use the section names in the output. 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_cistatic int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, 10898c2ecf20Sopenharmony_ci const char *symname) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci printf("%s\t%s\t%s\t%s\n", 10928c2ecf20Sopenharmony_ci sec_name(sec->shdr.sh_info), 10938c2ecf20Sopenharmony_ci rel_type(ELF_R_TYPE(rel->r_info)), 10948c2ecf20Sopenharmony_ci symname, 10958c2ecf20Sopenharmony_ci sec_name(sym->st_shndx)); 10968c2ecf20Sopenharmony_ci return 0; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic void print_reloc_info(void) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci printf("reloc section\treloc type\tsymbol\tsymbol section\n"); 11028c2ecf20Sopenharmony_ci walk_relocs(do_reloc_info); 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci#if ELF_BITS == 64 11068c2ecf20Sopenharmony_ci# define process process_64 11078c2ecf20Sopenharmony_ci#else 11088c2ecf20Sopenharmony_ci# define process process_32 11098c2ecf20Sopenharmony_ci#endif 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_civoid process(FILE *fp, int use_real_mode, int as_text, 11128c2ecf20Sopenharmony_ci int show_absolute_syms, int show_absolute_relocs, 11138c2ecf20Sopenharmony_ci int show_reloc_info) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci regex_init(use_real_mode); 11168c2ecf20Sopenharmony_ci read_ehdr(fp); 11178c2ecf20Sopenharmony_ci read_shdrs(fp); 11188c2ecf20Sopenharmony_ci read_strtabs(fp); 11198c2ecf20Sopenharmony_ci read_symtabs(fp); 11208c2ecf20Sopenharmony_ci read_relocs(fp); 11218c2ecf20Sopenharmony_ci if (ELF_BITS == 64) 11228c2ecf20Sopenharmony_ci percpu_init(); 11238c2ecf20Sopenharmony_ci if (show_absolute_syms) { 11248c2ecf20Sopenharmony_ci print_absolute_symbols(); 11258c2ecf20Sopenharmony_ci return; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci if (show_absolute_relocs) { 11288c2ecf20Sopenharmony_ci print_absolute_relocs(); 11298c2ecf20Sopenharmony_ci return; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci if (show_reloc_info) { 11328c2ecf20Sopenharmony_ci print_reloc_info(); 11338c2ecf20Sopenharmony_ci return; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci emit_relocs(as_text, use_real_mode); 11368c2ecf20Sopenharmony_ci} 1137