/*-
* Copyright (c) 2002-2018, 2020, 2022 The UbixOS Project.
* All rights reserved.
*
* This was developed by Christopher W. Olsen for the UbixOS Project.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors.
* 2) Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors in the documentation and/or
* other materials provided with the distribution.
* 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <ubixos/ld.h>
#include <ubixos/sched.h>
#include <sys/elf.h>
#include <sys/types.h>
#include <ubixos/kpanic.h>
#include <lib/kprintf.h>
#include <lib/kmalloc.h>
#include <vfs/vfs.h>
#include <vmm/vmm.h>
#include <string.h>
#include <assert.h>
uint32_t ldEnable(const char *interp) {
int i = 0x0;
int x = 0x0;
int rel = 0x0;
int sym = 0x0;
char *newLoc = 0x0;
char *shStr = 0x0;
char *dynStr = 0x0;
uint32_t *reMap = 0x0;
fileDescriptor_t *ldFd = 0x0;
Elf_Ehdr *binaryHeader = 0x0;
Elf_Phdr *programHeader = 0x0;
Elf_Phdr *programDynamic = 0x0;
Elf_Shdr *sectionHeader = 0x0;
Elf_Sym *relSymTab = 0x0;
Elf_Rel *elfRel = 0x0;
Elf_Rela *elfRela = 0x0;
Elf_Addr addr;
/* Open our dynamic linker */
ldFd = fopen( interp, "rb" );
if( ldFd == 0x0 ) {
ldFd = fopen( "sys:/libexec/ld.so", "rb" );
if ( ldFd == 0x0 ) {
return (0x0);
}
}
kern_fseek( ldFd, 0x0, 0x0 );
binaryHeader = ( Elf32_Ehdr * ) kmalloc( sizeof( Elf32_Ehdr ) );
assert( binaryHeader );
fread( binaryHeader, sizeof( Elf32_Ehdr ), 1, ldFd );
programHeader = ( Elf_Phdr * ) kmalloc( sizeof( Elf_Phdr ) * binaryHeader->e_phnum );
assert( programHeader );
kern_fseek( ldFd, binaryHeader->e_phoff, 0 );
fread( programHeader, sizeof( Elf_Shdr ), binaryHeader->e_phnum, ldFd );
sectionHeader = ( Elf_Shdr * ) kmalloc( sizeof( Elf_Shdr ) * binaryHeader->e_shnum );
assert(sectionHeader);
kern_fseek( ldFd, binaryHeader->e_shoff, 0 );
fread( sectionHeader, sizeof( Elf_Shdr ), binaryHeader->e_shnum, ldFd );
shStr = ( char *) kmalloc( sectionHeader[binaryHeader->e_shstrndx].sh_size );
kern_fseek( ldFd, sectionHeader[binaryHeader->e_shstrndx].sh_offset, 0 );
fread( shStr, sectionHeader[binaryHeader->e_shstrndx].sh_size, 1, ldFd );
for( i = 0x0; i < binaryHeader->e_phnum; i++ ) {
switch ( programHeader[i].p_type ) {
case PT_LOAD:
newLoc = ( char * ) programHeader[i].p_vaddr + LD_START;
/*
Allocate Memory Im Going To Have To Make This Load Memory With Correct
Settings so it helps us in the future
*/
for( x = 0; x < ( programHeader[i].p_memsz ); x += 0x1000 ) {
/* make r/w or ro */
if( (vmm_remapPage( vmm_findFreePage( _current->id ), ( ( programHeader[i].p_vaddr & 0xFFFFF000 ) + x + LD_START ), PAGE_DEFAULT, _current->id, 0 ) ) == 0x0 ) {
K_PANIC("vmmRemapPage: ld");
}
memset( ( void * ) ( ( programHeader[i].p_vaddr & 0xFFFFF000 ) + x + LD_START), 0x0, 0x1000 );
}
/* Now Load Section To Memory */
kern_fseek( ldFd, programHeader[i].p_offset, 0x0 );
fread( newLoc, programHeader[i].p_filesz, 1, ldFd );
break;
case PT_DYNAMIC:
//kprintf("[%s:%i] PT_DYNAMIC", __FILE__, __LINE__);
programDynamic = ( char * ) programHeader[i].p_vaddr + LD_START;
break;
case PT_GNU_STACK:
if( programHeader[i].p_filesz > 0 ) {
// XXX - not needed for LD
//kprintf("[%s:%i] PT_GNU_STACK - p_vaddr: 0x%X, p_offset: 0x%X, p_filesz: 0x%X\n", __FILE__, __LINE__, programHeader[i].p_vaddr, programHeader[i].p_offset, programHeader[i].p_filesz );
}
/* Tells us if the stack should be executable. Failsafe to executable
until we add checking */
break;
default:
kprintf( "Unhandled ELF header (kernel) : %08x\n", programHeader[i].p_type );
break;
}
}
for (i = 0x0; i < binaryHeader->e_shnum; i++) {
switch (sectionHeader[i].sh_type) {
case SHT_STRTAB:
if (!strcmp((shStr + sectionHeader[i].sh_name), ".dynstr")) {
dynStr = (char*) kmalloc(sectionHeader[i].sh_size);
//fseek(ldFd, sectionHeader[i].sh_offset, 0x0);
//fread(dynStr, sectionHeader[i].sh_size, 1, ldFd);
}
break;
case SHT_REL:
elfRel = (Elf_Rel*) kmalloc(sectionHeader[i].sh_size);
//fseek(ldFd, sectionHeader[i].sh_offset, 0x0);
//fread(elfRel, sectionHeader[i].sh_size, 1, ldFd);
for (x = 0x0; x < sectionHeader[i].sh_size / sizeof(Elf_Rel); x++) {
rel = ELF32_R_SYM(elfRel[x].r_info);
reMap = (uint32_t*) ((uint32_t) LD_START + elfRel[x].r_offset);
switch (ELF32_R_TYPE(elfRel[x].r_info)) {
case R_386_32:
*reMap += ((uint32_t) LD_START + relSymTab[rel].st_value);
break;
case R_386_PC32:
*reMap += ((uint32_t) LD_START + relSymTab[rel].st_value) - (uint32_t) reMap;
break;
case R_386_RELATIVE:
*reMap += (uint32_t) LD_START;
break;
case R_386_NONE:
break;
default:
kprintf("[0x%X][0x%X](%i)[%s]\n", elfRel[x].r_offset, elfRel[x].r_info, rel, elfGetRelType(ELF32_R_TYPE(elfRel[x].r_info)));
kprintf("relTab [%s][0x%X][0x%X]\n", dynStr + relSymTab[rel].st_name, relSymTab[rel].st_value, relSymTab[rel].st_name);
kprint("ld: unexpected relocation type\n");
break;
}
}
kfree(elfRel);
break;
case SHT_DYNSYM:
relSymTab = (Elf_Sym*) kmalloc(sectionHeader[i].sh_size);
kern_fseek(ldFd, sectionHeader[i].sh_offset, 0x0);
fread(relSymTab, sectionHeader[i].sh_size, 1, ldFd);
sym = i;
break;
case SHT_NOBITS:
case SHT_PROGBITS:
if (sectionHeader[i].sh_addr == 0x0)
break;
// XXX - not needed for LD
//kprintf("[%s:%i] SHT_PROGBITS: 0x%X", __FILE__, __LINE__, sectionHeader[i].sh_name );
break;
case SHT_HASH:
// XXX - not needed for LD
//kprintf("[%s:%i] SHT_HASH", __FILE__, __LINE__);
break;
case SHT_DYNAMIC:
// XXX - not needed for LD
//kprintf("[%s:%i] SHT_DYNAMIC", __FILE__, __LINE__);
break;
case SHT_SYMTAB:
// XXX - not needed for LD
//kprintf("[%s:%i] SHT_SYMTAB", __FILE__, __LINE__);
break;
default:
kprintf("Invalid: %i]", sectionHeader[i].sh_type);
break;
}
}
i = binaryHeader->e_entry + LD_START;
kfree(dynStr);
kfree(shStr);
kfree(relSymTab);
kfree(sectionHeader);
kfree(programHeader);
kfree(binaryHeader);
fclose(ldFd);
return( ( uint32_t ) i );
}