| 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; |
| | 7 | void 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 | |
| | 29 | int 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 | |
| | 67 | struct ElfResolve* DlCheckLoadedModules(const char* name) |
| | 68 | { |
| 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? */ |
| 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 | |
| | 84 | Elf_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 | |
| | 102 | int 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) |
| 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) |
| 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 */ |
| 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) |
| 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 | |
| | 166 | void DlUpdateSymbolTables(struct ElfResolve* entry) |
| | 167 | { |
| 179 | | |
| 180 | | |
| | 179 | } |
| | 180 | |
| | 181 | struct 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 | |
| | 195 | struct 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 | |