From b76125b9c12d811a049477ef50656627f9691173 Mon Sep 17 00:00:00 2001
From: Terraneo Federico <fede.tft@hotmail.it>
Date: Sat, 17 Mar 2012 00:30:07 +0100
Subject: [PATCH] Process image generation done

---
 Makefile                                      |   2 +-
 app_template/main.c                           |  10 +-
 elf_program.cpp                               | 133 +++++++++++++++---
 elf_program.h                                 |  39 +++++
 elf_types.h                                   |  52 +++++--
 main.cpp                                      |  52 ++-----
 .../common/interfaces-impl/portability.cpp    |  20 +++
 .../common/interfaces-impl/portability_impl.h |   3 +
 miosix/config/Makefile.inc                    |   4 +-
 miosix/kernel/kernel.cpp                      |  69 +++++++++
 miosix/kernel/kernel.h                        |   8 ++
 prog1.h                                       |  39 ++---
 test_driver.cpp                               |   2 +
 13 files changed, 344 insertions(+), 89 deletions(-)

diff --git a/Makefile b/Makefile
index ff704950..9f5f3565 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ SUBDIRS := miosix
 ## List here your source files (both .s, .c and .cpp)
 ##
 SRC :=                                  \
-main.cpp svc.s
+main.cpp elf_program.cpp svc.s
 
 ##
 ## List here additional static libraries with relative path
diff --git a/app_template/main.c b/app_template/main.c
index 89100a11..11726839 100644
--- a/app_template/main.c
+++ b/app_template/main.c
@@ -8,13 +8,15 @@ int mystrlen(const char *s)
 	return result;
 }
 
-int youShouldNotSeeThisInTheElfFile=0;
-int *youShouldNotSeeThisInTheElfFile2=&youShouldNotSeeThisInTheElfFile;
+//int youShouldNotSeeThisInTheElfFile=0;
+//int *youShouldNotSeeThisInTheElfFile2=&youShouldNotSeeThisInTheElfFile;
 
 int main()
 {
 	//FIXME: without static code fails!!
 	static const char str[]="Hello world\n";
-	youShouldNotSeeThisInTheElfFile=write(1,str,mystrlen(str));
-	return *youShouldNotSeeThisInTheElfFile2;
+	//youShouldNotSeeThisInTheElfFile=write(1,str,mystrlen(str));
+	//return *youShouldNotSeeThisInTheElfFile2;
+	write(1,str,mystrlen(str));
+	return 0;
 }
diff --git a/elf_program.cpp b/elf_program.cpp
index 93bdeba8..1e370dd3 100644
--- a/elf_program.cpp
+++ b/elf_program.cpp
@@ -1,3 +1,29 @@
+/***************************************************************************
+ *   Copyright (C) 2012 by Terraneo Federico                               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   As a special exception, if other files instantiate templates or use   *
+ *   macros or inline functions from this file, or you compile this file   *
+ *   and link it with other works to produce a work based on this file,    *
+ *   this file does not by itself cause the resulting work to be covered   *
+ *   by the GNU General Public License. However the source code for this   *
+ *   file must still be made available in accordance with the GNU General  *
+ *   Public License. This exception does not invalidate any other reasons  *
+ *   why a work based on this file might be covered by the GNU General     *
+ *   Public License.                                                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
+ ***************************************************************************/
 
 #include "elf_program.h"
 #include <stdexcept>
@@ -21,7 +47,8 @@ ElfProgram::ElfProgram(const unsigned int *elf, unsigned int size) : elf(elf)
 {
     //Trying to follow the "full recognition before processing" approach,
     //(http://www.cs.dartmouth.edu/~sergey/langsec/occupy/FullRecognition.jpg)
-    //all of the elf fields that will later be used are checked in advance
+    //all of the elf fields that will later be used are checked in advance.
+    //Unused fields are unchecked, so when using new fields, add new checks
     if(validateHeader(size)==false) throw runtime_error("Bad file");
 }
 
@@ -30,9 +57,10 @@ bool ElfProgram::validateHeader(unsigned int size)
     //Validate ELF header
     //Note: this code assumes a little endian elf and a little endian ARM CPU
     if(size<sizeof(Elf32_Ehdr)) return false;
-    static const char magic[EI_NIDENT]={0x7f,'E','L','F',1,1,1};
-    if(memcmp(elf,magic,EI_NIDENT)) throw runtime_error("Unrecognized format");
     const Elf32_Ehdr *ehdr=getElfHeader();
+    static const char magic[EI_NIDENT]={0x7f,'E','L','F',1,1,1};
+    if(memcmp(ehdr->e_ident,magic,EI_NIDENT))
+        throw runtime_error("Unrecognized format");
     if(ehdr->e_type!=ET_EXEC) throw runtime_error("Not an executable");
     if(ehdr->e_machine!=EM_ARM) throw runtime_error("Wrong CPU arch");
     if(ehdr->e_version!=EV_CURRENT) return false;
@@ -50,8 +78,8 @@ bool ElfProgram::validateHeader(unsigned int size)
     bool codeSegmentPresent=false;
     bool dataSegmentPresent=false;
     bool dynamicSegmentPresent=false;
-    const Elf32_Phdr *phdr=getProgramHeaderTable();
     int dataSegmentSize;
+    const Elf32_Phdr *phdr=getProgramHeaderTable();
     for(int i=0;i<getNumOfProgramHeaderEntries();i++,phdr++)
     {
         //The third condition does not imply the other due to 32bit wraparound
@@ -63,14 +91,6 @@ bool ElfProgram::validateHeader(unsigned int size)
         
         switch(phdr->p_type)
         {
-            case PT_DYNAMIC:
-                if(dynamicSegmentPresent) return false; //Two dynamic segments?
-                dynamicSegmentPresent=true;
-                //DYNAMIC segment *must* come after data segment
-                if(dataSegmentPresent==false) return false;
-                if(validateDynamicSegment(phdr,size,dataSegmentSize)==false)
-                    return false;
-                break;
             case PT_LOAD:
                 if(phdr->p_flags & ~(PF_R | PF_W | PF_X)) return false;
                 if(!(phdr->p_flags & PF_R)) return false;
@@ -78,22 +98,31 @@ bool ElfProgram::validateHeader(unsigned int size)
                     throw runtime_error("File violates W^X");
                 if(phdr->p_flags & PF_X)
                 {
-                    if(codeSegmentPresent) return false; //Two code segments?
+                    if(codeSegmentPresent) return false; //Can't apper twice
                     codeSegmentPresent=true;
                     if(ehdr->e_entry<phdr->p_offset ||
                        ehdr->e_entry>phdr->p_offset+phdr->p_filesz ||
                        phdr->p_filesz!=phdr->p_memsz) return false;
                 }
-                if(phdr->p_flags & PF_W)
+                if((phdr->p_flags & PF_W) && !(phdr->p_flags & PF_X))
                 {
                     if(dataSegmentPresent) return false; //Two data segments?
                     dataSegmentPresent=true;
+                    if(phdr->p_memsz<phdr->p_filesz) return false;
                     int maxSize=MAX_PROCESS_IMAGE_SIZE-MIN_PROCESS_STACK_SIZE;
                     if(phdr->p_memsz>=maxSize)
                         throw runtime_error("Data segment too big");
                     dataSegmentSize=phdr->p_memsz;
                 }
                 break;
+            case PT_DYNAMIC:
+                if(dynamicSegmentPresent) return false; //Two dynamic segments?
+                dynamicSegmentPresent=true;
+                //DYNAMIC segment *must* come after data segment
+                if(dataSegmentPresent==false) return false;
+                if(validateDynamicSegment(phdr,size,dataSegmentSize)==false)
+                    return false;
+                break;
             default:
                 //Ignoring other segments
                 break;
@@ -106,9 +135,9 @@ bool ElfProgram::validateHeader(unsigned int size)
 bool ElfProgram::validateDynamicSegment(const Elf32_Phdr *dynamic,
         unsigned int size, unsigned int dataSegmentSize)
 {
-    unsigned int base=reinterpret_cast<unsigned int>(elf);
+    unsigned int base=getElfBase();
     const Elf32_Dyn *dyn=
-        reinterpret_cast<const Elf32_Dyn*>(base+dynamic->p_offset);
+        reinterpret_cast<const Elf32_Dyn*>(getElfBase()+dynamic->p_offset);
     const int dynSize=dynamic->p_memsz/sizeof(Elf32_Dyn);
     Elf32_Addr dtRel;
     Elf32_Word dtRelsz;
@@ -158,6 +187,7 @@ bool ElfProgram::validateDynamicSegment(const Elf32_Phdr *dynamic,
                 case R_ARM_RELATIVE:
                     if(rel->r_offset<DATA_START) return false;
                     if(rel->r_offset>DATA_START+dataSegmentSize-4) return false;
+                    if(rel->r_offset & 0x3) return false;
                     break;
                 default:
                     throw runtime_error("Unexpected relocation type");
@@ -175,7 +205,76 @@ void ProcessImage::load(ElfProgram& program)
 {
     if(image) delete[] image;
     
-    
+    //TODO: add in elf file a field with the true image size
+    image=new unsigned int[MAX_PROCESS_IMAGE_SIZE/4];
+    const unsigned int base=program.getElfBase();
+    const Elf32_Phdr *phdr=program.getProgramHeaderTable();
+    Elf32_Addr dtRel;
+    Elf32_Word dtRelsz;
+    bool hasRelocs=false;
+    for(int i=0;i<program.getNumOfProgramHeaderEntries();i++,phdr++)
+    {
+        switch(phdr->p_type)
+        {
+            case PT_LOAD:
+                if((phdr->p_flags & PF_W) && !(phdr->p_flags & PF_X))
+                {
+                    const char *dataSegmentInFile=
+                        reinterpret_cast<const char*>(base+phdr->p_offset);
+                    char *dataSegmentInMem=reinterpret_cast<char*>(image);
+                    memcpy(dataSegmentInMem,dataSegmentInFile,phdr->p_filesz);
+                    dataSegmentInMem+=phdr->p_filesz;
+                    memset(dataSegmentInMem,0,phdr->p_memsz-phdr->p_filesz);
+                }
+                break;
+            case PT_DYNAMIC:
+            {
+                const Elf32_Dyn *dyn=reinterpret_cast<const Elf32_Dyn*>
+                    (base+phdr->p_offset);
+                const int dynSize=phdr->p_memsz/sizeof(Elf32_Dyn);
+                for(int i=0;i<dynSize;i++,dyn++)
+                {
+                    switch(dyn->d_tag)
+                    {
+                        case DT_REL:
+                            hasRelocs=true;
+                            dtRel=dyn->d_un.d_ptr;
+                            break;
+                        case DT_RELSZ:
+                            hasRelocs=true;
+                            dtRelsz=dyn->d_un.d_val;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                break;
+            }
+            default:
+                //Ignoring other segments
+                break;
+        }
+    }
+    if(hasRelocs)
+    {
+        const Elf32_Rel *rel=reinterpret_cast<const Elf32_Rel*>(base+dtRel);
+        const int relSize=dtRelsz/sizeof(Elf32_Rel);
+        for(int i=0;i<relSize;i++,rel++)
+        {
+            switch(ELF32_R_TYPE(rel->r_info))
+            {
+                case R_ARM_ABS32:
+                case R_ARM_RELATIVE:
+                {
+                    unsigned int offset=(rel->r_offset-DATA_START)/4;
+                    image[offset]+=reinterpret_cast<unsigned int>(image);
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+    }
 }
 
 ProcessImage::~ProcessImage()
diff --git a/elf_program.h b/elf_program.h
index 7d51eb5d..0dcb4eb1 100644
--- a/elf_program.h
+++ b/elf_program.h
@@ -1,3 +1,29 @@
+/***************************************************************************
+ *   Copyright (C) 2012 by Terraneo Federico                               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   As a special exception, if other files instantiate templates or use   *
+ *   macros or inline functions from this file, or you compile this file   *
+ *   and link it with other works to produce a work based on this file,    *
+ *   this file does not by itself cause the resulting work to be covered   *
+ *   by the GNU General Public License. However the source code for this   *
+ *   file must still be made available in accordance with the GNU General  *
+ *   Public License. This exception does not invalidate any other reasons  *
+ *   why a work based on this file might be covered by the GNU General     *
+ *   Public License.                                                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
+ ***************************************************************************/
 
 #include <utility>
 #include "elf_types.h"
@@ -56,6 +82,14 @@ public:
         return getElfHeader()->e_phnum;
     }
     
+    /**
+     * \return a number representing the elf base address in memory
+     */
+    unsigned int getElfBase() const
+    {
+        return reinterpret_cast<unsigned int>(elf);
+    }
+    
 private:
     /**
      * \param size elf file size
@@ -95,6 +129,11 @@ public:
      */
     void load(ElfProgram& program);
     
+    /**
+     * \return a pointer to the base of the program image
+     */
+    unsigned int *getProcessBasePointer() const { return image; }
+    
     /**
      * \return the size of the process image, or zero if it is not valid 
      */
diff --git a/elf_types.h b/elf_types.h
index 8f985c40..48d242dc 100644
--- a/elf_types.h
+++ b/elf_types.h
@@ -1,23 +1,48 @@
-/* 
- * File:   ELF.h
- * Author: lr
- *
- * Created on March 3, 2012, 3:31 PM
- */
+/***************************************************************************
+ *   Copyright (C) 2012 by Luigi Rucco and Terraneo Federico               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   As a special exception, if other files instantiate templates or use   *
+ *   macros or inline functions from this file, or you compile this file   *
+ *   and link it with other works to produce a work based on this file,    *
+ *   this file does not by itself cause the resulting work to be covered   *
+ *   by the GNU General Public License. However the source code for this   *
+ *   file must still be made available in accordance with the GNU General  *
+ *   Public License. This exception does not invalidate any other reasons  *
+ *   why a work based on this file might be covered by the GNU General     *
+ *   Public License.                                                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
+ ***************************************************************************/
 
 #include <inttypes.h>
 
 #ifndef ELF_TYPES_H
 #define	ELF_TYPES_H
 
+// elf-specific types
 typedef uint32_t Elf32_Word;
 typedef int32_t  Elf32_Sword;
 typedef uint16_t Elf32_Half;
 typedef uint32_t Elf32_Off;
 typedef uint32_t Elf32_Addr;
 
+// Size of e_ident in the elf header
 static const int EI_NIDENT=16;
 
+/*
+ * Elf header
+ */
 struct Elf32_Ehdr
 {
     unsigned char e_ident[EI_NIDENT]; // Ident bytes
@@ -53,6 +78,9 @@ static const int EM_ARM  = 0x28;
 static const int EF_ARM_EABI_MASK = 0x05000000;
 static const int EF_HAS_ENTRY_POINT = 2;
 
+/*
+ * Elf program header
+ */
 struct Elf32_Phdr
 {
     Elf32_Word p_type;   // Program header type, any of the PH_* constants
@@ -77,12 +105,15 @@ static const int PF_X = 0x1; // Execute
 static const int PF_W = 0x2; // Write
 static const int PF_R = 0x4; // Read
 
+/*
+ * Entries of the DYNAMIC segment
+ */
 struct Elf32_Dyn
 {
-    Elf32_Sword d_tag;
+    Elf32_Sword d_tag;    // Type of entry
     union {
-        Elf32_Word d_val;
-        Elf32_Addr d_ptr;
+        Elf32_Word d_val; // Value of entry, if number
+        Elf32_Addr d_ptr; // Value of entry, if offset into the file
     } d_un;
 } __attribute__((packed));
 
@@ -113,6 +144,9 @@ static const int DT_TEXTREL  = 22;
 static const int DT_JMPREL   = 23;
 static const int DT_BINDNOW  = 24;
 
+/*
+ * Relocation entries
+ */
 struct Elf32_Rel
 {
     Elf32_Addr r_offset;
diff --git a/main.cpp b/main.cpp
index 57160e13..d24ff779 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,8 +2,8 @@
 #include <cstdio>
 #include <cassert>
 #include "miosix.h"
-#include "elf_types.h"
-#include "prog1.h"
+#include "elf_program.h"
+#include "prog2.h"
 
 using namespace std;
 using namespace miosix;
@@ -68,34 +68,6 @@ void ledThread(void *)
     }
 }
 
-void loadPhdr(const Elf32_Ehdr *elf)
-{
-    assert(elf->e_phentsize==sizeof(Elf32_Phdr));
-    unsigned int base=reinterpret_cast<unsigned int>(elf);
-    const Elf32_Phdr *hdr=reinterpret_cast<const Elf32_Phdr*>(base+elf->e_phoff);
-    for(int i=0;i<elf->e_phnum;i++,hdr++)
-    {
-        switch(hdr->p_type)
-        {
-            case PT_DYNAMIC:
-                printf("Entry %d is dynamic\n",i);
-                break;
-            case PT_LOAD:
-                printf("Entry %d is load\n",i);
-                break;
-            default:
-                printf("Unexpected\n");
-        }
-        printf("Offset in file=%d\n",hdr->p_offset);
-        printf("Virtual address=%d\n",hdr->p_vaddr);
-        printf("Physical address=%d\n",hdr->p_paddr);
-        printf("Size in file=%d\n",hdr->p_filesz);
-        printf("Size in memory=%d\n",hdr->p_memsz);
-        printf("Flags=%d\n",hdr->p_flags);
-        printf("Align=%d\n",hdr->p_align);
-    }
-}
-
 int main()
 {
     Thread::create(ledThread,STACK_MIN);
@@ -103,15 +75,15 @@ int main()
     
     getchar();
     
-    const Elf32_Ehdr *elf=reinterpret_cast<const Elf32_Ehdr*>(main_elf);
-    loadPhdr(elf);
-    unsigned int base=reinterpret_cast<unsigned int>(main_elf);
-    base+=elf->e_entry;
-    void (*elfentry)(void*)=reinterpret_cast<void (*)(void*)>(base);
-    iprintf("elf base address = %p\n",main_elf);
-    iprintf("elf entry is = %p\n",elf->e_entry);
-    iprintf("elf entry (absolute) is = %p\n",elfentry);
-            
-    Thread::create(elfentry,2048);
+    ElfProgram prog(reinterpret_cast<const unsigned int*>(main_elf),main_elf_len);
+    ProcessImage pi;
+    pi.load(prog);
+
+    void *(*entry)(void*)=reinterpret_cast<void *(*)(void*)>(prog.getEntryPoint());
+    iprintf("elf base address = 0x%x\n",prog.getElfBase());
+    iprintf("elf entry (rebased) = 0x%x\n",prog.getEntryPoint());
+    iprintf("base pointer = %p\n",pi.getProcessBasePointer());
+    
+    Thread::createWithGotBase(entry,2048,1,0,0,pi.getProcessBasePointer());
     for(;;) Thread::sleep(1000);
 }
diff --git a/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability.cpp b/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability.cpp
index 721fe8b8..0e938acb 100644
--- a/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability.cpp
+++ b/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability.cpp
@@ -190,6 +190,26 @@ void initCtxsave(unsigned int *ctxsave, void *(*pc)(void *), unsigned int *sp,
     //leaving the content of r4-r11 uninitialized
 }
 
+void initCtxsave(unsigned int *ctxsave, void *(*pc)(void *), unsigned int *sp,
+        void *argv, unsigned int gotBase)
+{
+    unsigned int *stackPtr=sp;
+    stackPtr--; //Stack is full descending, so decrement first
+    *stackPtr=0x01000000; stackPtr--;                                 //--> xPSR
+    *stackPtr=reinterpret_cast<unsigned long>(
+            &miosix::Thread::threadLauncher); stackPtr--;             //--> pc
+    *stackPtr=0xffffffff; stackPtr--;                                 //--> lr
+    *stackPtr=0; stackPtr--;                                          //--> r12
+    *stackPtr=0; stackPtr--;                                          //--> r3
+    *stackPtr=0; stackPtr--;                                          //--> r2
+    *stackPtr=reinterpret_cast<unsigned long >(argv); stackPtr--;     //--> r1
+    *stackPtr=reinterpret_cast<unsigned long >(pc);                   //--> r0
+
+    ctxsave[0]=reinterpret_cast<unsigned long>(stackPtr);             //--> psp
+    ctxsave[6]=gotBase; //r9
+    //leaving the content of r4-r11 uninitialized
+}
+
 void IRQportableStartKernel()
 {
     //Enable fault handlers
diff --git a/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability_impl.h b/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability_impl.h
index d01c03f1..5da3a2bb 100644
--- a/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability_impl.h
+++ b/miosix/arch/cortexM3_stm32f2/common/interfaces-impl/portability_impl.h
@@ -194,6 +194,9 @@ private:
     friend void ISR_yield();
 };
 
+void initCtxsave(unsigned int *ctxsave, void *(*pc)(void *), unsigned int *sp,
+        void *argv, unsigned int gotBase);
+
 #endif //WITH_PROCESSES
 
 /**
diff --git a/miosix/config/Makefile.inc b/miosix/config/Makefile.inc
index f963354d..4fdf4fdc 100644
--- a/miosix/config/Makefile.inc
+++ b/miosix/config/Makefile.inc
@@ -13,13 +13,13 @@
 ## architecture
 ##
 #OPT_BOARD := lpc2138_miosix_board
-OPT_BOARD := stm32f103ze_stm3210e-eval
+#OPT_BOARD := stm32f103ze_stm3210e-eval
 #OPT_BOARD := stm32f103ve_mp3v2
 #OPT_BOARD := stm32f100rb_stm32vldiscovery
 #OPT_BOARD := stm32f103ve_strive_mini
 #OPT_BOARD := stm32f103ze_redbull_v2
 #OPT_BOARD := stm32f407vg_stm32f4discovery
-#OPT_BOARD := stm32f207ig_stm3220g-eval
+OPT_BOARD := stm32f207ig_stm3220g-eval
 
 ##
 ## Optimization flags, choose one.
diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp
index a53c9c05..9d0f4ba1 100644
--- a/miosix/kernel/kernel.cpp
+++ b/miosix/kernel/kernel.cpp
@@ -366,6 +366,75 @@ Thread *Thread::create(void (*startfunc)(void *), unsigned int stacksize,
             stacksize,priority,argv,options);
 }
 
+Thread *Thread::createWithGotBase(void *(*startfunc)(void *),
+                            unsigned int stacksize,
+                            Priority priority, void *argv,
+                            unsigned short options,unsigned int *gotBase)
+{
+        //Check to see if input parameters are valid
+    if(priority.validate()==false || stacksize<STACK_MIN)
+    {
+        errorHandler(INVALID_PARAMETERS);
+        return NULL;
+    }
+    //If stacksize is not divisible by 4, round it to a number divisible by 4
+    stacksize &= ~0x3;
+    
+    //Allocate memory for the thread, return if fail
+    unsigned int *base;
+    Thread *thread;
+    #ifdef __NO_EXCEPTIONS
+    base=new int[(stacksize+WATERMARK_LEN+CTXSAVE_ON_STACK)/4];
+    thread=new Thread(base,stacksize);
+    #else //__NO_EXCEPTIONS
+    try {
+        base=new unsigned int[(stacksize+WATERMARK_LEN+CTXSAVE_ON_STACK)/4];
+    } catch(std::bad_alloc&)
+    {
+        errorHandler(OUT_OF_MEMORY);
+        return NULL;//Error
+    }
+    try {
+        thread=new Thread(base,stacksize);
+    } catch(std::bad_alloc&)
+    {
+        delete[] base;
+        errorHandler(OUT_OF_MEMORY);
+        return NULL;//Error
+    }
+    #endif //__NO_EXCEPTIONS
+
+    //Fill watermark and stack
+    memset(base, WATERMARK_FILL, WATERMARK_LEN);
+    base+=WATERMARK_LEN/sizeof(unsigned int);
+    memset(base, STACK_FILL, stacksize);
+
+    //On some architectures some registers are saved on the stack, therefore
+    //initCtxsave *must* be called after filling the stack.
+    unsigned int *topOfStack=
+        thread->watermark+(stacksize+WATERMARK_LEN+CTXSAVE_ON_STACK)/4;
+    miosix_private::initCtxsave(thread->ctxsave,startfunc,topOfStack,argv,
+            (unsigned int)gotBase);
+
+    if((options & JOINABLE)==0) thread->flags.IRQsetDetached();
+    
+    //Add thread to thread list
+    {
+        //Handling the list of threads, critical section is required
+        PauseKernelLock lock;
+        if(Scheduler::PKaddThread(thread,priority)==false)
+        {
+            //Reached limit on number of threads
+            delete thread;
+            return NULL;
+        }
+    }
+    #ifdef SCHED_TYPE_EDF
+    if(isKernelRunning()) yield(); //The new thread might have a closer deadline
+    #endif //SCHED_TYPE_EDF
+    return thread;
+}
+
 void Thread::yield()
 {
     miosix_private::doYield();
diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h
index 63c4d96c..27653175 100644
--- a/miosix/kernel/kernel.h
+++ b/miosix/kernel/kernel.h
@@ -466,6 +466,11 @@ public:
     static Thread *create(void (*startfunc)(void *), unsigned int stacksize,
                             Priority priority=Priority(), void *argv=NULL,
                             unsigned short options=DEFAULT);
+    
+    static Thread *createWithGotBase(void *(*startfunc)(void *),
+                            unsigned int stacksize,
+                            Priority priority, void *argv,
+                            unsigned short options,unsigned int *gotBase);
 
     /**
      * When called, suggests the kernel to pause the current thread, and run
@@ -924,6 +929,9 @@ private:
     //Needs threadLauncher
     friend void miosix_private::initCtxsave(unsigned int *ctxsave,
             void *(*pc)(void *), unsigned int *sp, void *argv);
+    //Needs threadLauncher
+    friend void miosix_private::initCtxsave(unsigned int *ctxsave,
+            void *(*pc)(void *), unsigned int *sp, void *argv,unsigned int gotBase);
     //Needs access to priority, savedPriority, mutexLocked and flags.
     friend class Mutex;
     //Needs access to flags
diff --git a/prog1.h b/prog1.h
index cb2de8eb..b993810f 100644
--- a/prog1.h
+++ b/prog1.h
@@ -1,29 +1,36 @@
-const unsigned char main_elf[] = {
+const unsigned char __attribute__((aligned(8))) main_elf[] = {
   0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x99, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x02, 0x00, 0x00, 0x05, 0x34, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
-  0x98, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x80, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x98, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
+  0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
   0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x24, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x10,
+  0x50, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
   0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0c, 0xf8,
-  0x00, 0xf0, 0x1a, 0xf8, 0x03, 0x78, 0x23, 0xb1, 0x00, 0x23, 0x01, 0x33,
+  0x00, 0xf0, 0x26, 0xf8, 0x03, 0x78, 0x23, 0xb1, 0x00, 0x23, 0x01, 0x33,
   0xc2, 0x5c, 0x00, 0x2a, 0xfb, 0xd1, 0x18, 0x46, 0x70, 0x47, 0x00, 0xbf,
-  0x10, 0xb5, 0x06, 0x4c, 0x4c, 0x44, 0x20, 0x46, 0xff, 0xf7, 0xf0, 0xff,
-  0x21, 0x46, 0x02, 0x46, 0x01, 0x20, 0x00, 0xf0, 0x07, 0xf8, 0x00, 0x20,
-  0x10, 0xbd, 0x00, 0xbf, 0x10, 0x00, 0x00, 0x00, 0x01, 0x23, 0x00, 0xdf,
-  0x02, 0x23, 0x00, 0xdf, 0x70, 0x47, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+  0x10, 0xb5, 0x0a, 0x4c, 0x4c, 0x44, 0x20, 0x46, 0xff, 0xf7, 0xf0, 0xff,
+  0x21, 0x46, 0x02, 0x46, 0x01, 0x20, 0x00, 0xf0, 0x13, 0xf8, 0x06, 0x4b,
+  0x06, 0x4a, 0x59, 0xf8, 0x03, 0x30, 0x59, 0xf8, 0x02, 0x20, 0x1b, 0x68,
+  0x10, 0x60, 0x18, 0x68, 0x10, 0xbd, 0x00, 0xbf, 0x68, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x23, 0x00, 0xdf,
+  0x02, 0x23, 0x00, 0xdf, 0x70, 0x47, 0x00, 0x00, 0x78, 0x00, 0x00, 0x10,
+  0x02, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10, 0x17, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x00, 0x10, 0x17, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10,
+  0x78, 0x00, 0x00, 0x10, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6c, 0x6c,
-  0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00
+  0x00, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
+  0x72, 0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
-unsigned int main_elf_len = 312;
+unsigned int main_elf_len = 396;
diff --git a/test_driver.cpp b/test_driver.cpp
index 074b254f..33ce1737 100644
--- a/test_driver.cpp
+++ b/test_driver.cpp
@@ -21,4 +21,6 @@ int main()
         <<"base address = "<<elfFileData<<endl
         <<"entry (file relative) = "<<program.getElfHeader()->e_entry<<endl
         <<"entry (relocated) = "<<program.getEntryPoint()<<endl;
+    ProcessImage pi;
+    pi.load(program);
 }
-- 
GitLab