166 lines
3.7 KiB
C
166 lines
3.7 KiB
C
#include "vxBoot/loader.h"
|
|
#include "vxBoot/fs/smemfs.h"
|
|
#include "vxBoot/terminal.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
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,
|
|
" section '%s' with %d entries\n",
|
|
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_write("unable 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 = *(uintptr_t*)loc;
|
|
|
|
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\n",
|
|
// rela[i].r_offset,
|
|
// table[type].name,
|
|
// val
|
|
//);
|
|
*(uintptr_t *)loc = voff + val;
|
|
break;
|
|
default:
|
|
terminal_log(
|
|
LOG_ALERT,
|
|
" [%d] type %s not supported yet o(x_x)o\n",
|
|
i, table[type].name
|
|
);
|
|
return (-1);
|
|
}
|
|
}
|
|
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);
|
|
}
|