1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _libomf.d) 9 */ 10 11 module ddmd.libomf; 12 13 import core.stdc.stdio; 14 import core.stdc..string; 15 import core.stdc.stdlib; 16 17 import ddmd.globals; 18 import ddmd.utils; 19 import ddmd.lib; 20 21 import ddmd.root.array; 22 import ddmd.root.file; 23 import ddmd.root.filename; 24 import ddmd.root.outbuffer; 25 import ddmd.root.stringtable; 26 27 import ddmd.scanomf; 28 29 enum LOG = false; 30 31 struct OmfObjSymbol 32 { 33 char* name; 34 OmfObjModule* om; 35 } 36 37 alias OmfObjModules = Array!(OmfObjModule*); 38 alias OmfObjSymbols = Array!(OmfObjSymbol*); 39 40 extern (C) uint _rotl(uint value, int shift); 41 extern (C) uint _rotr(uint value, int shift); 42 43 final class LibOMF : Library 44 { 45 OmfObjModules objmodules; // OmfObjModule[] 46 OmfObjSymbols objsymbols; // OmfObjSymbol[] 47 StringTable tab; 48 49 extern (D) this() 50 { 51 tab._init(14000); 52 } 53 54 /*************************************** 55 * Add object module or library to the library. 56 * Examine the buffer to see which it is. 57 * If the buffer is NULL, use module_name as the file name 58 * and load the file. 59 */ 60 override void addObject(const(char)* module_name, const ubyte[] buffer) 61 { 62 static if (LOG) 63 { 64 printf("LibOMF::addObject(%s)\n", module_name ? module_name : ""); 65 } 66 67 void corrupt(int reason) 68 { 69 error("corrupt OMF object module %s %d", module_name, reason); 70 } 71 72 auto buf = buffer.ptr; 73 auto buflen = buffer.length; 74 if (!buf) 75 { 76 assert(module_name); 77 File* file = File.create(cast(char*)module_name); 78 readFile(Loc(), file); 79 buf = file.buffer; 80 buflen = file.len; 81 file._ref = 1; 82 } 83 uint g_page_size; 84 ubyte* pstart = cast(ubyte*)buf; 85 bool islibrary = false; 86 /* See if it's an OMF library. 87 * Don't go by file extension. 88 */ 89 struct LibHeader 90 { 91 align(1): 92 ubyte recTyp; // 0xF0 93 ushort pagesize; 94 uint lSymSeek; 95 ushort ndicpages; 96 } 97 98 /* Determine if it is an OMF library, an OMF object module, 99 * or something else. 100 */ 101 if (buflen < (LibHeader).sizeof) 102 return corrupt(__LINE__); 103 const lh = cast(const(LibHeader)*)buf; 104 if (lh.recTyp == 0xF0) 105 { 106 /* OMF library 107 * The modules are all at buf[g_page_size .. lh->lSymSeek] 108 */ 109 islibrary = 1; 110 g_page_size = lh.pagesize + 3; 111 buf = cast(ubyte*)(pstart + g_page_size); 112 if (lh.lSymSeek > buflen || g_page_size > buflen) 113 return corrupt(__LINE__); 114 buflen = lh.lSymSeek - g_page_size; 115 } 116 else if (lh.recTyp == '!' && memcmp(lh, cast(char*)"!<arch>\n", 8) == 0) 117 { 118 error("COFF libraries not supported"); 119 return; 120 } 121 else 122 { 123 // Not a library, assume OMF object module 124 g_page_size = 16; 125 } 126 bool firstmodule = true; 127 128 void addOmfObjModule(char* name, void* base, size_t length) 129 { 130 auto om = new OmfObjModule(); 131 om.base = cast(ubyte*)base; 132 om.page = om.page = cast(ushort)((om.base - pstart) / g_page_size); 133 om.length = cast(uint)length; 134 /* Determine the name of the module 135 */ 136 if (firstmodule && module_name && !islibrary) 137 { 138 // Remove path and extension 139 auto n = strdup(FileName.name(module_name)); 140 om.name = n[0 .. strlen(n)]; 141 char* ext = cast(char*)FileName.ext(n); 142 if (ext) 143 ext[-1] = 0; 144 } 145 else 146 { 147 /* Use THEADR name as module name, 148 * removing path and extension. 149 */ 150 auto n = strdup(FileName.name(name)); 151 om.name = n[0 .. strlen(n)]; 152 char* ext = cast(char*)FileName.ext(n); 153 if (ext) 154 ext[-1] = 0; 155 } 156 firstmodule = false; 157 this.objmodules.push(om); 158 } 159 160 if (scanOmfLib(&addOmfObjModule, cast(void*)buf, buflen, g_page_size)) 161 return corrupt(__LINE__); 162 } 163 164 /*****************************************************************************/ 165 166 void addSymbol(OmfObjModule* om, const(char)* name, int pickAny = 0) 167 { 168 static if (LOG) 169 { 170 printf("LibOMF::addSymbol(%s, %s, %d)\n", om.name.ptr, name, pickAny); 171 } 172 const namelen = strlen(name); 173 StringValue* s = tab.insert(name, namelen, null); 174 if (!s) 175 { 176 // already in table 177 if (!pickAny) 178 { 179 const s2 = tab.lookup(name, namelen); 180 assert(s2); 181 const os = cast(const(OmfObjSymbol)*)s2.ptrvalue; 182 error("multiple definition of %s: %s and %s: %s", om.name.ptr, name, os.om.name.ptr, os.name); 183 } 184 } 185 else 186 { 187 auto os = new OmfObjSymbol(); 188 os.name = strdup(name); 189 os.om = om; 190 s.ptrvalue = cast(void*)os; 191 objsymbols.push(os); 192 } 193 } 194 195 private: 196 /************************************ 197 * Scan single object module for dictionary symbols. 198 * Send those symbols to LibOMF::addSymbol(). 199 */ 200 void scanObjModule(OmfObjModule* om) 201 { 202 static if (LOG) 203 { 204 printf("LibMSCoff::scanObjModule(%s)\n", om.name.ptr); 205 } 206 207 extern (D) void addSymbol(const(char)[] name, int pickAny) 208 { 209 this.addSymbol(om, name.ptr, pickAny); 210 } 211 212 scanOmfObjModule(&addSymbol, om.base[0 .. om.length], om.name.ptr, loc); 213 } 214 215 /*********************************** 216 * Calculates number of pages needed for dictionary 217 * Returns: 218 * number of pages 219 */ 220 ushort numDictPages(uint padding) 221 { 222 ushort ndicpages; 223 ushort bucksForHash; 224 ushort bucksForSize; 225 uint symSize = 0; 226 for (size_t i = 0; i < objsymbols.dim; i++) 227 { 228 OmfObjSymbol* s = objsymbols[i]; 229 symSize += (strlen(s.name) + 4) & ~1; 230 } 231 for (size_t i = 0; i < objmodules.dim; i++) 232 { 233 OmfObjModule* om = objmodules[i]; 234 size_t len = om.name.length; 235 if (len > 0xFF) 236 len += 2; // Digital Mars long name extension 237 symSize += (len + 4 + 1) & ~1; 238 } 239 bucksForHash = cast(ushort)((objsymbols.dim + objmodules.dim + HASHMOD - 3) / (HASHMOD - 2)); 240 bucksForSize = cast(ushort)((symSize + BUCKETSIZE - padding - padding - 1) / (BUCKETSIZE - padding)); 241 ndicpages = (bucksForHash > bucksForSize) ? bucksForHash : bucksForSize; 242 //printf("ndicpages = %u\n",ndicpages); 243 // Find prime number greater than ndicpages 244 static __gshared uint* primes = 245 [ 246 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 247 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 248 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 249 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 250 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 251 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 252 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 253 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 254 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 255 //521,523,541,547, 256 0 257 ]; 258 for (size_t i = 0; 1; i++) 259 { 260 if (primes[i] == 0) 261 { 262 // Quick and easy way is out. 263 // Now try and find first prime number > ndicpages 264 uint prime; 265 for (prime = (ndicpages + 1) | 1; 1; prime += 2) 266 { 267 // Determine if prime is prime 268 for (uint u = 3; u < prime / 2; u += 2) 269 { 270 if ((prime / u) * u == prime) 271 goto L1; 272 } 273 break; 274 L1: 275 } 276 ndicpages = cast(ushort)prime; 277 break; 278 } 279 if (primes[i] > ndicpages) 280 { 281 ndicpages = cast(ushort)primes[i]; 282 break; 283 } 284 } 285 return ndicpages; 286 } 287 288 /******************************************* 289 * Write the module and symbol names to the dictionary. 290 * Returns: 291 * false failure 292 */ 293 bool FillDict(ubyte* bucketsP, ushort ndicpages) 294 { 295 // max size that will fit in dictionary 296 enum LIBIDMAX = (512 - 0x25 - 3 - 4); 297 ubyte[4 + LIBIDMAX + 2 + 1] entry; 298 //printf("FillDict()\n"); 299 // Add each of the module names 300 for (size_t i = 0; i < objmodules.dim; i++) 301 { 302 OmfObjModule* om = objmodules[i]; 303 ushort n = cast(ushort)om.name.length; 304 if (n > 255) 305 { 306 entry[0] = 0xFF; 307 entry[1] = 0; 308 *cast(ushort*)(entry.ptr + 2) = cast(ushort)(n + 1); 309 memcpy(entry.ptr + 4, om.name.ptr, n); 310 n += 3; 311 } 312 else 313 { 314 entry[0] = cast(ubyte)(1 + n); 315 memcpy(entry.ptr + 1, om.name.ptr, n); 316 } 317 entry[n + 1] = '!'; 318 *(cast(ushort*)(n + 2 + entry.ptr)) = om.page; 319 if (n & 1) 320 entry[n + 2 + 2] = 0; 321 if (!EnterDict(bucketsP, ndicpages, entry.ptr, n + 1)) 322 return false; 323 } 324 // Sort the symbols 325 qsort(objsymbols.tdata(), objsymbols.dim, (objsymbols[0]).sizeof, &NameCompare); 326 // Add each of the symbols 327 for (size_t i = 0; i < objsymbols.dim; i++) 328 { 329 OmfObjSymbol* os = objsymbols[i]; 330 ushort n = cast(ushort)strlen(os.name); 331 if (n > 255) 332 { 333 entry[0] = 0xFF; 334 entry[1] = 0; 335 *cast(ushort*)(entry.ptr + 2) = n; 336 memcpy(entry.ptr + 4, os.name, n); 337 n += 3; 338 } 339 else 340 { 341 entry[0] = cast(ubyte)n; 342 memcpy(entry.ptr + 1, os.name, n); 343 } 344 *(cast(ushort*)(n + 1 + entry.ptr)) = os.om.page; 345 if ((n & 1) == 0) 346 entry[n + 3] = 0; 347 if (!EnterDict(bucketsP, ndicpages, entry.ptr, n)) 348 { 349 return false; 350 } 351 } 352 return true; 353 } 354 355 /********************************************** 356 * Create and write library to libbuf. 357 * The library consists of: 358 * library header 359 * object modules... 360 * dictionary header 361 * dictionary pages... 362 */ 363 protected override void WriteLibToBuffer(OutBuffer* libbuf) 364 { 365 /* Scan each of the object modules for symbols 366 * to go into the dictionary 367 */ 368 for (size_t i = 0; i < objmodules.dim; i++) 369 { 370 OmfObjModule* om = objmodules[i]; 371 scanObjModule(om); 372 } 373 uint g_page_size = 16; 374 /* Calculate page size so that the number of pages 375 * fits in 16 bits. This is because object modules 376 * are indexed by page number, stored as an unsigned short. 377 */ 378 while (1) 379 { 380 Lagain: 381 static if (LOG) 382 { 383 printf("g_page_size = %d\n", g_page_size); 384 } 385 uint offset = g_page_size; 386 for (size_t i = 0; i < objmodules.dim; i++) 387 { 388 OmfObjModule* om = objmodules[i]; 389 uint page = offset / g_page_size; 390 if (page > 0xFFFF) 391 { 392 // Page size is too small, double it and try again 393 g_page_size *= 2; 394 goto Lagain; 395 } 396 offset += OMFObjSize(om.base, om.length, om.name.ptr); 397 // Round the size of the file up to the next page size 398 // by filling with 0s 399 uint n = (g_page_size - 1) & offset; 400 if (n) 401 offset += g_page_size - n; 402 } 403 break; 404 } 405 /* Leave one page of 0s at start as a dummy library header. 406 * Fill it in later with the real data. 407 */ 408 libbuf.fill0(g_page_size); 409 /* Write each object module into the library 410 */ 411 for (size_t i = 0; i < objmodules.dim; i++) 412 { 413 OmfObjModule* om = objmodules[i]; 414 uint page = cast(uint)(libbuf.offset / g_page_size); 415 assert(page <= 0xFFFF); 416 om.page = cast(ushort)page; 417 // Write out the object module om 418 writeOMFObj(libbuf, om.base, om.length, om.name.ptr); 419 // Round the size of the file up to the next page size 420 // by filling with 0s 421 uint n = (g_page_size - 1) & libbuf.offset; 422 if (n) 423 libbuf.fill0(g_page_size - n); 424 } 425 // File offset of start of dictionary 426 uint offset = cast(uint)libbuf.offset; 427 // Write dictionary header, then round it to a BUCKETPAGE boundary 428 ushort size = (BUCKETPAGE - (cast(short)offset + 3)) & (BUCKETPAGE - 1); 429 libbuf.writeByte(0xF1); 430 libbuf.writeword(size); 431 libbuf.fill0(size); 432 // Create dictionary 433 ubyte* bucketsP = null; 434 ushort ndicpages; 435 ushort padding = 32; 436 for (;;) 437 { 438 ndicpages = numDictPages(padding); 439 static if (LOG) 440 { 441 printf("ndicpages = %d\n", ndicpages); 442 } 443 // Allocate dictionary 444 if (bucketsP) 445 bucketsP = cast(ubyte*)realloc(bucketsP, ndicpages * BUCKETPAGE); 446 else 447 bucketsP = cast(ubyte*)malloc(ndicpages * BUCKETPAGE); 448 assert(bucketsP); 449 memset(bucketsP, 0, ndicpages * BUCKETPAGE); 450 for (uint u = 0; u < ndicpages; u++) 451 { 452 // 'next available' slot 453 bucketsP[u * BUCKETPAGE + HASHMOD] = (HASHMOD + 1) >> 1; 454 } 455 if (FillDict(bucketsP, ndicpages)) 456 break; 457 padding += 16; // try again with more margins 458 } 459 // Write dictionary 460 libbuf.write(bucketsP, ndicpages * BUCKETPAGE); 461 if (bucketsP) 462 free(bucketsP); 463 // Create library header 464 struct Libheader 465 { 466 align(1): 467 ubyte recTyp; 468 ushort recLen; 469 uint trailerPosn; 470 ushort ndicpages; 471 ubyte flags; 472 char* filler; 473 } 474 475 Libheader libHeader; 476 memset(&libHeader, 0, (Libheader).sizeof); 477 libHeader.recTyp = 0xF0; 478 libHeader.recLen = 0x0D; 479 libHeader.trailerPosn = offset + (3 + size); 480 libHeader.recLen = cast(ushort)(g_page_size - 3); 481 libHeader.ndicpages = ndicpages; 482 libHeader.flags = 1; // always case sensitive 483 // Write library header at start of buffer 484 memcpy(libbuf.data, &libHeader, (libHeader).sizeof); 485 } 486 } 487 488 extern (C++) Library LibOMF_factory() 489 { 490 return new LibOMF(); 491 } 492 493 /*****************************************************************************/ 494 /*****************************************************************************/ 495 struct OmfObjModule 496 { 497 ubyte* base; // where are we holding it in memory 498 uint length; // in bytes 499 ushort page; // page module starts in output file 500 const(char)[] name; // module name, with terminating 0 501 } 502 503 /*****************************************************************************/ 504 /*****************************************************************************/ 505 extern (C) 506 { 507 int NameCompare(const(void*) p1, const(void*) p2) 508 { 509 return strcmp((*cast(OmfObjSymbol**)p1).name, (*cast(OmfObjSymbol**)p2).name); 510 } 511 } 512 513 enum HASHMOD = 0x25; 514 enum BUCKETPAGE = 512; 515 enum BUCKETSIZE = (BUCKETPAGE - HASHMOD - 1); 516 517 /******************************************* 518 * Write a single entry into dictionary. 519 * Returns: 520 * false failure 521 */ 522 extern (C++) static bool EnterDict(ubyte* bucketsP, ushort ndicpages, ubyte* entry, uint entrylen) 523 { 524 ushort uStartIndex; 525 ushort uStep; 526 ushort uStartPage; 527 ushort uPageStep; 528 ushort uIndex; 529 ushort uPage; 530 ushort n; 531 uint u; 532 uint nbytes; 533 ubyte* aP; 534 ubyte* zP; 535 aP = entry; 536 zP = aP + entrylen; // point at last char in identifier 537 uStartPage = 0; 538 uPageStep = 0; 539 uStartIndex = 0; 540 uStep = 0; 541 u = entrylen; 542 while (u--) 543 { 544 uStartPage = cast(ushort)_rotl(uStartPage, 2) ^ (*aP | 0x20); 545 uStep = cast(ushort)_rotr(uStep, 2) ^ (*aP++ | 0x20); 546 uStartIndex = cast(ushort)_rotr(uStartIndex, 2) ^ (*zP | 0x20); 547 uPageStep = cast(ushort)_rotl(uPageStep, 2) ^ (*zP-- | 0x20); 548 } 549 uStartPage %= ndicpages; 550 uPageStep %= ndicpages; 551 if (uPageStep == 0) 552 uPageStep++; 553 uStartIndex %= HASHMOD; 554 uStep %= HASHMOD; 555 if (uStep == 0) 556 uStep++; 557 uPage = uStartPage; 558 uIndex = uStartIndex; 559 // number of bytes in entry 560 nbytes = 1 + entrylen + 2; 561 if (entrylen > 255) 562 nbytes += 2; 563 while (1) 564 { 565 aP = &bucketsP[uPage * BUCKETPAGE]; 566 uStartIndex = uIndex; 567 while (1) 568 { 569 if (0 == aP[uIndex]) 570 { 571 // n = next available position in this page 572 n = aP[HASHMOD] << 1; 573 assert(n > HASHMOD); 574 // if off end of this page 575 if (n + nbytes > BUCKETPAGE) 576 { 577 aP[HASHMOD] = 0xFF; 578 break; 579 // next page 580 } 581 else 582 { 583 aP[uIndex] = cast(ubyte)(n >> 1); 584 memcpy((aP + n), entry, nbytes); 585 aP[HASHMOD] += (nbytes + 1) >> 1; 586 if (aP[HASHMOD] == 0) 587 aP[HASHMOD] = 0xFF; 588 return true; 589 } 590 } 591 uIndex += uStep; 592 uIndex %= 0x25; 593 /*if (uIndex > 0x25) 594 uIndex -= 0x25;*/ 595 if (uIndex == uStartIndex) 596 break; 597 } 598 uPage += uPageStep; 599 if (uPage >= ndicpages) 600 uPage -= ndicpages; 601 if (uPage == uStartPage) 602 break; 603 } 604 return false; 605 }