1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "Dll.hpp" 16 17 #include <time.h> 18 19 #ifndef IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 20 #define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 21 #endif 22 23 #ifndef IMAGE_DLLCHARACTERISTICS_NX_COMPAT 24 #define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 25 #endif 26 27 namespace sw 28 { 29 #ifdef _M_AMD64 30 const bool AMD64 = true; 31 #else 32 const bool AMD64 = false; 33 #endif 34 DLL(const char * name,const void * constants,int constSize)35 DLL::DLL(const char *name, const void *constants, int constSize) : constants(constants), constSize(constSize) 36 { 37 dllName = new char[strlen(name) + 1]; 38 strcpy(dllName, name); 39 40 codeSize = 0; 41 } 42 ~DLL()43 DLL::~DLL() 44 { 45 delete[] dllName; 46 47 for(FunctionList::iterator i = functionList.begin(); i != functionList.end(); i++) 48 { 49 delete i->second; 50 } 51 } 52 addFunction(const void * function,const void * entry,int size)53 void DLL::addFunction(const void *function, const void *entry, int size) 54 { 55 functionOrder.push_back(function); 56 functionList[function] = new Function(codeSize, function, entry, size); 57 58 codeSize += size; 59 } 60 addRelocation(const void * function,const void * address,bool ripRelative)61 void DLL::addRelocation(const void *function, const void *address, bool ripRelative) 62 { 63 globalRelocations[function].push_back(Relocation((unsigned int)((unsigned char*)address - (unsigned char*)function), ripRelative)); 64 } 65 emit()66 void DLL::emit() 67 { 68 if(codeSize == 0) 69 { 70 return; 71 } 72 73 for(GlobalRelocations::iterator i = globalRelocations.begin(); i != globalRelocations.end(); i++) 74 { 75 const unsigned char *function = (const unsigned char*)i->first; 76 const std::vector<Relocation> &functionRelocations = i->second; 77 unsigned int location = functionList[function]->location; 78 79 for(unsigned int j = 0; j < functionRelocations.size(); j++) 80 { 81 unsigned int address = location + functionRelocations[j].offset; 82 unsigned int page = address / 0x1000; 83 unsigned short reloc = address - page * 0x1000; 84 85 unsigned int relocType = AMD64 ? IMAGE_REL_BASED_DIR64 : IMAGE_REL_BASED_HIGHLOW; 86 pageRelocations[page].push_back((relocType << 12) | reloc); 87 } 88 } 89 90 if(pageRelocations.empty()) 91 { 92 pageRelocations[0]; // Initialize an emtpy list 93 } 94 95 int relocSize = 0; 96 97 for(PageRelocations::iterator i = pageRelocations.begin(); i != pageRelocations.end(); i++) 98 { 99 if(i->second.size() % 2) // Pad to align to DWORD 100 { 101 i->second.push_back(0); 102 } 103 104 relocSize += (int)sizeof(IMAGE_BASE_RELOCATION) + (int)i->second.size() * (int)sizeof(unsigned short); 105 } 106 107 unsigned long timeDateStamp = (unsigned long)time(0); 108 109 memset(&DOSheader, 0, sizeof(DOSheader)); 110 DOSheader.e_magic = IMAGE_DOS_SIGNATURE; // "MZ" 111 DOSheader.e_lfanew = sizeof(DOSheader); 112 113 int base = 0x10000000; 114 int codePage = pageAlign(sizeof(DOSheader) + (AMD64 ? sizeof(COFFheader64) : sizeof(COFFheader32))); 115 int exportsPage = codePage + pageAlign(codeSize); 116 int exportsSize = (int)(sizeof(IMAGE_EXPORT_DIRECTORY) + functionList.size() * sizeof(void*) + (strlen(dllName) + 1)); 117 int relocPage = exportsPage + pageAlign(exportsSize); 118 int constPage = relocPage + pageAlign(relocSize); 119 120 if(!AMD64) 121 { 122 memset(&COFFheader32, 0, sizeof(COFFheader32)); 123 COFFheader32.Signature = IMAGE_NT_SIGNATURE; // "PE" 124 COFFheader32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; 125 COFFheader32.FileHeader.NumberOfSections = 4; 126 COFFheader32.FileHeader.TimeDateStamp = timeDateStamp; 127 COFFheader32.FileHeader.PointerToSymbolTable = 0; // Deprecated COFF symbol table 128 COFFheader32.FileHeader.NumberOfSymbols = 0; 129 COFFheader32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32); 130 COFFheader32.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | 131 IMAGE_FILE_32BIT_MACHINE | 132 IMAGE_FILE_DLL; 133 134 COFFheader32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; 135 COFFheader32.OptionalHeader.MajorLinkerVersion = 8; 136 COFFheader32.OptionalHeader.MinorLinkerVersion = 0; 137 COFFheader32.OptionalHeader.SizeOfCode = fileAlign(codeSize); 138 COFFheader32.OptionalHeader.SizeOfInitializedData = fileAlign(exportsSize) + fileAlign(relocSize) + fileAlign(constSize); 139 COFFheader32.OptionalHeader.SizeOfUninitializedData = 0; 140 COFFheader32.OptionalHeader.AddressOfEntryPoint = 0; 141 COFFheader32.OptionalHeader.BaseOfCode = codePage; 142 COFFheader32.OptionalHeader.BaseOfData = exportsPage; 143 144 COFFheader32.OptionalHeader.ImageBase = base; 145 COFFheader32.OptionalHeader.SectionAlignment = 0x1000; 146 COFFheader32.OptionalHeader.FileAlignment = 0x200; 147 COFFheader32.OptionalHeader.MajorOperatingSystemVersion = 4; 148 COFFheader32.OptionalHeader.MinorOperatingSystemVersion = 0; 149 COFFheader32.OptionalHeader.MajorImageVersion = 0; 150 COFFheader32.OptionalHeader.MinorImageVersion = 0; 151 COFFheader32.OptionalHeader.MajorSubsystemVersion = 4; 152 COFFheader32.OptionalHeader.MinorSubsystemVersion = 0; 153 COFFheader32.OptionalHeader.Win32VersionValue = 0; 154 COFFheader32.OptionalHeader.SizeOfImage = constPage + pageAlign(constSize); 155 COFFheader32.OptionalHeader.SizeOfHeaders = fileAlign(sizeof(DOSheader) + sizeof(COFFheader32)); 156 COFFheader32.OptionalHeader.CheckSum = 0; 157 COFFheader32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; 158 COFFheader32.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NO_SEH | 159 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | // Base address randomization 160 IMAGE_DLLCHARACTERISTICS_NX_COMPAT; // Data Execution Prevention compatible 161 COFFheader32.OptionalHeader.SizeOfStackReserve = 1024 * 1024; 162 COFFheader32.OptionalHeader.SizeOfStackCommit = 4 * 1024; 163 COFFheader32.OptionalHeader.SizeOfHeapReserve = 1024 * 1024; 164 COFFheader32.OptionalHeader.SizeOfHeapCommit = 4 * 1024; 165 COFFheader32.OptionalHeader.LoaderFlags = 0; 166 COFFheader32.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; 167 168 COFFheader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = exportsPage; 169 COFFheader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = exportsSize; 170 171 COFFheader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = relocPage; 172 COFFheader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = relocSize; 173 } 174 else 175 { 176 memset(&COFFheader64, 0, sizeof(COFFheader64)); 177 COFFheader64.Signature = IMAGE_NT_SIGNATURE; // "PE" 178 COFFheader64.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; 179 COFFheader64.FileHeader.NumberOfSections = 4; 180 COFFheader64.FileHeader.TimeDateStamp = timeDateStamp; 181 COFFheader64.FileHeader.PointerToSymbolTable = 0; // Deprecated COFF symbol table 182 COFFheader64.FileHeader.NumberOfSymbols = 0; 183 COFFheader64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64); 184 COFFheader64.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | 185 IMAGE_FILE_LARGE_ADDRESS_AWARE | 186 IMAGE_FILE_DLL; 187 188 COFFheader64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; 189 COFFheader64.OptionalHeader.MajorLinkerVersion = 8; 190 COFFheader64.OptionalHeader.MinorLinkerVersion = 0; 191 COFFheader64.OptionalHeader.SizeOfCode = fileAlign(codeSize); 192 COFFheader64.OptionalHeader.SizeOfInitializedData = fileAlign(exportsSize) + fileAlign(relocSize) + fileAlign(constSize); 193 COFFheader64.OptionalHeader.SizeOfUninitializedData = 0; 194 COFFheader64.OptionalHeader.AddressOfEntryPoint = 0; 195 COFFheader64.OptionalHeader.BaseOfCode = codePage; 196 197 COFFheader64.OptionalHeader.ImageBase = base; 198 COFFheader64.OptionalHeader.SectionAlignment = 0x1000; 199 COFFheader64.OptionalHeader.FileAlignment = 0x200; 200 COFFheader64.OptionalHeader.MajorOperatingSystemVersion = 4; 201 COFFheader64.OptionalHeader.MinorOperatingSystemVersion = 0; 202 COFFheader64.OptionalHeader.MajorImageVersion = 0; 203 COFFheader64.OptionalHeader.MinorImageVersion = 0; 204 COFFheader64.OptionalHeader.MajorSubsystemVersion = 4; 205 COFFheader64.OptionalHeader.MinorSubsystemVersion = 0; 206 COFFheader64.OptionalHeader.Win32VersionValue = 0; 207 COFFheader64.OptionalHeader.SizeOfImage = constPage + pageAlign(constSize); 208 COFFheader64.OptionalHeader.SizeOfHeaders = fileAlign(sizeof(DOSheader) + sizeof(COFFheader64)); 209 COFFheader64.OptionalHeader.CheckSum = 0; 210 COFFheader64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; 211 COFFheader64.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NO_SEH | 212 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | // Base address randomization 213 IMAGE_DLLCHARACTERISTICS_NX_COMPAT; // Data Execution Prevention compatible 214 COFFheader64.OptionalHeader.SizeOfStackReserve = 1024 * 1024; 215 COFFheader64.OptionalHeader.SizeOfStackCommit = 4 * 1024; 216 COFFheader64.OptionalHeader.SizeOfHeapReserve = 1024 * 1024; 217 COFFheader64.OptionalHeader.SizeOfHeapCommit = 4 * 1024; 218 COFFheader64.OptionalHeader.LoaderFlags = 0; 219 COFFheader64.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; 220 221 COFFheader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = exportsPage; 222 COFFheader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = exportsSize; 223 224 COFFheader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = relocPage; 225 COFFheader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = relocSize; 226 } 227 228 memset(&textSection, 0, sizeof(textSection)); 229 strcpy((char*)&textSection.Name, ".text"); 230 textSection.Misc.VirtualSize = pageAlign(codeSize); 231 textSection.VirtualAddress = codePage; 232 textSection.SizeOfRawData = fileAlign(codeSize); 233 textSection.PointerToRawData = fileAlign(sizeof(DOSheader) + (AMD64 ? sizeof(COFFheader64) : sizeof(COFFheader32))); 234 textSection.PointerToRelocations = 0; 235 textSection.PointerToLinenumbers = 0; 236 textSection.NumberOfRelocations = 0; 237 textSection.NumberOfLinenumbers = 0; 238 textSection.Characteristics = IMAGE_SCN_CNT_CODE | 239 IMAGE_SCN_MEM_EXECUTE | 240 IMAGE_SCN_MEM_READ; 241 242 memset(&exportsSection, 0, sizeof(exportsSection)); 243 strcpy((char*)&exportsSection.Name, ".edata"); 244 exportsSection.Misc.VirtualSize = pageAlign(exportsSize); 245 exportsSection.VirtualAddress = exportsPage; 246 exportsSection.SizeOfRawData = fileAlign(exportsSize); 247 exportsSection.PointerToRawData = textSection.PointerToRawData + fileAlign(codeSize); 248 exportsSection.PointerToRelocations = 0; 249 exportsSection.PointerToLinenumbers = 0; 250 exportsSection.NumberOfRelocations = 0; 251 exportsSection.NumberOfLinenumbers = 0; 252 exportsSection.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | 253 IMAGE_SCN_MEM_READ; 254 255 memset(&relocSection, 0, sizeof(relocSection)); 256 strcpy((char*)&relocSection.Name, ".reloc"); 257 relocSection.Misc.VirtualSize = pageAlign(relocSize); 258 relocSection.VirtualAddress = relocPage; 259 relocSection.SizeOfRawData = fileAlign(relocSize); 260 relocSection.PointerToRawData = exportsSection.PointerToRawData + fileAlign(exportsSize); 261 relocSection.PointerToRelocations = 0; 262 relocSection.PointerToLinenumbers = 0; 263 relocSection.NumberOfRelocations = 0; 264 relocSection.NumberOfLinenumbers = 0; 265 relocSection.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | 266 IMAGE_SCN_MEM_DISCARDABLE | 267 IMAGE_SCN_MEM_READ; 268 269 memset(&constSection, 0, sizeof(constSection)); 270 strcpy((char*)&constSection.Name, ".rdata"); 271 constSection.Misc.VirtualSize = pageAlign(constSize); 272 constSection.VirtualAddress = constPage; 273 constSection.SizeOfRawData = fileAlign(constSize); 274 constSection.PointerToRawData = relocSection.PointerToRawData + fileAlign(relocSize); 275 constSection.PointerToRelocations = 0; 276 constSection.PointerToLinenumbers = 0; 277 constSection.NumberOfRelocations = 0; 278 constSection.NumberOfLinenumbers = 0; 279 constSection.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | 280 IMAGE_SCN_MEM_READ; 281 282 memset(&exportDirectory, 0, sizeof(exportDirectory)); 283 exportDirectory.Characteristics = 0; 284 exportDirectory.TimeDateStamp = timeDateStamp; 285 exportDirectory.MajorVersion = 0; 286 exportDirectory.MinorVersion = 0; 287 exportDirectory.Name = (unsigned long)(exportsPage + sizeof(IMAGE_EXPORT_DIRECTORY) + functionList.size() * sizeof(void*)); 288 exportDirectory.Base = 1; 289 exportDirectory.NumberOfFunctions = (unsigned long)functionList.size(); 290 exportDirectory.NumberOfNames = 0; 291 exportDirectory.AddressOfFunctions = exportsPage + sizeof(IMAGE_EXPORT_DIRECTORY); 292 exportDirectory.AddressOfNames = 0; 293 exportDirectory.AddressOfNameOrdinals = 0; 294 295 FILE *file = fopen(dllName, "wb"); 296 297 if(file) 298 { 299 fwrite(&DOSheader, 1, sizeof(DOSheader), file); 300 301 if(AMD64) 302 { 303 fwrite(&COFFheader64, 1, sizeof(COFFheader64), file); 304 } 305 else 306 { 307 fwrite(&COFFheader32, 1, sizeof(COFFheader32), file); 308 } 309 310 fwrite(&textSection, 1, sizeof(textSection), file); 311 fwrite(&exportsSection, 1, sizeof(textSection), file); 312 fwrite(&relocSection, 1, sizeof(relocSection), file); 313 fwrite(&constSection, 1, sizeof(constSection), file); 314 315 for(FunctionList::iterator i = functionList.begin(); i != functionList.end(); i++) 316 { 317 const void *function = i->first; 318 unsigned int location = i->second->location; 319 const std::vector<Relocation> &functionRelocations = globalRelocations[function]; 320 321 for(unsigned int j = 0; j < functionRelocations.size(); j++) 322 { 323 unsigned int *address = (unsigned int*)((unsigned char*)i->second->buffer + functionRelocations[j].offset); 324 325 if(functionRelocations[j].ripRelative) 326 { 327 *address = base + codePage + location + (*address - (unsigned int)(size_t)function); 328 } 329 else 330 { 331 *address = base + constPage + (*address - (unsigned int)(size_t)constants); 332 } 333 } 334 335 fseek(file, textSection.PointerToRawData + location, SEEK_SET); 336 fwrite(i->second->buffer, 1, i->second->size, file); 337 } 338 339 fseek(file, exportsSection.PointerToRawData, SEEK_SET); 340 fwrite(&exportDirectory, 1, sizeof(exportDirectory), file); 341 342 for(unsigned int i = 0; i < functionOrder.size(); i++) 343 { 344 const void *buffer = functionOrder[i]; 345 Function *function = functionList[buffer]; 346 347 unsigned int functionAddress = codePage + function->location; 348 unsigned int functionEntry = functionAddress + (int)((size_t)function->entry - (size_t)buffer); 349 fwrite(&functionEntry, 1, sizeof(functionEntry), file); 350 } 351 352 fwrite(dllName, 1, strlen(dllName) + 1, file); 353 354 fseek(file, relocSection.PointerToRawData, SEEK_SET); 355 356 for(PageRelocations::iterator i = pageRelocations.begin(); i != pageRelocations.end(); i++) 357 { 358 IMAGE_BASE_RELOCATION relocationBlock; 359 360 relocationBlock.VirtualAddress = codePage + i->first * 0x1000; 361 relocationBlock.SizeOfBlock = (unsigned long)(sizeof(IMAGE_BASE_RELOCATION) + i->second.size() * sizeof(unsigned short)); 362 363 fwrite(&relocationBlock, 1, sizeof(IMAGE_BASE_RELOCATION), file); 364 365 if(i->second.size() > 0) 366 { 367 fwrite(&i->second[0], 1, i->second.size() * sizeof(unsigned short), file); 368 } 369 } 370 371 fseek(file, constSection.PointerToRawData, SEEK_SET); 372 fwrite(constants, 1, constSize, file); 373 374 char *padding = new char[fileAlign(constSize) - constSize]; 375 fwrite(padding, 1, fileAlign(constSize) - constSize, file); 376 delete[] padding; 377 378 fclose(file); 379 } 380 } 381 } 382