Newer
Older
UbixOS / sys / kernel / ld.c
@Christopher W. Olsen Christopher W. Olsen on 16 Feb 2022 8 KB Sync
/*-
 * 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 );

}