110 lines
2.9 KiB
C
110 lines
2.9 KiB
C
#include "vxBoot/loader.h"
|
|
#include "vxBoot/fs/smemfs.h"
|
|
#include "vxBoot/terminal.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
|
/* loader_get_section() : Try to find section information using its name */
|
|
static int loader_get_section(
|
|
Elf32_Shdr *shdr,
|
|
char const * const name,
|
|
struct smemfs_inode const * restrict const inode,
|
|
Elf32_Ehdr *hdr
|
|
) {
|
|
char buff[16];
|
|
off_t stroff;
|
|
off_t shoff;
|
|
|
|
/* find the section header table */
|
|
shoff = hdr->e_shoff;
|
|
|
|
/* find the section string table ".strtable" */
|
|
smemfs_pread(
|
|
inode,
|
|
shdr, sizeof(Elf32_Shdr),
|
|
shoff + (sizeof(Elf32_Shdr) * hdr->e_shstrndx)
|
|
);
|
|
stroff = shdr->sh_offset;
|
|
|
|
/* walk throught each section and find the .got section */
|
|
for (int i = 0; i < hdr->e_shnum; ++i) {
|
|
smemfs_pread(inode, shdr, sizeof(Elf32_Shdr), shoff);
|
|
smemfs_pread(inode, buff, 16, shdr->sh_name + stroff);
|
|
if (strcmp(buff, name) == 0)
|
|
return (0);
|
|
shoff += sizeof(Elf32_Shdr);
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
|
|
/* loader_get_symbols() : get symbols information */
|
|
static int loader_get_symbol(
|
|
Elf32_Sym *sym,
|
|
char const * const name,
|
|
struct smemfs_inode const * restrict const inode,
|
|
Elf32_Ehdr *hdr
|
|
){
|
|
Elf32_Shdr symhdr;
|
|
Elf32_Shdr strhdr;
|
|
char buff[64];
|
|
int off;
|
|
|
|
/* frist, find the symtab section */
|
|
loader_get_section(&symhdr, ".symtab", inode, hdr);
|
|
loader_get_section(&strhdr, ".strtab", inode, hdr);
|
|
|
|
/* walk throut the table */
|
|
off = symhdr.sh_offset;
|
|
for (uint32_t i = 0 ; i < symhdr.sh_size / sizeof(Elf32_Sym) ; ++i) {
|
|
smemfs_pread(inode, sym, sizeof(Elf32_Sym), off);
|
|
smemfs_pread(inode, buff, 64, sym->st_name + strhdr.sh_offset);
|
|
if (strcmp(buff, name) == 0)
|
|
return (0);
|
|
off += sizeof(Elf32_Sym);
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
|
|
/* loader_got_patch() : Try to patch the GOT/PLT section */
|
|
int loader_got_patch(
|
|
struct smemfs_inode const * restrict const inode,
|
|
struct kernel_info * const kernel,
|
|
Elf32_Ehdr *hdr
|
|
) {
|
|
Elf32_Shdr shdr;
|
|
Elf32_Sym sym;
|
|
uintptr_t *__got__;
|
|
uintptr_t *got;
|
|
uintptr_t addr;
|
|
|
|
/* first, try to find the __GLOBAL_OFFSET_TABLE__ symbol */
|
|
if (loader_get_symbol(&sym, "_GLOBAL_OFFSET_TABLE_", inode, hdr)) {
|
|
terminal_write("_GLOBAL_OFFSET_TABLE_ not found...\n");
|
|
return (0);
|
|
}
|
|
__got__ = kernel->memory.program.start;
|
|
__got__ = (void*)((uintptr_t)__got__ + (uintptr_t)sym.st_value);
|
|
terminal_write(" __GOT__ found at %p...\n", __got__);
|
|
|
|
|
|
/* and we need to relocalise the "real" GOT section and update the
|
|
hardcoded address in the same time */
|
|
loader_get_section(&shdr, ".got", inode, hdr);
|
|
got = kernel->memory.program.start;
|
|
got = (void*)((uintptr_t)got + (uintptr_t)shdr.sh_addr);
|
|
terminal_write(" GOT found at %p...\n", got);
|
|
|
|
/* perform transation */
|
|
for (uint32_t i = 0 ; i < shdr.sh_size >> 2 ; ++i) {
|
|
terminal_write(" path symbols %p...\n", got[i]);
|
|
addr = got[i];
|
|
addr += (uintptr_t)kernel->hardware.ram.physical.kernel_addr;
|
|
addr |= (uintptr_t)0x80000000;
|
|
__got__[i] = addr;
|
|
}
|
|
return (0);
|
|
}
|