Changeset 9

Show
Ignore:
Timestamp:
03/12/08 18:43:34 (10 months ago)
Author:
mwhitworth
Message:

Rework link_lib.c. Minor fixes in build system.

Location:
Whitix/trunk
Files:
18 modified

Legend:

Unmodified
Added
Removed
  • Whitix/trunk/arch/i386/kernel/ints.c

    r1 r9  
    108108        /* Do sanity checks on the stack pointer, note that numArgBytes is allowed 
    109109           to be 0. */ 
    110  
    111110        if (VirtCheckArea((void*)stackPointer,numArgBytes,VER_READ)) 
    112111                return -EFAULT; 
     
    152151         * Assuming the computer we run on has an FPU, this exception is only 
    153152         * fired when TS (task switch) is set in CR0, and that's only set if a previous 
    154          * task has used the FPU 
     153         * task has used the FPU. 
    155154         */ 
    156155 
     
    264263 
    265264        case 0x30: 
    266 //              printf("Syscall!\n index = %#X from %#X\n",curr.eax,curr.eip); 
    267265                curr.eax=IrqSysCall(curr.eax,curr.edx,curr.ecx); 
    268266                break; 
  • Whitix/trunk/include/sys.h

    r1 r9  
    1616 * 
    1717 */ 
     18 
     19/* TODO: Cleanup */ 
    1820 
    1921#ifndef SYS_H 
  • Whitix/trunk/kernel/main.c

    r1 r9  
    8888        int i; 
    8989        struct StorageDevice* rootDev=NULL; 
    90  
    9190        int fds[]={ 
    9291                0,0,0, 
  • Whitix/trunk/memory/mmap.c

    r7 r9  
    240240                if (area->flags & MMAP_SHARED) 
    241241                { 
     242                        /* TODO: Handle shared pages. */ 
    242243                        printf("Shared page..\n"); 
    243244                        MachineHalt(); 
     
    330331        address=PAGE_ALIGN(address); 
    331332 
    332 #if 0 
    333         printf("%#X: %s, %s, %#X\n",address,(error & VM_WRITE) ? "W" : "R",(error & VM_PROTECTION) ? "P" : "N",process); 
    334 #endif 
    335  
    336         /* A null pointer's been deferenced */ 
     333        /* A null pointer has been deferenced */ 
    337334        if (!process || address < PAGE_SIZE) 
    338335                return -EFAULT; 
     
    842839                goto end; 
    843840 
     841        /* TODO: Fix this case. What should we do here? */ 
    844842        if (len < 0) 
    845843        { 
  • Whitix/trunk/user/librtl/memory.h

    r7 r9  
    22#define MEMORY_H 
    33 
     4/* Constant for SysMemoryMap */ 
     5#define _SYS_MMAP_PRIVATE       0x00000000 
     6#define _SYS_MMAP_SHARED        0x00000001 
     7#define _SYS_MMAP_FIXED         0x00000002 
     8#define _SYS_MMAP_GROWDOWN      0x00000004 
     9 
     10/* Defines for architecture-specific memory functions. */ 
     11#define PAGE_SIZE       4096 /* 4K */ 
     12#define PAGE_ALIGN(addr) ((addr) & ~(PAGE_SIZE-1)) 
     13#define PAGE_OFFSET(addr) ((addr) & (PAGE_SIZE-1)) 
     14#define PAGE_ALIGN_UP(addr) (PAGE_ALIGN((addr)+PAGE_SIZE-1)) 
     15 
    416#endif 
  • Whitix/trunk/user/librtl/syscalls.h

    r7 r9  
    11#ifndef SYSCALLS_H 
    22#define SYSCALLS_H 
     3 
     4/* Include standard macros and constants */ 
     5#include <memory.h> 
    36 
    47/* FIXME: CHANGE ALL THIS SOON */ 
  • Whitix/trunk/user/librtl/sysdefs.h

    r7 r9  
    1111SYSCALL(9,int,SysTruncate,8,(int fd,DWORD length)); 
    1212SYSCALL(10,int,SysMove,8,(char* src,char* dest)); 
    13 SYSCALL(11,int,SysWrite,12,(int fd,BYTE* data,DWORD amount)); 
    14 SYSCALL(12,int,SysRead,12,(int fd,BYTE* buffer,DWORD amount)); 
     13SYSCALL(11,int,SysWrite,12,(int fd,void* data,DWORD amount)); 
     14SYSCALL(12,int,SysRead,12,(int fd,void* buffer,DWORD amount)); 
    1515SYSCALL(13,int,SysSeek,12,(int fd,int distance,int whence)); 
    1616SYSCALL(14,int,SysChangeDir,4,(char* newDir)); 
     
    2626/* Memory syscalls */ 
    2727SYSCALL(23,void*,SysMoreCore,4,(int len)); 
    28 SYSCALL(24,DWORD,SysMemoryMap,20,(DWORD address,DWORD length,int protection,int fd,DWORD offset)); 
     28SYSCALL(24,DWORD,SysMemoryMap,24,(DWORD address,DWORD length,int protection,int fd,DWORD offset,int flags)); 
    2929SYSCALL(25,int,SysMemoryUnmap,8,(DWORD address,DWORD length)); 
    3030 
  • Whitix/trunk/user/linker/Makefile

    r7 r9  
    1 CFLAGS = -Werror -Wall -nostdlib -ffreestanding -fno-omit-frame-pointer -fno-builtin -fPIC -I../libc/include -O2 -fno-stack-protector 
     1CFLAGS = -Werror -Wall -nostdlib -ffreestanding -fno-omit-frame-pointer -fno-builtin -fPIC -I../libc/include -I../librtl -O2 -fno-stack-protector 
    22 
    3 OBJS = main.o syscall.o relocate.o resolve.o load_lib.o hash.o 
     3OBJS = main.o relocate.o resolve.o load_lib.o hash.o 
    44 
    55.c.o: 
     
    77 
    88build: $(OBJS) 
    9         ld -shared --warn-common --warn-once -z combreloc -z relo -e _start -z now -Bsymbolic --export-dynamic --sort-common --discard-locals --discard-all --no-undefined $(OBJS) -o Linker.so 
     9        ld -shared --warn-common --warn-once -z combreloc -z relo -e _start -z now -Bsymbolic --export-dynamic --sort-common --discard-locals --discard-all --no-undefined $(OBJS) ../librtl/syscall.o -o Linker.so 
    1010        mv Linker.so Linker 
    1111 
  • Whitix/trunk/user/linker/hash.c

    r7 r9  
    6464} 
    6565 
    66 struct ElfResolve* DlAddHashTable(char* libName,unsigned long loadAddr,unsigned long* dynEntries,unsigned long dynAddr,unsigned long dynSize) 
     66struct ElfResolve* DlAddHashTable(const char* libName,unsigned long loadAddr,unsigned long* dynEntries,unsigned long dynAddr,unsigned long dynSize) 
    6767{ 
    6868        struct ElfResolve* entry; 
     
    8484 
    8585        entry->next=NULL; 
    86         entry->libName=link_strdup(libName); 
     86        entry->libName=link_strdup((char*)libName); 
    8787        entry->dynAddr=dynAddr; 
    8888        entry->loadAddr=loadAddr; 
  • Whitix/trunk/user/linker/hash.h

    r7 r9  
    44unsigned long DlElfHash(char* symName); 
    55unsigned long DlFindHash(char* symName); 
    6 struct ElfResolve* DlAddHashTable(char* libName,unsigned long loadAddr,unsigned long* dynEntries,unsigned long dynAddr,unsigned long dynSize); 
     6struct ElfResolve* DlAddHashTable(const char* libName,unsigned long loadAddr,unsigned long* dynEntries,unsigned long dynAddr,unsigned long dynSize); 
    77 
    88#endif 
  • Whitix/trunk/user/linker/lib.h

    r7 r9  
    22#define LIB_H 
    33 
    4 #include "syscalls.h" 
     4#include <syscalls.h> 
    55#include "elf.h" 
    66 
     
    3939} 
    4040 
    41 static inline void link_memcpy(char* dest,char* src,int size) 
     41static inline void link_memcpy(void* dest,void* src,int size) 
    4242{ 
     43        char* d=(char*)dest; 
     44        char* s=(char*)src; 
     45         
    4346        while (size--) 
    44                 *dest++=*src++; 
     47                *d++=*s++; 
    4548} 
    4649 
     
    5558static inline void link_puts(char* str) 
    5659{ 
    57         SysWrite(STDOUT,(BYTE*)str,link_strlen(str)); 
     60        SysWrite(STDOUT,str,link_strlen(str)); 
    5861} 
    5962 
     
    6568        link_memcpy(s,str,len); 
    6669        return s; 
     70} 
     71 
     72static inline void link_strcpy(char* dest,char* src) 
     73{ 
     74        while (*src) 
     75                *dest++=*src++; 
     76 
     77        *dest='\0'; 
    6778} 
    6879 
  • Whitix/trunk/user/linker/load_lib.c

    r7 r9  
    55#include "relocate.h" 
    66 
    7 void DlLoadProgramHeader(char* name,struct ElfProgHeader* header) 
    8 { 
    9         /* TODO: Write. Move from DlLoadElfLibrary. */ 
    10 } 
    11  
    12 struct ElfResolve* DlLoadElfLibrary(char* name) 
    13 { 
    14         /* Search different paths soon.. */ 
    15  
    16         int fd,i; 
     7void DlAddFilePath(char* out, char* directory, char* name) 
     8{ 
     9        /* Prepend a path to the filename. */ 
     10        link_strcpy(out,directory); 
     11        link_strcpy(out+link_strlen(directory),name); 
     12} 
     13 
     14/*********************************************************************** 
     15 * 
     16 * FUNCTION: DlLoadHeaders 
     17 * 
     18 * DESCRIPTION: Load an ELF executable's headers from a file descriptor. 
     19 * 
     20 * PARAMETERS: name - name of the library to be loaded. 
     21 *                         fileHeader - main ELF header. Return variable. 
     22 *                         progHeaders - program header array. Dynamically allocated 
     23 *                                                      and read in to. 
     24 * 
     25 * RETURNS: 0 if success, < 0 if failure, file descriptor if > 0. 
     26 * 
     27 ***********************************************************************/ 
     28 
     29int DlLoadHeaders(char* name,struct ElfHeader* fileHeader, struct ElfProgHeader** progHeaders) 
     30{ 
     31        char fileName[512]; 
     32        int     result,fd; 
     33 
     34        /* Search through library paths for the file. 
     35         * TODO: Add support for multiple path lookup. 
     36         */ 
     37        DlAddFilePath(fileName, "/System/Runtime/", name); 
     38 
     39        /* Open the library to read the headers and map in the sections later. */ 
     40        fd=SysOpen(fileName, _SYS_FILE_READ, 0); 
     41        if (fd < 0) 
     42                return fd; 
     43 
     44        /* Seek to the beginning of the file and read the file header. */ 
     45        SysSeek(fd,0,0); 
     46        result=SysRead(fd, fileHeader, sizeof(struct ElfHeader)); 
     47 
     48        if (result < 0) 
     49                return result; 
     50 
     51        /* Checks the ELF magic number, executable type and other sanity checks. */ 
     52        if (ElfHeaderCheck(fileHeader, ELF_TYPE_DYN)) 
     53                return -1; 
     54 
     55        /* Seek to the program header(s) file offset and read 'phEntries' number of entries, 
     56           dynamically allocating that number first. */ 
     57        *progHeaders = (struct ElfProgHeader*) Dl_malloc(sizeof(struct ElfProgHeader) * fileHeader->phEntries); 
     58        SysSeek(fd, fileHeader->phOffset, 0); 
     59        result=SysRead(fd, *progHeaders, sizeof(struct ElfProgHeader) * fileHeader->phEntries); 
     60 
     61        if (result < 0) 
     62                return result; 
     63 
     64        return fd; 
     65} 
     66 
     67struct ElfResolve* DlCheckLoadedModules(const char* name) 
     68{ 
    1769        struct ElfResolve* entry; 
    18         struct ElfHeader* header; 
    19         struct ElfProgHeader* pHeader; 
    20         Elf_Addr dynamicAddr=0; 
    21         unsigned long dynEntries[DT_NUM+1]; 
    22         char buffer[512]; 
    23         char* libName=name; 
    24  
    25         int picLib=1; 
    26  
    27         /* Use the buffer for filenames, then for the headers */ 
    28         link_memcpy(buffer,"/System/Runtime/",link_strlen("/System/Runtime/")); 
    29         i=link_strlen("/System/Runtime/"); 
    30         while (*name) 
    31                 buffer[i++]=*name++; 
    32  
    33         buffer[i]='\0'; 
    34  
    35         fd=SysOpen(buffer,FILE_READ,0); 
    36         if (fd < 0) 
    37         { 
    38                 link_puts("Could not find file"); 
    39                 return NULL; 
    40         } 
    41  
    42         /* Do device and vNode check? */ 
     70         
     71        /* TODO: Names may clash, so stat the filename and compare ids? */ 
    4372        for (entry=loadedModules; entry; entry=entry->next) 
    4473        { 
    45                 if (!link_strcmp(entry->libName,libName)) 
     74                if (!link_strcmp(entry->libName,name)) 
    4675                { 
    4776                        entry->refs++; 
    48                         SysClose(fd); 
    4977                        return entry; 
    5078                } 
    5179        } 
    52  
    53         /* Seek to start of file and read header. */ 
    54         SysSeek(fd,0,0); 
    55         if (SysRead(fd,(BYTE*)buffer,512) < 0) 
    56         { 
    57                 link_puts("Failed to read library header"); 
    58                 return NULL; 
    59         } 
    60  
    61         header=(struct ElfHeader*)buffer; 
    62  
    63         if (ElfHeaderCheck(header,ELF_TYPE_DYN)) 
    64         { 
    65                 link_puts("Not a valid ELF library"); 
    66                 return NULL; 
    67         } 
    68  
    69         pHeader=(struct ElfProgHeader*)(buffer+header->phOffset); 
    70  
    71         for (i=0; i<header->phEntries; i++) 
    72         { 
    73                 if (pHeader->type == PT_DYNAMIC && !dynamicAddr) 
     80         
     81        return NULL; 
     82} 
     83 
     84Elf_Addr DlGetDynamicAddress(struct ElfProgHeader* pHeaders, int numEntries, int* picLib) 
     85{ 
     86        int i; 
     87        Elf_Addr dynamicAddr=0; 
     88         
     89        for (i=0; i<numEntries; i++) 
     90        { 
     91                if (pHeaders[i].type == PT_DYNAMIC && !dynamicAddr) 
     92                        /* The dynamic section holds the ELF file's dynamic information address. */ 
     93                        dynamicAddr=pHeaders[i].vAddr; 
     94                else if (pHeaders[i].type == PT_LOAD && !i && pHeaders[i].vAddr > 0x1000000) 
     95                        /* Is it a position independent library? Most likely not. */ 
     96                                picLib=0; 
     97        } 
     98         
     99        return dynamicAddr; 
     100} 
     101 
     102int DlMapLibrarySections(struct ElfProgHeader* pHeaders, int numEntries, int fd, Elf_Addr dynamicAddr, int picLib, Elf_Addr* loadAddr) 
     103{ 
     104        Elf_Addr elfBss=0, mapAddr=0; 
     105        int i; 
     106         
     107        for (i=0; i<numEntries; i++) 
     108        { 
     109                if (pHeaders[i].type == PT_LOAD) 
    74110                { 
    75                         dynamicAddr=pHeader->vAddr; 
    76                 }else if (pHeader->type == PT_LOAD) 
    77                         /* Is it a position independent library? Most likely. */ 
    78                         if (!i && pHeader->vAddr > 0x1000000) 
    79                                 picLib=0; 
    80  
    81                 pHeader++; 
    82         } 
    83  
    84         if (!dynamicAddr) 
    85         { 
    86                 link_puts("Library missing a dynamic section"); 
    87                 return NULL; 
    88         } 
    89  
    90         /* Now map sections into memory. */ 
    91         pHeader=(struct ElfProgHeader*)(buffer+header->phOffset); 
    92  
    93         DWORD loadAddr=0,mapAddr; 
    94         DWORD elfBss=0; 
    95  
    96         for (i=0; i<header->phEntries; i++) 
    97         { 
    98                 if (pHeader->type == PT_LOAD) 
    99                 { 
    100                         int mmapFlags=MMAP_PRIVATE; 
    101                         int elfProt=5; 
    102                         if (pHeader->segFlags & 2) 
     111                        /* Set permissions. */ 
     112                        int mmapFlags=_SYS_MMAP_PRIVATE; 
     113                        int elfProt=5; /* Document ... */ 
     114                        if (pHeaders[i].segFlags & 2) 
    103115                                elfProt|=2; 
    104116 
    105117                        if (loadAddr || !picLib) 
    106                                 mmapFlags|=MMAP_FIXED; 
    107  
    108                         pHeader->vAddr+=loadAddr; 
    109  
    110                         mapAddr=SysMemoryMap(PAGE_ALIGN(pHeader->vAddr),pHeader->fileSize+(pHeader->vAddr & 0xFFF),elfProt,fd,pHeader->fileOffset-(pHeader->vAddr & 0xFFF),mmapFlags); 
     118                                mmapFlags|=_SYS_MMAP_FIXED; 
     119 
     120                        /* 
     121                         * loadAddr will be zero on the first iteration, so we can 
     122                         * find out where the section has been mapped to, if it is 
     123                         * PIC library. 
     124                         */ 
     125                        pHeaders[i].vAddr+=*loadAddr; 
     126 
     127                        mapAddr=SysMemoryMap(PAGE_ALIGN(pHeaders[i].vAddr),                                             /* Start address. */ 
     128                                                                 pHeaders[i].fileSize+PAGE_OFFSET(pHeaders[i].vAddr),   /* Size */ 
     129                                                                 elfProt,                                                                                               /* Protection */ 
     130                                                                 fd,                                                                                                    /* Backing file */ 
     131                                                                 pHeaders[i].fileOffset-PAGE_OFFSET(pHeaders[i].vAddr),  /* File offset */ 
     132                                                                 mmapFlags);                                                                                    /* Flags */ 
    111133 
    112134                        if (!mapAddr) 
    113135                        { 
    114                                 link_puts("Failed to map section of shared library"); 
    115                                 return NULL; 
     136                                link_puts("Failed to map section of shared library\n"); 
     137                                return -1; 
    116138                        } 
    117139 
    118                         if (!loadAddr) 
    119                                 loadAddr=mapAddr-(pHeader->vAddr & 0xFFF); 
    120  
    121                         if (elfBss < pHeader->vAddr+pHeader->fileSize) 
    122                                 elfBss=pHeader->vAddr+pHeader->fileSize; 
    123  
    124                         if (pHeader->memSize > pHeader->fileSize) 
     140                        if (!*loadAddr) 
     141                                *loadAddr=mapAddr-PAGE_OFFSET(pHeaders[i].vAddr); 
     142 
     143                        if (elfBss < pHeaders[i].vAddr+pHeaders[i].fileSize) 
     144                                elfBss=pHeaders[i].vAddr+pHeaders[i].fileSize; 
     145 
     146                        if (pHeaders[i].memSize > pHeaders[i].fileSize) 
    125147                        { 
    126                                 DWORD bssSize=PAGE_ALIGN(pHeader->memSize-pHeader->fileSize); 
    127                                 DWORD pageAddr=PAGE_ALIGN_UP(pHeader->vAddr+pHeader->fileSize); 
    128                                 if (bssSize) SysMemoryMap(pageAddr,bssSize,7,-1,0,MMAP_PRIVATE | MMAP_FIXED); 
    129  
    130                                 if (elfBss & 0xFFF) 
     148                                DWORD bssSize=PAGE_ALIGN(pHeaders[i].memSize-pHeaders[i].fileSize); 
     149                                DWORD pageAddr=PAGE_ALIGN_UP(pHeaders[i].vAddr+pHeaders[i].fileSize); 
     150                                if (bssSize) 
     151                                        SysMemoryMap(pageAddr,bssSize,7,-1,0,_SYS_MMAP_PRIVATE | _SYS_MMAP_FIXED); 
     152 
     153                                /* Zero out the bss. */ 
     154                                if (PAGE_OFFSET(elfBss) > 0) 
    131155                                { 
    132                                         DWORD partSize=(pHeader->memSize-pHeader->fileSize) & 0xFFF; 
    133                                         link_memset((char*)(pHeader->vAddr+pHeader->fileSize),0,partSize); 
    134          
     156                                        DWORD partSize=PAGE_OFFSET(pHeaders[i].memSize-pHeaders[i].fileSize); 
     157                                        link_memset((void*)(pHeaders[i].vAddr+pHeaders[i].fileSize), 0, partSize); 
    135158                                } 
    136159                        } 
    137160                } 
    138  
    139                 pHeader++; 
    140         } 
    141  
    142         if (!loadAddr) 
    143         { 
    144                 link_puts("No load addr!\n"); 
    145                 SysExit(0); 
    146         } 
    147  
    148         SysClose(fd); 
    149  
    150         if (picLib) 
    151                 dynamicAddr+=loadAddr; 
    152  
    153         /* Parse dynamic entries */ 
    154         ElfParseDynInfo((struct ElfDyn*)dynamicAddr,dynEntries,loadAddr); 
    155  
    156         if (dynEntries[DT_TEXTREL]) 
    157         { 
    158                 link_puts("Todo: make pages writeable"); 
    159                 SysExit(0); 
    160         } 
    161  
    162         entry=DlAddHashTable(libName,loadAddr,dynEntries,dynamicAddr,0); 
    163  
    164         /* Fill in the rest of the ElfResolve structure */ 
    165         entry->pHeaders=(struct ElfProgHeader*)(buffer+header->phOffset); 
    166         entry->phNum=header->phEntries; 
    167  
    168         /* Move to separate function */ 
     161        } 
     162         
     163        return 0; 
     164} 
     165 
     166void DlUpdateSymbolTables(struct ElfResolve* entry) 
     167{ 
    169168        struct ElfSymResolve* symEntry=symbolTables; 
    170169 
    171         /* Add at end of list. */ 
     170        /* Get to the end of the list ...*/ 
    172171        while (symEntry->next) 
    173172                symEntry=symEntry->next; 
    174173         
     174        /* and add it there. */ 
    175175        symEntry->next=(struct ElfSymResolve*)Dl_malloc(sizeof(struct ElfSymResolve)); 
    176176        symEntry->next->prev=symEntry; 
    177177        symEntry=symEntry->next; 
    178178        symEntry->resolveEntry=entry; 
    179  
    180  
     179} 
     180 
     181struct ElfResolve* DlCreateResolveEntry(const char* name, struct ElfProgHeader* pHeaders, int phEntries, Elf_Addr loadAddr, Elf_Addr dynamicAddr, unsigned long* dynEntries) 
     182{ 
     183        struct ElfResolve* entry=DlAddHashTable(name, loadAddr, dynEntries, dynamicAddr, 0); 
     184 
     185        /* Fill in the rest of the ElfResolve structure */ 
     186        entry->pHeaders=pHeaders; 
     187        entry->phNum=phEntries; 
     188 
     189        /* Add it for symbol lookup. */ 
     190        DlUpdateSymbolTables(entry); 
     191         
     192        return entry; 
     193} 
     194 
     195struct ElfResolve* DlLoadElfLibrary(char* name) 
     196{ 
     197        int fd; 
     198        struct ElfResolve* entry; 
     199        struct ElfHeader fileHeader; 
     200        struct ElfProgHeader* pHeaders; /* Should we malloc this? */ 
     201        Elf_Addr dynamicAddr=0, loadAddr=0; 
     202        unsigned long dynEntries[DT_NUM+1]; 
     203        int picLib=1; 
     204 
     205        /* Check if we've loaded this library into memory already. */ 
     206        entry=DlCheckLoadedModules(name); 
     207         
     208        if (entry) 
     209                return entry; 
     210 
     211        /* Get the library's headers. */ 
     212        fd=DlLoadHeaders(name,&fileHeader,&pHeaders); 
     213 
     214        if (fd < 0) 
     215                return NULL; 
     216 
     217        /* Get the library's dynamic information address. We also figure out whether the library 
     218         * has position independent code from here. 
     219         */ 
     220        dynamicAddr=DlGetDynamicAddress(pHeaders, fileHeader.phEntries, &picLib); 
     221         
     222        if (!dynamicAddr) 
     223        { 
     224                link_puts("Library missing a dynamic section"); 
     225                return NULL; 
     226        } 
     227         
     228        /* Now map in the sections themselves. */ 
     229        DlMapLibrarySections(pHeaders, fileHeader.phEntries, fd, dynamicAddr, picLib, &loadAddr); 
     230 
     231        /* TODO: Check for errors.. */ 
     232        if (!loadAddr) 
     233        { 
     234                link_puts("No load addr!\n"); 
     235                SysExit(0); 
     236        } 
     237 
     238        /* Close the file descriptor we used for mapping the sections in. */ 
     239        SysClose(fd); 
     240 
     241        if (picLib) 
     242                dynamicAddr+=loadAddr; 
     243 
     244        /* Parse dynamic entries. Reads the contents at dynamicAddr into dynEntries. */ 
     245        ElfParseDynInfo((struct ElfDyn*)dynamicAddr,dynEntries,loadAddr); 
     246 
     247        if (dynEntries[DT_TEXTREL]) 
     248        { 
     249                link_puts("Todo: make pages writeable"); 
     250                SysExit(0); 
     251