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_ci 168c2ecf20Sopenharmony_cistruct relocs { 178c2ecf20Sopenharmony_ci uint32_t *offset; 188c2ecf20Sopenharmony_ci unsigned long count; 198c2ecf20Sopenharmony_ci unsigned long size; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic struct relocs relocs; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct section { 258c2ecf20Sopenharmony_ci Elf_Shdr shdr; 268c2ecf20Sopenharmony_ci struct section *link; 278c2ecf20Sopenharmony_ci Elf_Sym *symtab; 288c2ecf20Sopenharmony_ci Elf_Rel *reltab; 298c2ecf20Sopenharmony_ci char *strtab; 308c2ecf20Sopenharmony_ci long shdr_offset; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_cistatic struct section *secs; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const char * const regex_sym_kernel = { 358c2ecf20Sopenharmony_ci/* Symbols matching these regex's should never be relocated */ 368c2ecf20Sopenharmony_ci "^(__crc_)", 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic regex_t sym_regex_c; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int regex_skip_reloc(const char *sym_name) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci return !regexec(&sym_regex_c, sym_name, 0, NULL, 0); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void regex_init(void) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci char errbuf[128]; 498c2ecf20Sopenharmony_ci int err; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci err = regcomp(&sym_regex_c, regex_sym_kernel, 528c2ecf20Sopenharmony_ci REG_EXTENDED|REG_NOSUB); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (err) { 558c2ecf20Sopenharmony_ci regerror(err, &sym_regex_c, errbuf, sizeof(errbuf)); 568c2ecf20Sopenharmony_ci die("%s", errbuf); 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const char *rel_type(unsigned type) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci static const char * const type_name[] = { 638c2ecf20Sopenharmony_ci#define REL_TYPE(X)[X] = #X 648c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_NONE), 658c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_32), 668c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_64), 678c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_MARK_LA), 688c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_MARK_PCREL), 698c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_PUSH_PCREL), 708c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_PUSH_ABSOLUTE), 718c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_PUSH_DUP), 728c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_PUSH_PLT_PCREL), 738c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_SUB), 748c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_SL), 758c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_SR), 768c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_ADD), 778c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_AND), 788c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_IF_ELSE), 798c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_S_10_5), 808c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_U_10_12), 818c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_S_10_12), 828c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_S_10_16), 838c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_S_10_16_S2), 848c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_S_5_20), 858c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_S_0_5_10_16_S2), 868c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_S_0_10_10_16_S2), 878c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SOP_POP_32_U), 888c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_ADD32), 898c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_ADD64), 908c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SUB32), 918c2ecf20Sopenharmony_ci REL_TYPE(R_LARCH_SUB64), 928c2ecf20Sopenharmony_ci#undef REL_TYPE 938c2ecf20Sopenharmony_ci }; 948c2ecf20Sopenharmony_ci const char *name = "unknown type rel type name"; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (type < ARRAY_SIZE(type_name) && type_name[type]) 978c2ecf20Sopenharmony_ci name = type_name[type]; 988c2ecf20Sopenharmony_ci return name; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const char *sec_name(unsigned shndx) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci const char *sec_strtab; 1048c2ecf20Sopenharmony_ci const char *name; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci sec_strtab = secs[ehdr.e_shstrndx].strtab; 1078c2ecf20Sopenharmony_ci if (shndx < ehdr.e_shnum) 1088c2ecf20Sopenharmony_ci name = sec_strtab + secs[shndx].shdr.sh_name; 1098c2ecf20Sopenharmony_ci else if (shndx == SHN_ABS) 1108c2ecf20Sopenharmony_ci name = "ABSOLUTE"; 1118c2ecf20Sopenharmony_ci else if (shndx == SHN_COMMON) 1128c2ecf20Sopenharmony_ci name = "COMMON"; 1138c2ecf20Sopenharmony_ci else 1148c2ecf20Sopenharmony_ci name = "<noname>"; 1158c2ecf20Sopenharmony_ci return name; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic struct section *sec_lookup(const char *secname) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci int i; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci for (i = 0; i < ehdr.e_shnum; i++) 1238c2ecf20Sopenharmony_ci if (strcmp(secname, sec_name(i)) == 0) 1248c2ecf20Sopenharmony_ci return &secs[i]; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return NULL; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic const char *sym_name(const char *sym_strtab, Elf_Sym *sym) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci const char *name; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (sym->st_name) 1348c2ecf20Sopenharmony_ci name = sym_strtab + sym->st_name; 1358c2ecf20Sopenharmony_ci else 1368c2ecf20Sopenharmony_ci name = sec_name(sym->st_shndx); 1378c2ecf20Sopenharmony_ci return name; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void read_ehdr(FILE *fp) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) 1438c2ecf20Sopenharmony_ci die("Cannot read ELF header: %s\n", strerror(errno)); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) 1468c2ecf20Sopenharmony_ci die("No ELF magic\n"); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) 1498c2ecf20Sopenharmony_ci die("Not a %d bit executable\n", ELF_BITS); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) 1528c2ecf20Sopenharmony_ci die("Unsupported ELF Endianness\n"); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) 1558c2ecf20Sopenharmony_ci die("Unknown ELF version\n"); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) 1588c2ecf20Sopenharmony_ci die("Unsupported ELF header type\n"); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (ehdr.e_machine != ELF_MACHINE) 1618c2ecf20Sopenharmony_ci die("Not for %s\n", ELF_MACHINE_NAME); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (ehdr.e_version != EV_CURRENT) 1648c2ecf20Sopenharmony_ci die("Unknown ELF version\n"); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) 1678c2ecf20Sopenharmony_ci die("Bad Elf header size\n"); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (ehdr.e_phentsize != sizeof(Elf_Phdr)) 1708c2ecf20Sopenharmony_ci die("Bad program header entry\n"); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (ehdr.e_shentsize != sizeof(Elf_Shdr)) 1738c2ecf20Sopenharmony_ci die("Bad section header entry\n"); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (ehdr.e_shstrndx >= ehdr.e_shnum) 1768c2ecf20Sopenharmony_ci die("String table index out of bounds\n"); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void read_shdrs(FILE *fp) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int i; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci secs = calloc(ehdr.e_shnum, sizeof(struct section)); 1848c2ecf20Sopenharmony_ci if (!secs) 1858c2ecf20Sopenharmony_ci die("Unable to allocate %d section headers\n", ehdr.e_shnum); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) 1888c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", ehdr.e_shoff, strerror(errno)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci for (i = 0; i < ehdr.e_shnum; i++) { 1918c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci sec->shdr_offset = ftell(fp); 1948c2ecf20Sopenharmony_ci if (fread(&sec->shdr, sizeof(Elf_Shdr), 1, fp) != 1) 1958c2ecf20Sopenharmony_ci die("Cannot read ELF section headers %d/%d: %s\n", 1968c2ecf20Sopenharmony_ci i, ehdr.e_shnum, strerror(errno)); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (sec->shdr.sh_link < ehdr.e_shnum) 1998c2ecf20Sopenharmony_ci sec->link = &secs[sec->shdr.sh_link]; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void read_strtabs(FILE *fp) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int i; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci for (i = 0; i < ehdr.e_shnum; i++) { 2088c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_STRTAB) 2118c2ecf20Sopenharmony_ci continue; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci sec->strtab = malloc(sec->shdr.sh_size); 2148c2ecf20Sopenharmony_ci if (!sec->strtab) 2158c2ecf20Sopenharmony_ci die("malloc of %d bytes for strtab failed\n", 2168c2ecf20Sopenharmony_ci sec->shdr.sh_size); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) 2198c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 2208c2ecf20Sopenharmony_ci sec->shdr.sh_offset, strerror(errno)); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) != 2238c2ecf20Sopenharmony_ci sec->shdr.sh_size) 2248c2ecf20Sopenharmony_ci die("Cannot read symbol table: %s\n", strerror(errno)); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void read_symtabs(FILE *fp) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci int i; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (i = 0; i < ehdr.e_shnum; i++) { 2338c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 2348c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_SYMTAB) 2358c2ecf20Sopenharmony_ci continue; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci sec->symtab = malloc(sec->shdr.sh_size); 2388c2ecf20Sopenharmony_ci if (!sec->symtab) 2398c2ecf20Sopenharmony_ci die("malloc of %d bytes for symtab failed\n", 2408c2ecf20Sopenharmony_ci sec->shdr.sh_size); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) 2438c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 2448c2ecf20Sopenharmony_ci sec->shdr.sh_offset, strerror(errno)); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) != 2478c2ecf20Sopenharmony_ci sec->shdr.sh_size) 2488c2ecf20Sopenharmony_ci die("Cannot read symbol table: %s\n", strerror(errno)); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic void read_relocs(FILE *fp) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci static unsigned long base = 0; 2558c2ecf20Sopenharmony_ci int i, j; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (!base) { 2588c2ecf20Sopenharmony_ci struct section *sec = sec_lookup(".text"); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (!sec) 2618c2ecf20Sopenharmony_ci die("Could not find .text section\n"); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci base = sec->shdr.sh_addr; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci for (i = 0; i < ehdr.e_shnum; i++) { 2678c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_REL_TYPE) 2708c2ecf20Sopenharmony_ci continue; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci sec->reltab = malloc(sec->shdr.sh_size); 2738c2ecf20Sopenharmony_ci if (!sec->reltab) 2748c2ecf20Sopenharmony_ci die("malloc of %d bytes for relocs failed\n", 2758c2ecf20Sopenharmony_ci sec->shdr.sh_size); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) 2788c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 2798c2ecf20Sopenharmony_ci sec->shdr.sh_offset, strerror(errno)); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != 2828c2ecf20Sopenharmony_ci sec->shdr.sh_size) 2838c2ecf20Sopenharmony_ci die("Cannot read symbol table: %s\n", strerror(errno)); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 2868c2ecf20Sopenharmony_ci Elf_Rel *rel = &sec->reltab[j]; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Set offset into kernel image */ 2898c2ecf20Sopenharmony_ci rel->r_offset -= base; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void remove_relocs(FILE *fp) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci int i; 2978c2ecf20Sopenharmony_ci Elf_Shdr shdr; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci for (i = 0; i < ehdr.e_shnum; i++) { 3008c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_REL_TYPE) 3038c2ecf20Sopenharmony_ci continue; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0) 3068c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 3078c2ecf20Sopenharmony_ci sec->shdr_offset, strerror(errno)); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (fread(&shdr, sizeof(shdr), 1, fp) != 1) 3108c2ecf20Sopenharmony_ci die("Cannot read ELF section headers %d/%d: %s\n", 3118c2ecf20Sopenharmony_ci i, ehdr.e_shnum, strerror(errno)); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Set relocation section size to 0, effectively removing it. 3148c2ecf20Sopenharmony_ci * This is necessary due to lack of support for relocations 3158c2ecf20Sopenharmony_ci * in objcopy when creating 32bit elf from 64bit elf. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci shdr.sh_size = 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0) 3208c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 3218c2ecf20Sopenharmony_ci sec->shdr_offset, strerror(errno)); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (fwrite(&shdr, sizeof(shdr), 1, fp) != 1) 3248c2ecf20Sopenharmony_ci die("Cannot write ELF section headers %d/%d: %s\n", 3258c2ecf20Sopenharmony_ci i, ehdr.e_shnum, strerror(errno)); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void add_reloc(struct relocs *r, uint32_t offset, unsigned type) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci /* Relocation representation in binary table: 3328c2ecf20Sopenharmony_ci * |76543210|76543210|76543210|76543210| 3338c2ecf20Sopenharmony_ci * | Type | offset from _text >> 2 | 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci offset >>= 2; 3368c2ecf20Sopenharmony_ci if (offset > 0x00FFFFFF) 3378c2ecf20Sopenharmony_ci die("Kernel image exceeds maximum size for relocation!\n"); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci offset = (offset & 0x00FFFFFF) | ((type & 0xFF) << 24); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (r->count == r->size) { 3428c2ecf20Sopenharmony_ci unsigned long newsize = r->size + 50000; 3438c2ecf20Sopenharmony_ci void *mem = realloc(r->offset, newsize * sizeof(r->offset[0])); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (!mem) 3468c2ecf20Sopenharmony_ci die("realloc failed\n"); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci r->offset = mem; 3498c2ecf20Sopenharmony_ci r->size = newsize; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci r->offset[r->count++] = offset; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, 3558c2ecf20Sopenharmony_ci Elf_Sym *sym, const char *symname)) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* Walk through the relocations */ 3608c2ecf20Sopenharmony_ci for (i = 0; i < ehdr.e_shnum; i++) { 3618c2ecf20Sopenharmony_ci char *sym_strtab; 3628c2ecf20Sopenharmony_ci Elf_Sym *sh_symtab; 3638c2ecf20Sopenharmony_ci struct section *sec_applies, *sec_symtab; 3648c2ecf20Sopenharmony_ci int j; 3658c2ecf20Sopenharmony_ci struct section *sec = &secs[i]; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (sec->shdr.sh_type != SHT_REL_TYPE) 3688c2ecf20Sopenharmony_ci continue; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci sec_symtab = sec->link; 3718c2ecf20Sopenharmony_ci sec_applies = &secs[sec->shdr.sh_info]; 3728c2ecf20Sopenharmony_ci if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) 3738c2ecf20Sopenharmony_ci continue; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci sh_symtab = sec_symtab->symtab; 3768c2ecf20Sopenharmony_ci sym_strtab = sec_symtab->link->strtab; 3778c2ecf20Sopenharmony_ci for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { 3788c2ecf20Sopenharmony_ci Elf_Rel *rel = &sec->reltab[j]; 3798c2ecf20Sopenharmony_ci Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; 3808c2ecf20Sopenharmony_ci const char *symname = sym_name(sym_strtab, sym); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci process(sec, rel, sym, symname); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, 3888c2ecf20Sopenharmony_ci const char *symname) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci unsigned r_type = ELF_R_TYPE(rel->r_info); 3918c2ecf20Sopenharmony_ci unsigned bind = ELF_ST_BIND(sym->st_info); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if ((bind == STB_WEAK) && (sym->st_value == 0)) { 3948c2ecf20Sopenharmony_ci /* Don't relocate weak symbols without a target */ 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (regex_skip_reloc(symname)) 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci switch (r_type) { 4028c2ecf20Sopenharmony_ci case R_LARCH_NONE: 4038c2ecf20Sopenharmony_ci case R_LARCH_MARK_PCREL: 4048c2ecf20Sopenharmony_ci case R_LARCH_SOP_PUSH_PCREL: 4058c2ecf20Sopenharmony_ci case R_LARCH_SOP_PUSH_ABSOLUTE: 4068c2ecf20Sopenharmony_ci case R_LARCH_SOP_PUSH_DUP: 4078c2ecf20Sopenharmony_ci case R_LARCH_SOP_PUSH_PLT_PCREL: 4088c2ecf20Sopenharmony_ci case R_LARCH_SOP_SUB: 4098c2ecf20Sopenharmony_ci case R_LARCH_SOP_SL: 4108c2ecf20Sopenharmony_ci case R_LARCH_SOP_SR: 4118c2ecf20Sopenharmony_ci case R_LARCH_SOP_ADD: 4128c2ecf20Sopenharmony_ci case R_LARCH_SOP_AND: 4138c2ecf20Sopenharmony_ci case R_LARCH_SOP_IF_ELSE: 4148c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_S_10_5: 4158c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_U_10_12: 4168c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_S_10_12: 4178c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_S_10_16: 4188c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_S_10_16_S2: 4198c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_S_5_20: 4208c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: 4218c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: 4228c2ecf20Sopenharmony_ci case R_LARCH_SOP_POP_32_U: 4238c2ecf20Sopenharmony_ci case R_LARCH_ADD32: 4248c2ecf20Sopenharmony_ci case R_LARCH_ADD64: 4258c2ecf20Sopenharmony_ci case R_LARCH_SUB32: 4268c2ecf20Sopenharmony_ci case R_LARCH_SUB64: 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci case R_LARCH_32: 4308c2ecf20Sopenharmony_ci case R_LARCH_64: 4318c2ecf20Sopenharmony_ci case R_LARCH_MARK_LA: 4328c2ecf20Sopenharmony_ci add_reloc(&relocs, rel->r_offset, r_type); 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci default: 4368c2ecf20Sopenharmony_ci die("Unsupported relocation type: %s (%d)\n", rel_type(r_type), r_type); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int write_reloc_as_bin(uint32_t v, FILE *f) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci return fwrite(&v, 4, 1, f); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int write_reloc_as_text(uint32_t v, FILE *f) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci int res; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci res = fprintf(f, "\t.long 0x%08"PRIx32"\n", v); 4538c2ecf20Sopenharmony_ci if (res < 0) 4548c2ecf20Sopenharmony_ci return res; 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci return sizeof(uint32_t); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void emit_relocs(int as_text, int as_bin, FILE *outf) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci int i; 4628c2ecf20Sopenharmony_ci int (*write_reloc)(uint32_t, FILE *) = write_reloc_as_bin; 4638c2ecf20Sopenharmony_ci int size = 0; 4648c2ecf20Sopenharmony_ci int size_reserved; 4658c2ecf20Sopenharmony_ci struct section *sec_reloc; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci sec_reloc = sec_lookup(".data.reloc"); 4688c2ecf20Sopenharmony_ci if (!sec_reloc) 4698c2ecf20Sopenharmony_ci die("Could not find relocation section\n"); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci size_reserved = sec_reloc->shdr.sh_size; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* Collect up the relocations */ 4748c2ecf20Sopenharmony_ci walk_relocs(do_reloc); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Print the relocations */ 4778c2ecf20Sopenharmony_ci if (as_text) { 4788c2ecf20Sopenharmony_ci /* Print the relocations in a form suitable that 4798c2ecf20Sopenharmony_ci * gas will like. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci printf(".section \".data.reloc\",\"a\"\n"); 4828c2ecf20Sopenharmony_ci printf(".balign 4\n"); 4838c2ecf20Sopenharmony_ci /* Output text to stdout */ 4848c2ecf20Sopenharmony_ci write_reloc = write_reloc_as_text; 4858c2ecf20Sopenharmony_ci outf = stdout; 4868c2ecf20Sopenharmony_ci } else if (as_bin) { 4878c2ecf20Sopenharmony_ci /* Output raw binary to stdout */ 4888c2ecf20Sopenharmony_ci outf = stdout; 4898c2ecf20Sopenharmony_ci } else { 4908c2ecf20Sopenharmony_ci /* Seek to offset of the relocation section. 4918c2ecf20Sopenharmony_ci * Each relocation is then written into the 4928c2ecf20Sopenharmony_ci * vmlinux kernel image. 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci if (fseek(outf, sec_reloc->shdr.sh_offset, SEEK_SET) < 0) { 4958c2ecf20Sopenharmony_ci die("Seek to %d failed: %s\n", 4968c2ecf20Sopenharmony_ci sec_reloc->shdr.sh_offset, strerror(errno)); 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci for (i = 0; i < relocs.count; i++) 5018c2ecf20Sopenharmony_ci size += write_reloc(relocs.offset[i], outf); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* Print a stop, but only if we've actually written some relocs */ 5048c2ecf20Sopenharmony_ci if (size) 5058c2ecf20Sopenharmony_ci size += write_reloc(0, outf); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (size > size_reserved) 5088c2ecf20Sopenharmony_ci /* Die, but suggest a value for CONFIG_RELOCATION_TABLE_SIZE 5098c2ecf20Sopenharmony_ci * which will fix this problem and allow a bit of headroom 5108c2ecf20Sopenharmony_ci * if more kernel features are enabled 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci die("Relocations overflow available space!\n" \ 5138c2ecf20Sopenharmony_ci "Please adjust CONFIG_RELOCATION_TABLE_SIZE " \ 5148c2ecf20Sopenharmony_ci "to at least 0x%08x\n", (size + 0x1000) & ~0xFFF); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* 5188c2ecf20Sopenharmony_ci * As an aid to debugging problems with different linkers 5198c2ecf20Sopenharmony_ci * print summary information about the relocs. 5208c2ecf20Sopenharmony_ci * Since different linkers tend to emit the sections in 5218c2ecf20Sopenharmony_ci * different orders we use the section names in the output. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_cistatic int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, 5248c2ecf20Sopenharmony_ci const char *symname) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci printf("%-16s 0x%08x %-35s %-40s %-16s\n", 5278c2ecf20Sopenharmony_ci sec_name(sec->shdr.sh_info), 5288c2ecf20Sopenharmony_ci (unsigned int)rel->r_offset, 5298c2ecf20Sopenharmony_ci rel_type(ELF_R_TYPE(rel->r_info)), 5308c2ecf20Sopenharmony_ci symname, 5318c2ecf20Sopenharmony_ci sec_name(sym->st_shndx)); 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic void print_reloc_info(void) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci printf("%-16s %-10s %-35s %-40s %-16s\n", 5388c2ecf20Sopenharmony_ci "reloc section", 5398c2ecf20Sopenharmony_ci "offset", 5408c2ecf20Sopenharmony_ci "reloc type", 5418c2ecf20Sopenharmony_ci "symbol", 5428c2ecf20Sopenharmony_ci "symbol section"); 5438c2ecf20Sopenharmony_ci walk_relocs(do_reloc_info); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci#if ELF_BITS == 64 5478c2ecf20Sopenharmony_ci# define process process_64 5488c2ecf20Sopenharmony_ci#else 5498c2ecf20Sopenharmony_ci# define process process_32 5508c2ecf20Sopenharmony_ci#endif 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_civoid process(FILE *fp, int as_text, int as_bin, 5538c2ecf20Sopenharmony_ci int show_reloc_info, int keep_relocs) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci regex_init(); 5568c2ecf20Sopenharmony_ci read_ehdr(fp); 5578c2ecf20Sopenharmony_ci read_shdrs(fp); 5588c2ecf20Sopenharmony_ci read_strtabs(fp); 5598c2ecf20Sopenharmony_ci read_symtabs(fp); 5608c2ecf20Sopenharmony_ci read_relocs(fp); 5618c2ecf20Sopenharmony_ci if (show_reloc_info) { 5628c2ecf20Sopenharmony_ci print_reloc_info(); 5638c2ecf20Sopenharmony_ci return; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci emit_relocs(as_text, as_bin, fp); 5668c2ecf20Sopenharmony_ci if (!keep_relocs) 5678c2ecf20Sopenharmony_ci remove_relocs(fp); 5688c2ecf20Sopenharmony_ci} 569