#include "vxBoot/loader.h" #include "vxBoot/fs/smemfs.h" #include "vxBoot/terminal.h" #include #include struct { char const * restrict const name; uint16_t id; } const table[] = { {"R_SH_NONE", 0}, {"R_SH_DIR32", 1}, {"R_SH_REL32", 2}, {"R_SH_DIR8WPN", 3}, {"R_SH_IND12W", 4}, {"R_SH_DIR8WPL", 5}, {"R_SH_DIR8WPZ", 6}, {"R_SH_DIR8BP", 7}, {"R_SH_DIR8W", 8}, {"R_SH_DIR8L", 9}, {"R_SH_SWITCH16", 25}, {"R_SH_SWITCH32", 26}, {"R_SH_USES", 27}, {"R_SH_COUNT", 28}, {"R_SH_ALIGN", 29}, {"R_SH_CODE", 30}, {"R_SH_DATA", 31}, {"R_SH_LABEL", 32}, {"R_SH_SWITCH8", 33}, {"R_SH_GNU_VTINHERIT", 4}, {"R_SH_GNU_VTENTRY", 5}, {"R_SH_TLS_GD_32", 144}, {"R_SH_TLS_LD_32", 145}, {"R_SH_TLS_LDO_32", 146}, {"R_SH_TLS_IE_32", 147}, {"R_SH_TLS_LE_32", 148}, {"R_SH_TLS_DTPMOD32", 49}, {"R_SH_TLS_DTPOFF32", 50}, {"R_SH_TLS_TPOFF32", 51}, {"R_SH_GOT32", 160}, {"R_SH_PLT32", 161}, {"R_SH_COPY", 162}, {"R_SH_GLOB_DAT", 163}, {"R_SH_JMP_SLOT", 164}, {"R_SH_RELATIVE", 165}, {"R_SH_GOTOFF", 166}, {"R_SH_GOTPC", 167}, {"R_SH_NUM", 256}, {NULL, 0} }; /* loader_reloc_symbols() : relocalize symbols */ static int loader_reloc_section( Elf32_Rela *rela, int nb_rela, char const * const name, struct kernel * const kernel ) { uintptr_t voff; uintptr_t val; uintptr_t loc; int type; /* logs */ terminal_log( LOG_INFO, " > '%s' (%d)...", name, nb_rela ); /* precalculate relocalisation operation */ voff = (uintptr_t)kernel->hardware.ram.physical.kernel_addr; voff |= (uintptr_t)0x80000000; /* try to relocalise symbols */ for (int i = 0; i < nb_rela; ++i) { type = -1; for (int j = 0; table[j].name != NULL; ++j) { if (table[j].id != ELF32_R_TYPE(rela[i].r_info)) continue; if (ELF32_R_TYPE(rela[i].r_info) == R_SH_NUM) return (0); type = j; break; } if (type < 0) { terminal_log( LOG_ALERT, "\nunable to relocalize symbols %d\n", i ); return (-1); } loc = rela[i].r_offset; loc += (uintptr_t)kernel->hardware.ram.physical.kernel_addr; loc |= (uintptr_t)0xa0000000; /* IMPORTANT NOTE: We cannot use the real symbols value for patching the binary because some symbols are completely broken and refer to something else. Specially when a global use another global (for example: const char * const text = "vive les g@m3rz"). But, after some RE, each time a global symbol is used, its virtual address is set. So, for now, we just need to add the relocation offset to the content of the location. */ //val = kernel->elf.sym.tab[ELF32_R_SYM(rela[i].r_info)].st_value; val = (((uint8_t*)loc)[0] << 24); val |= (((uint8_t*)loc)[1] << 16); val |= (((uint8_t*)loc)[2] << 8); val |= (((uint8_t*)loc)[3] << 0); switch (table[type].id) { case R_SH_GOT32: case R_SH_PLT32: case R_SH_GOTPC: case R_SH_GOTOFF: break; case R_SH_DIR32: terminal_log( LOG_DEBUG, " %08x %-8s %08x %d %d", rela[i].r_offset, table[type].name, val, rela[i].r_addend, type ); val += voff; ((uint8_t *)loc)[0] = (val & 0xff000000) >> 24; ((uint8_t *)loc)[1] = (val & 0x00ff0000) >> 16; ((uint8_t *)loc)[2] = (val & 0x0000ff00) >> 8; ((uint8_t *)loc)[3] = (val & 0x000000ff) >> 0; break; default: terminal_log( LOG_ALERT, " [%d] type %s not supported yet o(x_x)o\n", i, table[type].name ); return (-1); } } terminal_log(LOG_INFO, "OK\n"); return (0); } /* loader_rela_patch() : Try to patch the GOT/PLT section */ int loader_rela_patch(struct kernel * const kernel) { Elf32_Rela *rela; int error; rela = NULL; for (int i = 0; i < kernel->elf.hdr.e_shnum; ++i) { if (kernel->elf.shdr[i].sh_type != SHT_RELA) continue; rela = realloc(rela, kernel->elf.shdr[i].sh_size); smemfs_pread( kernel->inode, rela, kernel->elf.shdr[i].sh_size, kernel->elf.shdr[i].sh_offset ); error = loader_reloc_section( rela, kernel->elf.shdr[i].sh_size / sizeof(Elf32_Rela), &kernel->elf.shstrtab[kernel->elf.shdr[i].sh_name], kernel ); if (error != 0) return (error); } return (0); }