1 /** 2 * Compiler implementation of the 3 * $(LINK2 https://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 2009-2023 by The D Language Foundation, All Rights Reserved 6 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/mscoffobj.d, backend/mscoffobj.d) 9 */ 10 11 module dmd.backend.mscoffobj; 12 13 import core.stdc.ctype; 14 import core.stdc.stdio; 15 import core.stdc.stdint; 16 import core.stdc.stdlib; 17 import core.stdc.string; 18 import core.stdc.time; 19 20 import dmd.backend.barray; 21 import dmd.backend.cc; 22 import dmd.backend.cdef; 23 import dmd.backend.code; 24 import dmd.backend.code_x86; 25 import dmd.backend.cv8; 26 import dmd.backend.dlist; 27 import dmd.backend.dvec; 28 import dmd.backend.el; 29 import dmd.backend.md5; 30 import dmd.backend.mem; 31 import dmd.backend.global; 32 import dmd.backend.obj; 33 import dmd.backend.ty; 34 import dmd.backend.type; 35 36 import dmd.backend.mscoff; 37 38 import dmd.common.outbuffer; 39 40 nothrow: 41 @safe: 42 43 alias _compare_fp_t = extern(C) nothrow int function(const void*, const void*); 44 extern(C) void qsort(void* base, size_t nmemb, size_t size, _compare_fp_t compar); 45 46 extern (C) char* strupr(char*); 47 48 private extern (D) __gshared OutBuffer *fobjbuf; 49 50 enum DEST_LEN = (IDMAX + IDOHD + 1); 51 52 53 /****************************************** 54 */ 55 56 // The object file is built ib several separate pieces 57 58 __gshared private 59 { 60 61 // String Table - String table for all other names 62 OutBuffer *string_table; 63 64 // Section Headers 65 public OutBuffer *ScnhdrBuf; // Buffer to build section table in 66 67 // The -1 is because it is 1 based indexing 68 @trusted 69 IMAGE_SECTION_HEADER* ScnhdrTab() { return cast(IMAGE_SECTION_HEADER *)ScnhdrBuf.buf - 1; } 70 71 int scnhdr_cnt; // Number of sections in table 72 enum SCNHDR_TAB_INITSIZE = 16; // Initial number of sections in buffer 73 enum SCNHDR_TAB_INC = 4; // Number of sections to increment buffer by 74 75 enum SYM_TAB_INIT = 100; // Initial number of symbol entries in buffer 76 enum SYM_TAB_INC = 50; // Number of symbols to increment buffer by 77 78 // The symbol table 79 OutBuffer *symbuf; 80 81 OutBuffer *syment_buf; // array of struct syment 82 83 segidx_t segidx_drectve = UNKNOWN; // contents of ".drectve" section 84 segidx_t segidx_debugS = UNKNOWN; 85 segidx_t segidx_xdata = UNKNOWN; 86 segidx_t segidx_pdata = UNKNOWN; 87 88 extern (D) int jumpTableSeg; // segment index for __jump_table 89 90 extern (D) OutBuffer *indirectsymbuf2; // indirect symbol table of Symbol*'s 91 extern (D) int pointersSeg; // segment index for __pointers 92 93 OutBuffer *ptrref_buf; // buffer for pointer references 94 95 int floatused; 96 97 /* If an MsCoffObj_external_def() happens, set this to the string index, 98 * to be added last to the symbol table. 99 * Obviously, there can be only one. 100 */ 101 extern (D) IDXSTR extdef; 102 103 // Each compiler segment is a section 104 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes 105 // into SegData[] 106 // New compiler segments are added to end. 107 108 public: 109 110 /****************************** 111 * Returns !=0 if this segment is a code segment. 112 */ 113 114 @trusted 115 int mscoff_seg_data_isCode(const ref seg_data sd) 116 { 117 return (ScnhdrTab[sd.SDshtidx].Characteristics & IMAGE_SCN_CNT_CODE) != 0; 118 } 119 120 121 122 private extern (D) segidx_t seg_tlsseg = UNKNOWN; 123 private extern (D) segidx_t seg_tlsseg_bss = UNKNOWN; 124 125 } 126 127 /******************************************************* 128 * Because the mscoff relocations cannot be computed until after 129 * all the segments are written out, and we need more information 130 * than the mscoff relocations provide, make our own relocation 131 * type. Later, translate to mscoff relocation structure. 132 */ 133 134 enum 135 { 136 RELaddr = 0, // straight address 137 RELrel = 1, // relative to location to be fixed up 138 RELseg = 2, // 2 byte section 139 RELaddr32 = 3, // 4 byte offset 140 } 141 142 struct Relocation 143 { // Relocations are attached to the struct seg_data they refer to 144 targ_size_t offset; // location in segment to be fixed up 145 Symbol *funcsym; // function in which offset lies, if any 146 Symbol *targsym; // if !=null, then location is to be fixed up 147 // to address of this symbol 148 uint targseg; // if !=0, then location is to be fixed up 149 // to address of start of this segment 150 ubyte rtype; // RELxxxx 151 short val; // 0, -1, -2, -3, -4, -5 152 } 153 154 155 /******************************* 156 * Output a string into a string table 157 * Input: 158 * strtab = string table for entry 159 * str = string to add 160 * 161 * Returns offset into the specified string table. 162 */ 163 164 IDXSTR MsCoffObj_addstr(OutBuffer *strtab, const char[] str) @system 165 { 166 //printf("MsCoffObj_addstr(strtab = %p str = '%s')\n",strtab,str); 167 IDXSTR idx = cast(IDXSTR)strtab.length(); // remember starting offset 168 strtab.writeStringz(str); 169 //printf("\tidx %d, new size %d\n",idx,strtab.length()); 170 return idx; 171 } 172 173 /************************** 174 * Output read only data and generate a symbol for it. 175 * 176 */ 177 178 Symbol * MsCoffObj_sym_cdata(tym_t ty,char *p,int len) 179 { 180 //printf("MsCoffObj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA)); 181 alignOffset(CDATA, tysize(ty)); 182 Symbol *s = symboldata(Offset(CDATA), ty); 183 s.Sseg = CDATA; 184 MsCoffObj_pubdef(CDATA, s, Offset(CDATA)); 185 MsCoffObj_bytes(CDATA, Offset(CDATA), len, p); 186 187 s.Sfl = FLdata; //FLextern; 188 return s; 189 } 190 191 /************************** 192 * Ouput read only data for data 193 * 194 */ 195 196 @trusted 197 int MsCoffObj_data_readonly(char *p, int len, segidx_t *pseg) 198 { 199 int oldoff; 200 oldoff = cast(int)Offset(CDATA); 201 SegData[CDATA].SDbuf.reserve(len); 202 SegData[CDATA].SDbuf.writen(p,len); 203 Offset(CDATA) += len; 204 *pseg = CDATA; 205 return oldoff; 206 } 207 208 @trusted 209 int MsCoffObj_data_readonly(char *p, int len) 210 { 211 segidx_t pseg; 212 213 return MsCoffObj_data_readonly(p, len, &pseg); 214 } 215 216 /***************************** 217 * Get segment for readonly string literals. 218 * The linker will pool strings in this section. 219 * Params: 220 * sz = number of bytes per character (1, 2, or 4) 221 * Returns: 222 * segment index 223 */ 224 int MsCoffObj_string_literal_segment(uint sz) 225 { 226 assert(0); 227 } 228 229 /****************************** 230 * Start a .obj file. 231 * Called before any other obj_xxx routines. 232 * One source file can generate multiple .obj files. 233 */ 234 235 @system 236 Obj MsCoffObj_init(OutBuffer *objbuf, const(char)* filename, const(char)* csegname) 237 { 238 //printf("MsCoffObj_init()\n"); 239 Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj)); 240 241 cseg = CODE; 242 fobjbuf = objbuf; 243 assert(objbuf.length() == 0); 244 245 floatused = 0; 246 247 segidx_drectve = UNKNOWN; 248 seg_tlsseg = UNKNOWN; 249 seg_tlsseg_bss = UNKNOWN; 250 251 segidx_pdata = UNKNOWN; 252 segidx_xdata = UNKNOWN; 253 segidx_debugS = UNKNOWN; 254 255 // Initialize buffers 256 257 if (!string_table) 258 { 259 string_table = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 260 if (!string_table) 261 err_nomem(); 262 string_table.reserve(2048); 263 } 264 string_table.reset(); 265 string_table.write32(4); // first 4 bytes are length of string table 266 267 if (symbuf) 268 { 269 Symbol **p = cast(Symbol **)symbuf.buf; 270 const size_t n = symbuf.length() / (Symbol *).sizeof; 271 for (size_t i = 0; i < n; ++i) 272 symbol_reset(p[i]); 273 symbuf.reset(); 274 } 275 else 276 { 277 symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 278 if (!symbuf) 279 err_nomem(); 280 symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 281 } 282 283 if (!syment_buf) 284 { 285 syment_buf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 286 if (!syment_buf) 287 err_nomem(); 288 syment_buf.reserve(SymbolTable32.sizeof * SYM_TAB_INIT); 289 } 290 syment_buf.reset(); 291 292 extdef = 0; 293 pointersSeg = 0; 294 295 // Initialize segments for CODE, DATA, UDATA and CDATA 296 if (!ScnhdrBuf) 297 { 298 ScnhdrBuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 299 if (!ScnhdrBuf) 300 err_nomem(); 301 ScnhdrBuf.reserve(SCNHDR_TAB_INITSIZE * (IMAGE_SECTION_HEADER).sizeof); 302 } 303 ScnhdrBuf.reset(); 304 scnhdr_cnt = 0; 305 306 /* Define sections. Although the order should not matter, we duplicate 307 * the same order VC puts out just to avoid trouble. 308 */ 309 310 int alignText = I64 ? IMAGE_SCN_ALIGN_16BYTES : IMAGE_SCN_ALIGN_8BYTES; 311 int alignData = IMAGE_SCN_ALIGN_16BYTES; 312 MsCoffObj_addScnhdr(".data$B", IMAGE_SCN_CNT_INITIALIZED_DATA | 313 alignData | 314 IMAGE_SCN_MEM_READ | 315 IMAGE_SCN_MEM_WRITE); // DATA 316 MsCoffObj_addScnhdr(".text", IMAGE_SCN_CNT_CODE | 317 alignText | 318 IMAGE_SCN_MEM_EXECUTE | 319 IMAGE_SCN_MEM_READ); // CODE 320 MsCoffObj_addScnhdr(".bss$B", IMAGE_SCN_CNT_UNINITIALIZED_DATA | 321 alignData | 322 IMAGE_SCN_MEM_READ | 323 IMAGE_SCN_MEM_WRITE); // UDATA 324 MsCoffObj_addScnhdr(".rdata", IMAGE_SCN_CNT_INITIALIZED_DATA | 325 alignData | 326 IMAGE_SCN_MEM_READ); // CONST 327 328 SegData.reset(); 329 SegData.push(); 330 331 enum 332 { 333 SHI_DATA = 1, 334 SHI_TEXT = 2, 335 SHI_UDATA = 3, 336 SHI_CDATA = 4, 337 } 338 339 MsCoffObj_getsegment2(SHI_TEXT); 340 assert(SegData[CODE].SDseg == CODE); 341 342 MsCoffObj_getsegment2(SHI_DATA); 343 assert(SegData[DATA].SDseg == DATA); 344 345 MsCoffObj_getsegment2(SHI_CDATA); 346 assert(SegData[CDATA].SDseg == CDATA); 347 348 MsCoffObj_getsegment2(SHI_UDATA); 349 assert(SegData[UDATA].SDseg == UDATA); 350 351 if (config.fulltypes) 352 cv8_initfile(filename); 353 assert(objbuf.length() == 0); 354 return obj; 355 } 356 357 /************************** 358 * Start a module within a .obj file. 359 * There can be multiple modules within a single .obj file. 360 * 361 * Input: 362 * filename: Name of source file 363 * csegname: User specified default code segment name 364 */ 365 366 @trusted 367 void MsCoffObj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname) 368 { 369 //dbg_printf("MsCoffObj_initfile(filename = %s, modname = %s)\n",filename,modname); 370 if (config.fulltypes) 371 cv8_initmodule(filename, modname); 372 } 373 374 /************************************ 375 * Patch pseg/offset by adding in the vmaddr difference from 376 * pseg/offset to start of seg. 377 */ 378 379 @trusted 380 private extern (D) 381 int32_t *MsCoffObj_patchAddr(int seg, targ_size_t offset) 382 { 383 return cast(int32_t *)(fobjbuf.buf + ScnhdrTab[SegData[seg].SDshtidx].PointerToRawData + offset); 384 } 385 386 @trusted 387 private extern (D) 388 int32_t *MsCoffObj_patchAddr64(int seg, targ_size_t offset) 389 { 390 return cast(int32_t *)(fobjbuf.buf + ScnhdrTab[SegData[seg].SDshtidx].PointerToRawData + offset); 391 } 392 393 private extern (D) 394 static if (0) 395 { 396 @trusted 397 void patch(seg_data *pseg, targ_size_t offset, int seg, targ_size_t value) 398 { 399 //printf("patch(offset = x%04x, seg = %d, value = x%llx)\n", cast(uint)offset, seg, value); 400 if (I64) 401 { 402 int32_t *p = cast(int32_t *)(fobjbuf.buf + ScnhdrTab[pseg.SDshtidx].PointerToRawData + offset); 403 404 static if (0) 405 printf("\taddr1 = x%llx\n\taddr2 = x%llx\n\t*p = x%llx\n\tdelta = x%llx\n", 406 ScnhdrTab[pseg.SDshtidx].VirtualAddress, 407 ScnhdrTab[SegData[seg].SDshtidx].VirtualAddress, 408 *p, 409 ScnhdrTab[SegData[seg].SDshtidx].VirtualAddress - 410 (ScnhdrTab[pseg.SDshtidx].VirtualAddress + offset)); 411 412 *p += ScnhdrTab[SegData[seg].SDshtidx].VirtualAddress - 413 (ScnhdrTab[pseg.SDshtidx].VirtualAddress - value); 414 } 415 else 416 { 417 int32_t *p = cast(int32_t *)(fobjbuf.buf + ScnhdrTab[pseg.SDshtidx].PointerToRawData + offset); 418 419 static if (0) 420 printf("\taddr1 = x%x\n\taddr2 = x%x\n\t*p = x%x\n\tdelta = x%x\n", 421 ScnhdrTab[pseg.SDshtidx].VirtualAddress, 422 ScnhdrTab[SegData[seg].SDshtidx].VirtualAddress, 423 *p, 424 ScnhdrTab[SegData[seg].SDshtidx].VirtualAddress - 425 (ScnhdrTab[pseg.SDshtidx].VirtualAddress + offset)); 426 427 *p += ScnhdrTab[SegData[seg].SDshtidx].VirtualAddress - 428 (ScnhdrTab[pseg.SDshtidx].VirtualAddress - value); 429 } 430 } 431 } 432 433 /********************************* 434 * Build syment[], the array of symbols. 435 * Store them in syment_buf. 436 */ 437 438 @trusted 439 private void syment_set_name(SymbolTable32 *sym, const(char)* name) 440 { 441 size_t len = strlen(name); 442 if (len > 8) 443 { // Use offset into string table 444 IDXSTR idx = MsCoffObj_addstr(string_table, name[0 .. len]); 445 sym.Zeros = 0; 446 sym.Offset = idx; 447 } 448 else 449 { memcpy(sym.Name.ptr, name, len); 450 if (len < 8) 451 memset(sym.Name.ptr + len, 0, 8 - len); 452 } 453 } 454 455 @trusted 456 void write_sym(SymbolTable32* sym, bool bigobj) 457 { 458 assert((*sym).sizeof == 20); 459 if (bigobj) 460 { 461 syment_buf.write(sym[0 .. 1]); 462 } 463 else 464 { 465 // the only difference between SymbolTable32 and SymbolTable 466 // is that field SectionNumber is long instead of short 467 uint scoff = cast(uint)(cast(char*)&sym.SectionNumber - cast(char*)sym); 468 syment_buf.write(sym, scoff + 2); 469 syment_buf.write(cast(char*)sym + scoff + 4, cast(uint)((*sym).sizeof - scoff - 4)); 470 } 471 } 472 @trusted 473 474 void build_syment_table(bool bigobj) 475 { 476 /* The @comp.id symbol appears to be the version of VC that generated the .obj file. 477 * Anything we put in there would have no relevance, so we'll not put out this symbol. 478 */ 479 480 uint symsize = bigobj ? SymbolTable32.sizeof : SymbolTable.sizeof; 481 /* Now goes one symbol per section. 482 */ 483 for (segidx_t seg = 1; seg < SegData.length; seg++) 484 { 485 seg_data *pseg = SegData[seg]; 486 IMAGE_SECTION_HEADER *psechdr = &ScnhdrTab[pseg.SDshtidx]; // corresponding section 487 488 SymbolTable32 sym; 489 memcpy(sym.Name.ptr, psechdr.Name.ptr, 8); 490 sym.Value = 0; 491 sym.SectionNumber = pseg.SDshtidx; 492 sym.Type = 0; 493 sym.StorageClass = IMAGE_SYM_CLASS_STATIC; 494 sym.NumberOfAuxSymbols = 1; 495 496 write_sym(&sym, bigobj); 497 498 auxent aux = void; 499 memset(&aux, 0, (aux).sizeof); 500 501 // s_size is not set yet 502 //aux.x_section.length = psechdr.s_size; 503 if (pseg.SDbuf && pseg.SDbuf.length()) 504 aux.x_section.length = cast(uint)pseg.SDbuf.length(); 505 else 506 aux.x_section.length = cast(uint)pseg.SDoffset; 507 508 if (pseg.SDrel) 509 aux.x_section.NumberOfRelocations = cast(ushort)(pseg.SDrel.length() / (Relocation).sizeof); 510 511 if (psechdr.Characteristics & IMAGE_SCN_LNK_COMDAT) 512 { 513 aux.x_section.Selection = cast(ubyte)IMAGE_COMDAT_SELECT_ANY; 514 if (pseg.SDassocseg) 515 { aux.x_section.Selection = cast(ubyte)IMAGE_COMDAT_SELECT_ASSOCIATIVE; 516 aux.x_section.NumberHighPart = cast(ushort)(pseg.SDassocseg >> 16); 517 aux.x_section.NumberLowPart = cast(ushort)(pseg.SDassocseg & 0x0000FFFF); 518 } 519 } 520 521 // memset(&aux.x_section.Zeros, 0, 2); 522 523 syment_buf.write(&aux, symsize); 524 525 assert((aux).sizeof == 18); 526 } 527 528 /* Add symbols from symbuf[] 529 */ 530 531 int n = cast(int)SegData.length; 532 size_t dim = symbuf.length() / (Symbol *).sizeof; 533 for (size_t i = 0; i < dim; i++) 534 { Symbol *s = (cast(Symbol **)symbuf.buf)[i]; 535 s.Sxtrnnum = cast(uint)(syment_buf.length() / symsize); 536 n++; 537 538 SymbolTable32 sym; 539 540 char[DEST_LEN+1] dest = void; 541 char *destr = obj_mangle2(s, dest.ptr); 542 syment_set_name(&sym, destr); 543 544 sym.Value = 0; 545 switch (s.Sclass) 546 { 547 case SC.extern_: 548 sym.SectionNumber = IMAGE_SYM_UNDEFINED; 549 break; 550 551 default: 552 sym.SectionNumber = SegData[s.Sseg].SDshtidx; 553 break; 554 } 555 sym.Type = tyfunc(s.Stype.Tty) ? 0x20 : 0; 556 switch (s.Sclass) 557 { 558 case SC.static_: 559 if (s.Sflags & SFLhidden) 560 goto default; 561 goto case; 562 case SC.locstat: 563 sym.StorageClass = IMAGE_SYM_CLASS_STATIC; 564 sym.Value = cast(uint)s.Soffset; 565 break; 566 567 default: 568 sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; 569 if (sym.SectionNumber != IMAGE_SYM_UNDEFINED) 570 sym.Value = cast(uint)s.Soffset; 571 break; 572 } 573 sym.NumberOfAuxSymbols = 0; 574 575 write_sym(&sym, bigobj); 576 } 577 } 578 579 580 /*************************** 581 * Fixup and terminate object file. 582 */ 583 584 @trusted 585 void MsCoffObj_termfile() 586 { 587 //dbg_printf("MsCoffObj_termfile\n"); 588 if (configv.addlinenumbers) 589 { 590 cv8_termmodule(); 591 } 592 } 593 594 /********************************* 595 * Terminate package. 596 */ 597 598 @trusted 599 void MsCoffObj_term(const(char)* objfilename) 600 { 601 //printf("MsCoffObj_term()\n"); 602 assert(fobjbuf.length() == 0); 603 604 objflush_pointerRefs(); 605 outfixlist(); // backpatches 606 607 if (configv.addlinenumbers) 608 { 609 cv8_termfile(objfilename); 610 } 611 612 // To allow tooling support for most output files 613 // switch to new object file format (similar to C++ with /bigobj) 614 // only when exceeding the limit for 16-bit section count according to 615 // https://msdn.microsoft.com/en-us/library/8578y171%28v=vs.71%29.aspx 616 bool bigobj = scnhdr_cnt > 65_279; 617 build_syment_table(bigobj); 618 619 /* Write out the object file in the following order: 620 * Header 621 * Section Headers 622 * Symbol table 623 * String table 624 * Section data 625 */ 626 627 uint foffset; 628 629 // Write out the bytes for the header 630 631 BIGOBJ_HEADER header = void; 632 IMAGE_FILE_HEADER header_old = void; 633 634 time_t f_timedat = 0; 635 time(&f_timedat); 636 uint symtable_offset; 637 638 if (bigobj) 639 { 640 header.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN; 641 header.Sig2 = 0xFFFF; 642 header.Version = 2; 643 header.Machine = I64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386; 644 header.NumberOfSections = scnhdr_cnt; 645 header.TimeDateStamp = cast(uint)f_timedat; 646 static immutable ubyte[16] uuid = 647 [ '\xc7', '\xa1', '\xba', '\xd1', '\xee', '\xba', '\xa9', '\x4b', 648 '\xaf', '\x20', '\xfa', '\xf6', '\x6a', '\xa4', '\xdc', '\xb8' ]; 649 memcpy(header.UUID.ptr, uuid.ptr, 16); 650 memset(header.unused.ptr, 0, (header.unused).sizeof); 651 foffset = (header).sizeof; // start after header 652 foffset += ScnhdrBuf.length(); // section headers 653 header.PointerToSymbolTable = foffset; // offset to symbol table 654 symtable_offset = foffset; 655 header.NumberOfSymbols = cast(uint)(syment_buf.length() / (SymbolTable32).sizeof); 656 foffset += header.NumberOfSymbols * (SymbolTable32).sizeof; // symbol table 657 } 658 else 659 { 660 header_old.Machine = I64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386; 661 header_old.NumberOfSections = cast(ushort)scnhdr_cnt; 662 header_old.TimeDateStamp = cast(uint)f_timedat; 663 header_old.SizeOfOptionalHeader = 0; 664 header_old.Characteristics = 0; 665 foffset = (header_old).sizeof; // start after header 666 foffset += ScnhdrBuf.length(); // section headers 667 header_old.PointerToSymbolTable = foffset; // offset to symbol table 668 symtable_offset = foffset; 669 header_old.NumberOfSymbols = cast(uint)(syment_buf.length() / (SymbolTable).sizeof); 670 foffset += header_old.NumberOfSymbols * (SymbolTable).sizeof; // symbol table 671 } 672 673 uint string_table_offset = foffset; 674 foffset += string_table.length(); // string table 675 676 // Compute file offsets of all the section data 677 678 for (segidx_t seg = 1; seg < SegData.length; seg++) 679 { 680 seg_data *pseg = SegData[seg]; 681 IMAGE_SECTION_HEADER *psechdr = &ScnhdrTab[pseg.SDshtidx]; // corresponding section 682 683 int align_ = pseg.SDalignment; 684 if (align_ > 1) 685 foffset = (foffset + align_ - 1) & ~(align_ - 1); 686 687 if (pseg.SDbuf && pseg.SDbuf.length()) 688 { 689 psechdr.PointerToRawData = foffset; 690 //printf("seg = %2d SDshtidx = %2d psechdr = %p s_scnptr = x%x\n", seg, pseg.SDshtidx, psechdr, cast(uint)psechdr.s_scnptr); 691 psechdr.SizeOfRawData = cast(uint)pseg.SDbuf.length(); 692 foffset += psechdr.SizeOfRawData; 693 } 694 else 695 psechdr.SizeOfRawData = cast(uint)pseg.SDoffset; 696 } 697 698 // Compute file offsets of the relocation data 699 for (segidx_t seg = 1; seg < SegData.length; seg++) 700 { 701 seg_data *pseg = SegData[seg]; 702 IMAGE_SECTION_HEADER *psechdr = &ScnhdrTab[pseg.SDshtidx]; // corresponding section 703 if (pseg.SDrel) 704 { 705 foffset = (foffset + 3) & ~3; 706 assert(psechdr.PointerToRelocations == 0); 707 auto nreloc = pseg.SDrel.length() / Relocation.sizeof; 708 if (nreloc > 0xffff) 709 { 710 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#coff-relocations-object-only 711 psechdr.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL; 712 psechdr.PointerToRelocations = foffset; 713 psechdr.NumberOfRelocations = 0xffff; 714 foffset += reloc.sizeof; 715 } 716 else if (nreloc) 717 { 718 psechdr.PointerToRelocations = foffset; 719 //printf("seg = %d SDshtidx = %d psechdr = %p s_relptr = x%x\n", seg, pseg.SDshtidx, psechdr, cast(uint)psechdr.s_relptr); 720 psechdr.NumberOfRelocations = cast(ushort)nreloc; 721 } 722 foffset += nreloc * reloc.sizeof; 723 } 724 } 725 726 assert(fobjbuf.length() == 0); 727 728 // Write the header 729 if (bigobj) 730 { 731 fobjbuf.write((&header)[0 .. 1]); 732 foffset = (header).sizeof; 733 } 734 else 735 { 736 fobjbuf.write((&header_old)[0 .. 1]); 737 foffset = (header_old).sizeof; 738 } 739 740 // Write the section headers 741 fobjbuf.write((*ScnhdrBuf)[]); 742 foffset += ScnhdrBuf.length(); 743 744 // Write the symbol table 745 assert(foffset == symtable_offset); 746 fobjbuf.write((*syment_buf)[]); 747 foffset += syment_buf.length(); 748 749 // Write the string table 750 assert(foffset == string_table_offset); 751 *cast(uint *)(string_table.buf) = cast(uint)string_table.length(); 752 fobjbuf.write((*string_table)[]); 753 foffset += string_table.length(); 754 755 // Write the section data 756 for (segidx_t seg = 1; seg < SegData.length; seg++) 757 { 758 seg_data *pseg = SegData[seg]; 759 IMAGE_SECTION_HEADER *psechdr = &ScnhdrTab[pseg.SDshtidx]; // corresponding section 760 foffset = elf_align(pseg.SDalignment, foffset); 761 if (pseg.SDbuf && pseg.SDbuf.length()) 762 { 763 //printf("seg = %2d SDshtidx = %2d psechdr = %p s_scnptr = x%x, foffset = x%x\n", seg, pseg.SDshtidx, psechdr, cast(uint)psechdr.s_scnptr, cast(uint)foffset); 764 assert(pseg.SDbuf.length() == psechdr.SizeOfRawData); 765 assert(foffset == psechdr.PointerToRawData); 766 fobjbuf.write((*pseg.SDbuf)[]); 767 foffset += pseg.SDbuf.length(); 768 } 769 } 770 771 // Compute the relocations, write them out 772 assert((reloc).sizeof == 10); 773 for (segidx_t seg = 1; seg < SegData.length; seg++) 774 { 775 seg_data *pseg = SegData[seg]; 776 IMAGE_SECTION_HEADER *psechdr = &ScnhdrTab[pseg.SDshtidx]; // corresponding section 777 if (pseg.SDrel) 778 { 779 Relocation *r = cast(Relocation *)pseg.SDrel.buf; 780 size_t sz = pseg.SDrel.length(); 781 bool pdata = (strcmp(cast(const(char)* )psechdr.Name, ".pdata") == 0); 782 Relocation *rend = cast(Relocation *)(pseg.SDrel.buf + sz); 783 foffset = elf_align(4, foffset); 784 785 debug 786 if (sz && foffset != psechdr.PointerToRelocations) 787 printf("seg = %d SDshtidx = %d psechdr = %p s_relptr = x%x, foffset = x%x\n", seg, pseg.SDshtidx, psechdr, cast(uint)psechdr.PointerToRelocations, cast(uint)foffset); 788 assert(sz == 0 || foffset == psechdr.PointerToRelocations); 789 790 if (psechdr.Characteristics & IMAGE_SCN_LNK_NRELOC_OVFL) 791 { 792 auto rel = reloc(cast(uint)(sz / Relocation.sizeof) + 1); 793 fobjbuf.write((&rel)[0 .. 1]); 794 foffset += rel.sizeof; 795 } 796 for (; r != rend; r++) 797 { reloc rel; 798 rel.r_vaddr = 0; 799 rel.r_symndx = 0; 800 rel.r_type = 0; 801 802 Symbol *s = r.targsym; 803 const(char)* rs = r.rtype == RELaddr ? "addr" : "rel"; 804 //printf("%d:x%04lx : tseg %d tsym %s REL%s\n", seg, cast(int)r.offset, r.targseg, s ? s.Sident.ptr : "0", rs); 805 if (s) 806 { 807 //printf("Relocation\n"); 808 //symbol_print(s); 809 if (pseg.isCode()) 810 { 811 if (I64) 812 { 813 rel.r_type = (r.rtype == RELrel) 814 ? IMAGE_REL_AMD64_REL32 815 : IMAGE_REL_AMD64_REL32; 816 817 if (s.Stype.Tty & mTYthread) 818 rel.r_type = IMAGE_REL_AMD64_SECREL; 819 820 if (r.val == -1) 821 rel.r_type = IMAGE_REL_AMD64_REL32_1; 822 else if (r.val == -2) 823 rel.r_type = IMAGE_REL_AMD64_REL32_2; 824 else if (r.val == -3) 825 rel.r_type = IMAGE_REL_AMD64_REL32_3; 826 else if (r.val == -4) 827 rel.r_type = IMAGE_REL_AMD64_REL32_4; 828 else if (r.val == -5) 829 rel.r_type = IMAGE_REL_AMD64_REL32_5; 830 831 /+if (s.Sclass == SCextern || 832 s.Sclass == SCcomdef || 833 s.Sclass == SCcomdat || 834 s.Sclass == SCglobal) 835 { 836 rel.r_vaddr = cast(uint)r.offset; 837 rel.r_symndx = s.Sxtrnnum; 838 } 839 else+/ 840 { 841 rel.r_vaddr = cast(uint)r.offset; 842 rel.r_symndx = s.Sxtrnnum; 843 } 844 } 845 else if (I32) 846 { 847 rel.r_type = (r.rtype == RELrel) 848 ? IMAGE_REL_I386_REL32 849 : IMAGE_REL_I386_DIR32; 850 851 if (s.Stype.Tty & mTYthread) 852 rel.r_type = IMAGE_REL_I386_SECREL; 853 854 /+if (s.Sclass == SCextern || 855 s.Sclass == SCcomdef || 856 s.Sclass == SCcomdat || 857 s.Sclass == SCglobal) 858 { 859 rel.r_vaddr = cast(uint)r.offset; 860 rel.r_symndx = s.Sxtrnnum; 861 } 862 else+/ 863 { 864 rel.r_vaddr = cast(uint)r.offset; 865 rel.r_symndx = s.Sxtrnnum; 866 } 867 } 868 else 869 assert(false); // not implemented for I16 870 } 871 else 872 { 873 if (I64) 874 { 875 if (pdata) 876 rel.r_type = IMAGE_REL_AMD64_ADDR32NB; 877 else 878 rel.r_type = IMAGE_REL_AMD64_ADDR64; 879 880 if (r.rtype == RELseg) 881 rel.r_type = IMAGE_REL_AMD64_SECTION; 882 else if (r.rtype == RELaddr32) 883 rel.r_type = IMAGE_REL_AMD64_SECREL; 884 } 885 else if (I32) 886 { 887 if (pdata) 888 rel.r_type = IMAGE_REL_I386_DIR32NB; 889 else 890 rel.r_type = IMAGE_REL_I386_DIR32; 891 892 if (r.rtype == RELseg) 893 rel.r_type = IMAGE_REL_I386_SECTION; 894 else if (r.rtype == RELaddr32) 895 rel.r_type = IMAGE_REL_I386_SECREL; 896 } 897 else 898 assert(false); // not implemented for I16 899 900 rel.r_vaddr = cast(uint)r.offset; 901 rel.r_symndx = s.Sxtrnnum; 902 } 903 } 904 else if (r.rtype == RELaddr && pseg.isCode()) 905 { 906 int32_t *p = null; 907 p = MsCoffObj_patchAddr(seg, r.offset); 908 909 rel.r_vaddr = cast(uint)r.offset; 910 rel.r_symndx = s ? s.Sxtrnnum : 0; 911 912 if (I64) 913 { 914 rel.r_type = IMAGE_REL_AMD64_REL32; 915 //srel.r_value = ScnhdrTab[SegData[r.targseg].SDshtidx].s_vaddr + *p; 916 //printf("SECTDIFF: x%llx + x%llx = x%x\n", ScnhdrTab[SegData[r.targseg].SDshtidx].s_vaddr, *p, srel.r_value); 917 } 918 else 919 { 920 rel.r_type = IMAGE_REL_I386_SECREL; 921 //srel.r_value = ScnhdrTab[SegData[r.targseg].SDshtidx].s_vaddr + *p; 922 //printf("SECTDIFF: x%x + x%x = x%x\n", ScnhdrTab[SegData[r.targseg].SDshtidx].s_vaddr, *p, srel.r_value); 923 } 924 } 925 else 926 { 927 assert(0); 928 } 929 930 /* Some programs do generate a lot of symbols. 931 * Note that MS-Link can get pretty slow with large numbers of symbols. 932 */ 933 //assert(rel.r_symndx <= 20000); 934 935 assert(rel.r_type <= 0x14); 936 fobjbuf.write((&rel)[0 .. 1]); 937 foffset += (rel).sizeof; 938 } 939 } 940 } 941 } 942 943 /***************************** 944 * Line number support. 945 */ 946 947 /*************************** 948 * Record file and line number at segment and offset. 949 * Params: 950 * srcpos = source file position 951 * seg = segment it corresponds to 952 * offset = offset within seg 953 */ 954 955 @trusted 956 void MsCoffObj_linnum(Srcpos srcpos, int seg, targ_size_t offset) 957 { 958 if (srcpos.Slinnum == 0 || !srcpos.Sfilename) 959 return; 960 961 cv8_linnum(srcpos, cast(uint)offset); 962 } 963 964 965 /******************************* 966 * Set start address 967 */ 968 969 void MsCoffObj_startaddress(Symbol *s) 970 { 971 //dbg_printf("MsCoffObj_startaddress(Symbol *%s)\n",s.Sident.ptr); 972 //obj.startaddress = s; 973 } 974 975 /******************************* 976 * Output library name. 977 */ 978 979 @trusted 980 extern (D) 981 bool MsCoffObj_includelib(scope const char[] name) 982 { 983 int seg = MsCoffObj_seg_drectve(); 984 //dbg_printf("MsCoffObj_includelib(name *%s)\n",name); 985 SegData[seg].SDbuf.write(" /DEFAULTLIB:\"".ptr, 14); 986 SegData[seg].SDbuf.write(name.ptr, cast(uint)name.length); 987 SegData[seg].SDbuf.writeByte('"'); 988 return true; 989 } 990 991 /******************************* 992 * Output linker directive name. 993 */ 994 995 @trusted 996 bool MsCoffObj_linkerdirective(const(char)* directive) 997 { 998 int seg = MsCoffObj_seg_drectve(); 999 //dbg_printf("MsCoffObj::linkerdirective(directive *%s)\n",directive); 1000 SegData[seg].SDbuf.writeByte(' '); 1001 SegData[seg].SDbuf.write(directive, cast(uint)strlen(directive)); 1002 return true; 1003 } 1004 1005 /********************************** 1006 * Do we allow zero sized objects? 1007 */ 1008 1009 bool MsCoffObj_allowZeroSize() 1010 { 1011 return true; 1012 } 1013 1014 /************************** 1015 * Embed string in executable. 1016 */ 1017 1018 void MsCoffObj_exestr(const(char)* p) 1019 { 1020 //dbg_printf("MsCoffObj_exestr(char *%s)\n",p); 1021 } 1022 1023 /************************** 1024 * Embed string in obj. 1025 */ 1026 1027 void MsCoffObj_user(const(char)* p) 1028 { 1029 //dbg_printf("MsCoffObj_user(char *%s)\n",p); 1030 } 1031 1032 /******************************* 1033 * Output a weak extern record. 1034 */ 1035 1036 void MsCoffObj_wkext(Symbol *s1,Symbol *s2) 1037 { 1038 //dbg_printf("MsCoffObj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr); 1039 } 1040 1041 /******************************* 1042 * Output file name record. 1043 * 1044 * Currently assumes that obj_filename will not be called 1045 * twice for the same file. 1046 */ 1047 1048 void MsCoffObj_filename(const(char)* modname) 1049 { 1050 //dbg_printf("MsCoffObj_filename(char *%s)\n",modname); 1051 // Not supported by mscoff 1052 } 1053 1054 /******************************* 1055 * Embed compiler version in .obj file. 1056 */ 1057 1058 void MsCoffObj_compiler(const(char)* p) 1059 { 1060 //dbg_printf("MsCoffObj_compiler\n"); 1061 MsCoffObj_user(p); 1062 } 1063 1064 /************************************** 1065 * Symbol is the function that calls the static constructors. 1066 * Put a pointer to it into a special segment that the startup code 1067 * looks at. 1068 * Input: 1069 * s static constructor function 1070 * dtor !=0 if leave space for static destructor 1071 * seg 1: user 1072 * 2: lib 1073 * 3: compiler 1074 */ 1075 1076 void MsCoffObj_staticctor(Symbol *s,int dtor,int none) 1077 { 1078 MsCoffObj_setModuleCtorDtor(s, true); 1079 } 1080 1081 /************************************** 1082 * Symbol is the function that calls the static destructors. 1083 * Put a pointer to it into a special segment that the exit code 1084 * looks at. 1085 * Input: 1086 * s static destructor function 1087 */ 1088 1089 void MsCoffObj_staticdtor(Symbol *s) 1090 { 1091 MsCoffObj_setModuleCtorDtor(s, false); 1092 } 1093 1094 1095 /*************************************** 1096 * Stuff pointer to function in its own segment. 1097 * Used for static ctor and dtor lists. 1098 */ 1099 1100 @trusted 1101 void MsCoffObj_setModuleCtorDtor(Symbol *sfunc, bool isCtor) 1102 { 1103 // Also see https://blogs.msdn.microsoft.com/vcblog/2006/10/20/crt-initialization/ 1104 // and https://www.codeguru.com/cplusplus/running-code-before-and-after-main/ 1105 const int align_ = I64 ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES; 1106 const int attr = IMAGE_SCN_CNT_INITIALIZED_DATA | align_ | IMAGE_SCN_MEM_READ; 1107 const int seg = MsCoffObj_getsegment(isCtor ? ".CRT$XCU" : ".CRT$XPU", attr); 1108 1109 const int relflags = I64 ? CFoff | CFoffset64 : CFoff; 1110 const int sz = MsCoffObj_reftoident(seg, SegData[seg].SDoffset, sfunc, 0, relflags); 1111 SegData[seg].SDoffset += sz; 1112 } 1113 1114 1115 /*************************************** 1116 * Stuff the following data (instance of struct FuncTable) in a separate segment: 1117 * pointer to function 1118 * pointer to ehsym 1119 * length of function 1120 */ 1121 1122 @trusted 1123 void MsCoffObj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym) 1124 { 1125 //printf("MsCoffObj_ehtables(func = %s, handler table = %s) \n",sfunc.Sident.ptr, ehsym.Sident.ptr); 1126 1127 /* BUG: this should go into a COMDAT if sfunc is in a COMDAT 1128 * otherwise the duplicates aren't removed. 1129 */ 1130 1131 int align_ = I64 ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES; // align to _tysize[TYnptr] 1132 1133 // The size is (FuncTable).sizeof in deh2.d 1134 const int seg = 1135 MsCoffObj_getsegment("._deh$B", IMAGE_SCN_CNT_INITIALIZED_DATA | 1136 align_ | 1137 IMAGE_SCN_MEM_READ); 1138 1139 OutBuffer *buf = SegData[seg].SDbuf; 1140 if (I64) 1141 { MsCoffObj_reftoident(seg, buf.length(), sfunc, 0, CFoff | CFoffset64); 1142 MsCoffObj_reftoident(seg, buf.length(), ehsym, 0, CFoff | CFoffset64); 1143 buf.write64(sfunc.Ssize); 1144 } 1145 else 1146 { MsCoffObj_reftoident(seg, buf.length(), sfunc, 0, CFoff); 1147 MsCoffObj_reftoident(seg, buf.length(), ehsym, 0, CFoff); 1148 buf.write32(cast(uint)sfunc.Ssize); 1149 } 1150 } 1151 1152 /********************************************* 1153 * Put out symbols that define the beginning/end of the .deh_eh section. 1154 * This gets called if this is the module with "extern (D) main()" in it. 1155 */ 1156 1157 @trusted 1158 private void emitSectionBrace(const(char)* segname, const(char)* symname, int attr, bool coffZeroBytes) 1159 { 1160 char[16] name = void; 1161 strcat(strcpy(name.ptr, segname), "$A"); 1162 const int seg_bg = MsCoffObj_getsegment(name.ptr, attr); 1163 1164 strcat(strcpy(name.ptr, segname), "$C"); 1165 const int seg_en = MsCoffObj_getsegment(name.ptr, attr); 1166 1167 /* Create symbol sym_beg that sits just before the .seg$B section 1168 */ 1169 strcat(strcpy(name.ptr, symname), "_beg"); 1170 Symbol *beg = symbol_name(name[0 .. strlen(name.ptr)], SC.global, tspvoid); 1171 beg.Sseg = seg_bg; 1172 beg.Soffset = 0; 1173 symbuf.write((&beg)[0 .. 1]); 1174 if (coffZeroBytes) // unnecessary, but required by current runtime 1175 MsCoffObj_bytes(seg_bg, 0, I64 ? 8 : 4, null); 1176 1177 /* Create symbol sym_end that sits just after the .seg$B section 1178 */ 1179 strcat(strcpy(name.ptr, symname), "_end"); 1180 Symbol *end = symbol_name(name[0 .. strlen(name.ptr)], SC.global, tspvoid); 1181 end.Sseg = seg_en; 1182 end.Soffset = 0; 1183 symbuf.write((&end)[0 .. 1]); 1184 if (coffZeroBytes) // unnecessary, but required by current runtime 1185 MsCoffObj_bytes(seg_en, 0, I64 ? 8 : 4, null); 1186 } 1187 1188 void MsCoffObj_ehsections() 1189 { 1190 //printf("MsCoffObj_ehsections()\n"); 1191 1192 int align_ = I64 ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES; 1193 int attr = IMAGE_SCN_CNT_INITIALIZED_DATA | align_ | IMAGE_SCN_MEM_READ; 1194 emitSectionBrace("._deh", "_deh", attr, true); 1195 emitSectionBrace(".minfo", "_minfo", attr, true); 1196 1197 attr = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; 1198 emitSectionBrace(".dp", "_DP", attr, false); // references to pointers in .data and .bss 1199 emitSectionBrace(".tp", "_TP", attr, false); // references to pointers in .tls 1200 1201 attr = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; 1202 emitSectionBrace(".data", "_data", attr, false); 1203 1204 attr = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; 1205 emitSectionBrace(".bss", "_bss", attr, false); 1206 1207 /*************************************************************************/ 1208 static if (0) 1209 { 1210 { 1211 /* TLS sections 1212 */ 1213 int align_ = I64 ? IMAGE_SCN_ALIGN_16BYTES : IMAGE_SCN_ALIGN_4BYTES; 1214 1215 int segbg = 1216 MsCoffObj_getsegment(".tls$AAA", IMAGE_SCN_CNT_INITIALIZED_DATA | 1217 align_ | 1218 IMAGE_SCN_MEM_READ | 1219 IMAGE_SCN_MEM_WRITE); 1220 int segen = 1221 MsCoffObj_getsegment(".tls$AAC", IMAGE_SCN_CNT_INITIALIZED_DATA | 1222 align_ | 1223 IMAGE_SCN_MEM_READ | 1224 IMAGE_SCN_MEM_WRITE); 1225 1226 /* Create symbol _minfo_beg that sits just before the .tls$AAB section 1227 */ 1228 Symbol *minfo_beg = symbol_name("_tlsstart", SC.global, tspvoid); 1229 minfo_beg.Sseg = segbg; 1230 minfo_beg.Soffset = 0; 1231 symbuf.write((&minfo_beg)[0 .. 1]); 1232 MsCoffObj_bytes(segbg, 0, I64 ? 8 : 4, null); 1233 1234 /* Create symbol _minfo_end that sits just after the .tls$AAB section 1235 */ 1236 Symbol *minfo_end = symbol_name("_tlsend", SC.global, tspvoid); 1237 minfo_end.Sseg = segen; 1238 minfo_end.Soffset = 0; 1239 symbuf.write((&minfo_end)[0 .. 1]); 1240 MsCoffObj_bytes(segen, 0, I64 ? 8 : 4, null); 1241 } 1242 } 1243 } 1244 1245 /********************************* 1246 * Setup for Symbol s to go into a COMDAT segment. 1247 * Output (if s is a function): 1248 * cseg segment index of new current code segment 1249 * Offset(cseg) starting offset in cseg 1250 * Returns: 1251 * "segment index" of COMDAT 1252 */ 1253 1254 int MsCoffObj_comdatsize(Symbol *s, targ_size_t symsize) 1255 { 1256 return MsCoffObj_comdat(s); 1257 } 1258 1259 @trusted 1260 int MsCoffObj_comdat(Symbol *s) 1261 { 1262 uint align_; 1263 1264 //printf("MsCoffObj_comdat(Symbol* %s)\n",s.Sident.ptr); 1265 //symbol_print(s); 1266 //symbol_debug(s); 1267 1268 if (tyfunc(s.ty())) 1269 { 1270 align_ = I64 ? 16 : 4; 1271 s.Sseg = MsCoffObj_getsegment(".text", IMAGE_SCN_CNT_CODE | 1272 IMAGE_SCN_LNK_COMDAT | 1273 (I64 ? IMAGE_SCN_ALIGN_16BYTES : IMAGE_SCN_ALIGN_4BYTES) | 1274 IMAGE_SCN_MEM_EXECUTE | 1275 IMAGE_SCN_MEM_READ); 1276 } 1277 else if ((s.ty() & mTYLINK) == mTYthread) 1278 { 1279 s.Sfl = FLtlsdata; 1280 align_ = 16; 1281 s.Sseg = MsCoffObj_getsegment(".tls$AAB", IMAGE_SCN_CNT_INITIALIZED_DATA | 1282 IMAGE_SCN_LNK_COMDAT | 1283 IMAGE_SCN_ALIGN_16BYTES | 1284 IMAGE_SCN_MEM_READ | 1285 IMAGE_SCN_MEM_WRITE); 1286 MsCoffObj_data_start(s, align_, s.Sseg); 1287 } 1288 else 1289 { 1290 s.Sfl = FLdata; 1291 align_ = 16; 1292 s.Sseg = MsCoffObj_getsegment(".data$B", IMAGE_SCN_CNT_INITIALIZED_DATA | 1293 IMAGE_SCN_LNK_COMDAT | 1294 IMAGE_SCN_ALIGN_16BYTES | 1295 IMAGE_SCN_MEM_READ | 1296 IMAGE_SCN_MEM_WRITE); 1297 } 1298 // find or create new segment 1299 if (s.Salignment > align_) 1300 { SegData[s.Sseg].SDalignment = s.Salignment; 1301 assert(s.Salignment >= -1); 1302 } 1303 s.Soffset = SegData[s.Sseg].SDoffset; 1304 if (s.Sfl == FLdata || s.Sfl == FLtlsdata) 1305 { // Code symbols are 'published' by MsCoffObj_func_start() 1306 1307 MsCoffObj_pubdef(s.Sseg,s,s.Soffset); 1308 } 1309 return s.Sseg; 1310 } 1311 1312 @trusted 1313 int MsCoffObj_readonly_comdat(Symbol *s) 1314 { 1315 //printf("MsCoffObj_readonly_comdat(Symbol* %s)\n",s.Sident.ptr); 1316 //symbol_print(s); 1317 symbol_debug(s); 1318 1319 s.Sfl = FLdata; 1320 s.Sseg = MsCoffObj_getsegment(".rdata", IMAGE_SCN_CNT_INITIALIZED_DATA | 1321 IMAGE_SCN_LNK_COMDAT | 1322 IMAGE_SCN_ALIGN_16BYTES | 1323 IMAGE_SCN_MEM_READ); 1324 1325 SegData[s.Sseg].SDalignment = s.Salignment; 1326 assert(s.Salignment >= -1); 1327 s.Soffset = SegData[s.Sseg].SDoffset; 1328 if (s.Sfl == FLdata || s.Sfl == FLtlsdata) 1329 { // Code symbols are 'published' by MsCoffObj_func_start() 1330 1331 MsCoffObj_pubdef(s.Sseg,s,s.Soffset); 1332 } 1333 return s.Sseg; 1334 } 1335 1336 1337 /*********************************** 1338 * Returns: 1339 * jump table segment for function s 1340 */ 1341 @trusted 1342 int MsCoffObj_jmpTableSegment(Symbol *s) 1343 { 1344 return (config.flags & CFGromable) ? cseg : DATA; 1345 } 1346 1347 1348 /********************************** 1349 * Get segment, which may already exist. 1350 * Input: 1351 * flags2 put out some data for this, so the linker will keep things in order 1352 * Returns: 1353 * segment index of found or newly created segment 1354 */ 1355 1356 @trusted 1357 segidx_t MsCoffObj_getsegment(const(char)* sectname, uint flags) 1358 { 1359 //printf("getsegment(%s)\n", sectname); 1360 assert(strlen(sectname) <= 8); // so it won't go into string_table 1361 if (!(flags & IMAGE_SCN_LNK_COMDAT)) 1362 { 1363 for (segidx_t seg = 1; seg < SegData.length; seg++) 1364 { seg_data *pseg = SegData[seg]; 1365 if (!(ScnhdrTab[pseg.SDshtidx].Characteristics & IMAGE_SCN_LNK_COMDAT) && 1366 strncmp(cast(const(char)* )ScnhdrTab[pseg.SDshtidx].Name, sectname, 8) == 0) 1367 { 1368 //printf("\t%s\n", sectname); 1369 return seg; // return existing segment 1370 } 1371 } 1372 } 1373 1374 segidx_t seg = MsCoffObj_getsegment2(MsCoffObj_addScnhdr(sectname, flags)); 1375 1376 //printf("\tSegData.length = %d\n", SegData.length); 1377 //printf("\tseg = %d, %d, %s\n", seg, SegData[seg].SDshtidx, ScnhdrTab[SegData[seg].SDshtidx].s_name); 1378 return seg; 1379 } 1380 1381 /****************************************** 1382 * Create a new segment corresponding to an existing scnhdr index shtidx 1383 */ 1384 1385 @trusted 1386 segidx_t MsCoffObj_getsegment2(IDXSEC shtidx) 1387 { 1388 const segidx_t seg = cast(segidx_t)SegData.length; 1389 seg_data** ppseg = SegData.push(); 1390 1391 seg_data* pseg = *ppseg; 1392 if (pseg) 1393 { 1394 OutBuffer *b1 = pseg.SDbuf; 1395 OutBuffer *b2 = pseg.SDrel; 1396 memset(pseg, 0, (seg_data).sizeof); 1397 if (b1) 1398 b1.reset(); 1399 else 1400 { 1401 b1 = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 1402 if (!b1) 1403 err_nomem(); 1404 b1.reserve(4096); 1405 } 1406 if (b2) 1407 b2.reset(); 1408 pseg.SDbuf = b1; 1409 pseg.SDrel = b2; 1410 } 1411 else 1412 { 1413 pseg = cast(seg_data *)mem_calloc((seg_data).sizeof); 1414 SegData[seg] = pseg; 1415 if (!(ScnhdrTab[shtidx].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) 1416 1417 { 1418 pseg.SDbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 1419 if (!pseg.SDbuf) 1420 err_nomem(); 1421 pseg.SDbuf.reserve(4096); 1422 } 1423 } 1424 1425 //dbg_printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf); 1426 1427 pseg.SDseg = seg; 1428 pseg.SDoffset = 0; 1429 1430 pseg.SDshtidx = shtidx; 1431 pseg.SDaranges_offset = 0; 1432 pseg.SDlinnum_data.reset(); 1433 1434 //printf("SegData.length = %d\n", SegData.length); 1435 return seg; 1436 } 1437 1438 /******************************************** 1439 * Add new scnhdr. 1440 * Returns: 1441 * scnhdr number for added scnhdr 1442 */ 1443 1444 @trusted 1445 IDXSEC MsCoffObj_addScnhdr(const(char)* scnhdr_name, uint flags) 1446 { 1447 IMAGE_SECTION_HEADER sec; 1448 memset(&sec, 0, (sec).sizeof); 1449 size_t len = strlen(scnhdr_name); 1450 if (len > 8) 1451 { // Use /nnnn form 1452 IDXSTR idx = MsCoffObj_addstr(string_table, scnhdr_name[0 .. len]); 1453 snprintf(cast(char *)sec.Name, IMAGE_SIZEOF_SHORT_NAME, "/%d", idx); 1454 } 1455 else 1456 memcpy(sec.Name.ptr, scnhdr_name, len); 1457 sec.Characteristics = flags; 1458 ScnhdrBuf.write(cast(void *)&sec, (sec).sizeof); 1459 return ++scnhdr_cnt; 1460 } 1461 1462 /******************************** 1463 * Define a new code segment. 1464 * Input: 1465 * name name of segment, if null then revert to default 1466 * suffix 0 use name as is 1467 * 1 append "_TEXT" to name 1468 * Output: 1469 * cseg segment index of new current code segment 1470 * Offset(cseg) starting offset in cseg 1471 * Returns: 1472 * segment index of newly created code segment 1473 */ 1474 1475 int MsCoffObj_codeseg(const char *name,int suffix) 1476 { 1477 //dbg_printf("MsCoffObj_codeseg(%s,%x)\n",name,suffix); 1478 return 0; 1479 } 1480 1481 /********************************* 1482 * Define segments for Thread Local Storage. 1483 * Output: 1484 * seg_tlsseg set to segment number for TLS segment. 1485 * Returns: 1486 * segment for TLS segment 1487 */ 1488 1489 @trusted 1490 seg_data *MsCoffObj_tlsseg() 1491 { 1492 //printf("MsCoffObj_tlsseg\n"); 1493 1494 if (seg_tlsseg == UNKNOWN) 1495 { 1496 seg_tlsseg = MsCoffObj_getsegment(".tls$AAB", IMAGE_SCN_CNT_INITIALIZED_DATA | 1497 IMAGE_SCN_LNK_COMDAT | 1498 IMAGE_SCN_ALIGN_16BYTES | 1499 IMAGE_SCN_MEM_READ | 1500 IMAGE_SCN_MEM_WRITE); 1501 } 1502 return SegData[seg_tlsseg]; 1503 } 1504 1505 1506 /********************************* 1507 * Define segments for Thread Local Storage. 1508 * Output: 1509 * seg_tlsseg_bss set to segment number for TLS segment. 1510 * Returns: 1511 * segment for TLS segment 1512 */ 1513 1514 seg_data *MsCoffObj_tlsseg_bss() 1515 { 1516 /* No thread local bss for MS-COFF 1517 */ 1518 return MsCoffObj_tlsseg(); 1519 } 1520 1521 seg_data *MsCoffObj_tlsseg_data() 1522 { 1523 // specific for Mach-O 1524 assert(0); 1525 } 1526 1527 /************************************* 1528 * Return segment indices for .pdata and .xdata sections 1529 */ 1530 1531 @trusted 1532 segidx_t MsCoffObj_seg_pdata() 1533 { 1534 if (segidx_pdata == UNKNOWN) 1535 { 1536 segidx_pdata = MsCoffObj_getsegment(".pdata", IMAGE_SCN_CNT_INITIALIZED_DATA | 1537 IMAGE_SCN_ALIGN_4BYTES | 1538 IMAGE_SCN_MEM_READ); 1539 } 1540 return segidx_pdata; 1541 } 1542 1543 @trusted 1544 segidx_t MsCoffObj_seg_xdata() 1545 { 1546 if (segidx_xdata == UNKNOWN) 1547 { 1548 segidx_xdata = MsCoffObj_getsegment(".xdata", IMAGE_SCN_CNT_INITIALIZED_DATA | 1549 IMAGE_SCN_ALIGN_4BYTES | 1550 IMAGE_SCN_MEM_READ); 1551 } 1552 return segidx_xdata; 1553 } 1554 1555 @trusted 1556 segidx_t MsCoffObj_seg_pdata_comdat(Symbol *sfunc) 1557 { 1558 segidx_t seg = MsCoffObj_getsegment(".pdata", IMAGE_SCN_CNT_INITIALIZED_DATA | 1559 IMAGE_SCN_ALIGN_4BYTES | 1560 IMAGE_SCN_MEM_READ | 1561 IMAGE_SCN_LNK_COMDAT); 1562 SegData[seg].SDassocseg = sfunc.Sseg; 1563 return seg; 1564 } 1565 1566 @trusted 1567 segidx_t MsCoffObj_seg_xdata_comdat(Symbol *sfunc) 1568 { 1569 segidx_t seg = MsCoffObj_getsegment(".xdata", IMAGE_SCN_CNT_INITIALIZED_DATA | 1570 IMAGE_SCN_ALIGN_4BYTES | 1571 IMAGE_SCN_MEM_READ | 1572 IMAGE_SCN_LNK_COMDAT); 1573 SegData[seg].SDassocseg = sfunc.Sseg; 1574 return seg; 1575 } 1576 1577 @trusted 1578 segidx_t MsCoffObj_seg_debugS() 1579 { 1580 if (segidx_debugS == UNKNOWN) 1581 { 1582 segidx_debugS = MsCoffObj_getsegment(".debug$S", IMAGE_SCN_CNT_INITIALIZED_DATA | 1583 IMAGE_SCN_ALIGN_1BYTES | 1584 IMAGE_SCN_MEM_READ | 1585 IMAGE_SCN_MEM_DISCARDABLE); 1586 } 1587 return segidx_debugS; 1588 } 1589 1590 1591 @trusted 1592 segidx_t MsCoffObj_seg_debugS_comdat(Symbol *sfunc) 1593 { 1594 //printf("associated with seg %d\n", sfunc.Sseg); 1595 segidx_t seg = MsCoffObj_getsegment(".debug$S", IMAGE_SCN_CNT_INITIALIZED_DATA | 1596 IMAGE_SCN_ALIGN_1BYTES | 1597 IMAGE_SCN_MEM_READ | 1598 IMAGE_SCN_LNK_COMDAT | 1599 IMAGE_SCN_MEM_DISCARDABLE); 1600 SegData[seg].SDassocseg = sfunc.Sseg; 1601 return seg; 1602 } 1603 1604 segidx_t MsCoffObj_seg_debugT() 1605 { 1606 segidx_t seg = MsCoffObj_getsegment(".debug$T", IMAGE_SCN_CNT_INITIALIZED_DATA | 1607 IMAGE_SCN_ALIGN_1BYTES | 1608 IMAGE_SCN_MEM_READ | 1609 IMAGE_SCN_MEM_DISCARDABLE); 1610 return seg; 1611 } 1612 1613 @trusted 1614 segidx_t MsCoffObj_seg_drectve() 1615 { 1616 if (segidx_drectve == UNKNOWN) 1617 { 1618 segidx_drectve = MsCoffObj_getsegment(".drectve", IMAGE_SCN_LNK_INFO | 1619 IMAGE_SCN_ALIGN_1BYTES | 1620 IMAGE_SCN_LNK_REMOVE); // linker commands 1621 } 1622 return segidx_drectve; 1623 } 1624 1625 1626 /******************************* 1627 * Output an alias definition record. 1628 */ 1629 1630 void MsCoffObj_alias(const(char)* n1,const(char)* n2) 1631 { 1632 //printf("MsCoffObj_alias(%s,%s)\n",n1,n2); 1633 assert(0); 1634 static if (0) // NOT_DONE 1635 { 1636 uint len; 1637 char *buffer; 1638 1639 buffer = cast(char *) alloca(strlen(n1) + strlen(n2) + 2 * ONS_OHD); 1640 len = obj_namestring(buffer,n1); 1641 len += obj_namestring(buffer + len,n2); 1642 objrecord(ALIAS,buffer,len); 1643 } 1644 } 1645 1646 @trusted 1647 private extern (D) char* unsstr(uint value) 1648 { 1649 __gshared char[64] buffer; 1650 1651 snprintf (buffer.ptr, buffer.length, "%d", value); 1652 return buffer.ptr; 1653 } 1654 1655 /******************************* 1656 * Mangle a name. 1657 * Returns: 1658 * mangled name 1659 */ 1660 1661 @trusted 1662 private extern (D) 1663 char *obj_mangle2(Symbol *s,char *dest) 1664 { 1665 size_t len; 1666 const(char)* name; 1667 1668 //printf("MsCoffObj_mangle(s = %p, '%s'), mangle = x%x\n",s,s.Sident.ptr,type_mangle(s.Stype)); 1669 symbol_debug(s); 1670 assert(dest); 1671 1672 // C++ name mangling is handled by front end 1673 name = &s.Sident[0]; 1674 1675 len = strlen(name); // # of bytes in name 1676 //dbg_printf("len %d\n",len); 1677 switch (type_mangle(s.Stype)) 1678 { 1679 case mTYman_pas: // if upper case 1680 case mTYman_for: 1681 if (len >= DEST_LEN) 1682 dest = cast(char *)mem_malloc(len + 1); 1683 memcpy(dest,name,len + 1); // copy in name and ending 0 1684 strupr(dest); // to upper case 1685 break; 1686 case mTYman_std: 1687 if (!(config.flags4 & CFG4oldstdmangle) && 1688 config.exe == EX_WIN32 && tyfunc(s.ty()) && 1689 !variadic(s.Stype)) 1690 { 1691 char *pstr = unsstr(type_paramsize(s.Stype)); 1692 size_t pstrlen = strlen(pstr); 1693 size_t prelen = I32 ? 1 : 0; 1694 size_t destlen = prelen + len + 1 + pstrlen + 1; 1695 1696 if (destlen > DEST_LEN) 1697 dest = cast(char *)mem_malloc(destlen); 1698 dest[0] = '_'; 1699 memcpy(dest + prelen,name,len); 1700 dest[prelen + len] = '@'; 1701 memcpy(dest + prelen + 1 + len, pstr, pstrlen + 1); 1702 break; 1703 } 1704 goto case; 1705 1706 case mTYman_cpp: 1707 case mTYman_sys: 1708 case_mTYman_c64: 1709 case 0: 1710 if (len >= DEST_LEN) 1711 dest = cast(char *)mem_malloc(len + 1); 1712 memcpy(dest,name,len+1);// copy in name and trailing 0 1713 break; 1714 1715 case mTYman_c: 1716 case mTYman_d: 1717 if(I64) 1718 goto case_mTYman_c64; 1719 // Prepend _ to identifier 1720 if (len >= DEST_LEN - 1) 1721 dest = cast(char *)mem_malloc(1 + len + 1); 1722 dest[0] = '_'; 1723 memcpy(dest + 1,name,len+1);// copy in name and trailing 0 1724 break; 1725 1726 default: 1727 debug 1728 { 1729 printf("mangling %x\n",type_mangle(s.Stype)); 1730 symbol_print(s); 1731 } 1732 printf("%d\n", type_mangle(s.Stype)); 1733 assert(0); 1734 } 1735 //dbg_printf("\t %s\n",dest); 1736 return dest; 1737 } 1738 1739 /******************************* 1740 * Export a function name. 1741 */ 1742 1743 @trusted 1744 void MsCoffObj_export_symbol(Symbol *s,uint argsize) 1745 { 1746 char[DEST_LEN+1] dest = void; 1747 char *destr = obj_mangle2(s, dest.ptr); 1748 1749 int seg = MsCoffObj_seg_drectve(); 1750 //printf("MsCoffObj_export_symbol(%s,%d)\n",s.Sident.ptr,argsize); 1751 SegData[seg].SDbuf.write(" /EXPORT:".ptr, 9); 1752 SegData[seg].SDbuf.write(dest.ptr, cast(uint)strlen(dest.ptr)); 1753 } 1754 1755 /******************************* 1756 * Update data information about symbol 1757 * align for output and assign segment 1758 * if not already specified. 1759 * 1760 * Input: 1761 * sdata data symbol 1762 * datasize output size 1763 * seg default seg if not known 1764 * Returns: 1765 * actual seg 1766 */ 1767 1768 @trusted 1769 segidx_t MsCoffObj_data_start(Symbol *sdata, targ_size_t datasize, segidx_t seg) 1770 { 1771 targ_size_t alignbytes; 1772 1773 //printf("MsCoffObj_data_start(%s,size %d,seg %d)\n",sdata.Sident.ptr,cast(int)datasize,seg); 1774 //symbol_print(sdata); 1775 1776 assert(sdata.Sseg); 1777 if (sdata.Sseg == UNKNOWN) // if we don't know then there 1778 sdata.Sseg = seg; // wasn't any segment override 1779 else 1780 seg = sdata.Sseg; 1781 targ_size_t offset = Offset(seg); 1782 if (sdata.Salignment > 0) 1783 { if (SegData[seg].SDalignment < sdata.Salignment) 1784 SegData[seg].SDalignment = sdata.Salignment; 1785 alignbytes = ((offset + sdata.Salignment - 1) & ~(sdata.Salignment - 1)) - offset; 1786 } 1787 else 1788 alignbytes = _align(datasize, offset) - offset; 1789 if (alignbytes) 1790 MsCoffObj_lidata(seg, offset, alignbytes); 1791 sdata.Soffset = offset + alignbytes; 1792 return seg; 1793 } 1794 1795 /******************************* 1796 * Update function info before codgen 1797 * 1798 * If code for this function is in a different segment 1799 * than the current default in cseg, switch cseg to new segment. 1800 */ 1801 1802 @trusted 1803 void MsCoffObj_func_start(Symbol *sfunc) 1804 { 1805 //printf("MsCoffObj_func_start(%s)\n",sfunc.Sident.ptr); 1806 symbol_debug(sfunc); 1807 1808 assert(sfunc.Sseg); 1809 if (sfunc.Sseg == UNKNOWN) 1810 sfunc.Sseg = CODE; 1811 //printf("sfunc.Sseg %d CODE %d cseg %d Coffset x%x\n",sfunc.Sseg,CODE,cseg,Offset(cseg)); 1812 cseg = sfunc.Sseg; 1813 assert(cseg == CODE || cseg > UDATA); 1814 MsCoffObj_pubdef(cseg, sfunc, Offset(cseg)); 1815 sfunc.Soffset = Offset(cseg); 1816 1817 if (config.fulltypes) 1818 cv8_func_start(sfunc); 1819 } 1820 1821 /******************************* 1822 * Update function info after codgen 1823 */ 1824 1825 @trusted 1826 void MsCoffObj_func_term(Symbol *sfunc) 1827 { 1828 //dbg_printf("MsCoffObj_func_term(%s) offset %x, Coffset %x symidx %d\n", 1829 // sfunc.Sident.ptr, sfunc.Soffset,Offset(cseg),sfunc.Sxtrnnum); 1830 1831 if (config.fulltypes) 1832 cv8_func_term(sfunc); 1833 } 1834 1835 /******************************** 1836 * Output a public definition. 1837 * Params: 1838 * seg = segment index that symbol is defined in 1839 * s = symbol 1840 * offset = offset of name within segment 1841 */ 1842 1843 @trusted 1844 void MsCoffObj_pubdef(segidx_t seg, Symbol *s, targ_size_t offset) 1845 { 1846 //printf("MsCoffObj_pubdef(%d:x%x s=%p, %s)\n", seg, cast(int)offset, s, s.Sident.ptr); 1847 //symbol_print(s); 1848 1849 symbol_debug(s); 1850 1851 s.Soffset = offset; 1852 s.Sseg = seg; 1853 switch (s.Sclass) 1854 { 1855 case SC.global: 1856 case SC.inline: 1857 symbuf.write((&s)[0 .. 1]); 1858 break; 1859 case SC.comdat: 1860 case SC.comdef: 1861 symbuf.write((&s)[0 .. 1]); 1862 break; 1863 default: 1864 symbuf.write((&s)[0 .. 1]); 1865 break; 1866 } 1867 //printf("%p\n", *cast(void**)symbuf.buf); 1868 s.Sxtrnnum = 1; 1869 } 1870 1871 void MsCoffObj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize) 1872 { 1873 MsCoffObj_pubdef(seg, s, offset); 1874 } 1875 1876 /******************************* 1877 * Output an external symbol for name. 1878 * Input: 1879 * name Name to do EXTDEF on 1880 * (Not to be mangled) 1881 * Returns: 1882 * Symbol table index of the definition 1883 * NOTE: Numbers will not be linear. 1884 */ 1885 1886 @trusted 1887 int MsCoffObj_external_def(const(char)* name) 1888 { 1889 //printf("MsCoffObj_external_def('%s')\n",name); 1890 assert(name); 1891 Symbol *s = symbol_name(name[0 .. strlen(name)], SC.extern_, tspvoid); 1892 symbuf.write((&s)[0 .. 1]); 1893 return 0; 1894 } 1895 1896 1897 /******************************* 1898 * Output an external for existing symbol. 1899 * Input: 1900 * s Symbol to do EXTDEF on 1901 * (Name is to be mangled) 1902 * Returns: 1903 * Symbol table index of the definition 1904 * NOTE: Numbers will not be linear. 1905 */ 1906 1907 @trusted 1908 int MsCoffObj_external(Symbol *s) 1909 { 1910 //printf("MsCoffObj_external('%s') %x\n",s.Sident.ptr,s.Svalue); 1911 symbol_debug(s); 1912 symbuf.write((&s)[0 .. 1]); 1913 s.Sxtrnnum = 1; 1914 return 1; 1915 } 1916 1917 /******************************* 1918 * Output a common block definition. 1919 * Params: 1920 * s = Symbol for common block 1921 * size = size in bytes of each elem 1922 * count = number of elems 1923 * Returns: 1924 * Symbol table index for symbol 1925 */ 1926 1927 @trusted 1928 int MsCoffObj_common_block(Symbol *s,targ_size_t size,targ_size_t count) 1929 { 1930 //printf("MsCoffObj_common_block('%s', size=%d, count=%d)\n",s.Sident.ptr,size,count); 1931 symbol_debug(s); 1932 1933 // can't have code or thread local comdef's 1934 assert(!(s.ty() & mTYthread)); 1935 1936 s.Sfl = FLudata; 1937 uint align_ = 16; 1938 s.Sseg = MsCoffObj_getsegment(".bss$B", IMAGE_SCN_CNT_UNINITIALIZED_DATA | 1939 IMAGE_SCN_LNK_COMDAT | 1940 IMAGE_SCN_ALIGN_16BYTES | 1941 IMAGE_SCN_MEM_READ | 1942 IMAGE_SCN_MEM_WRITE); 1943 if (s.Salignment > align_) 1944 { 1945 SegData[s.Sseg].SDalignment = s.Salignment; 1946 assert(s.Salignment >= -1); 1947 } 1948 s.Soffset = SegData[s.Sseg].SDoffset; 1949 SegData[s.Sseg].SDsym = s; 1950 SegData[s.Sseg].SDoffset += count * size; 1951 1952 MsCoffObj_pubdef(s.Sseg, s, s.Soffset); 1953 1954 return 1; // should return void 1955 } 1956 1957 int MsCoffObj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count) 1958 { 1959 return MsCoffObj_common_block(s, size, count); 1960 } 1961 1962 /*************************************** 1963 * Append an iterated data block of 0s. 1964 * (uninitialized data only) 1965 */ 1966 1967 void MsCoffObj_write_zeros(seg_data *pseg, targ_size_t count) 1968 { 1969 MsCoffObj_lidata(pseg.SDseg, pseg.SDoffset, count); 1970 } 1971 1972 /*************************************** 1973 * Output an iterated data block of 0s. 1974 * 1975 * For boundary alignment and initialization 1976 */ 1977 1978 @trusted 1979 void MsCoffObj_lidata(segidx_t seg,targ_size_t offset,targ_size_t count) 1980 { 1981 //printf("MsCoffObj_lidata(%d,%x,%d)\n",seg,offset,count); 1982 size_t idx = SegData[seg].SDshtidx; 1983 if ((ScnhdrTab[idx].Characteristics) & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 1984 { // Use SDoffset to record size of bss section 1985 SegData[seg].SDoffset += count; 1986 } 1987 else 1988 { 1989 MsCoffObj_bytes(seg, offset, cast(uint)count, null); 1990 } 1991 } 1992 1993 /*********************************** 1994 * Append byte to segment. 1995 */ 1996 1997 void MsCoffObj_write_byte(seg_data *pseg, uint byte_) 1998 { 1999 MsCoffObj_byte(pseg.SDseg, pseg.SDoffset, byte_); 2000 } 2001 2002 /************************************ 2003 * Output byte_ to object file. 2004 */ 2005 2006 @trusted 2007 void MsCoffObj_byte(segidx_t seg,targ_size_t offset,uint byte_) 2008 { 2009 OutBuffer *buf = SegData[seg].SDbuf; 2010 int save = cast(int)buf.length(); 2011 //dbg_printf("MsCoffObj_byte(seg=%d, offset=x%lx, byte=x%x)\n",seg,offset,byte_); 2012 buf.setsize(cast(uint)offset); 2013 buf.writeByte(byte_); 2014 if (save > offset+1) 2015 buf.setsize(save); 2016 else 2017 SegData[seg].SDoffset = offset+1; 2018 //dbg_printf("\tsize now %d\n",buf.length()); 2019 } 2020 2021 /*********************************** 2022 * Append bytes to segment. 2023 */ 2024 2025 @trusted 2026 void MsCoffObj_write_bytes(seg_data *pseg, const(void[]) a) 2027 { 2028 MsCoffObj_bytes(pseg.SDseg, pseg.SDoffset, a.length, a.ptr); 2029 } 2030 2031 /************************************ 2032 * Output bytes to object file. 2033 * Returns: 2034 * nbytes 2035 */ 2036 2037 @trusted 2038 size_t MsCoffObj_bytes(segidx_t seg, targ_size_t offset, size_t nbytes, const(void)* p) 2039 { 2040 static if (0) 2041 { 2042 if (!(seg >= 0 && seg < SegData.length)) 2043 { printf("MsCoffObj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length); 2044 *cast(char*)0=0; 2045 } 2046 } 2047 assert(seg >= 0 && seg < SegData.length); 2048 OutBuffer *buf = SegData[seg].SDbuf; 2049 if (buf == null) 2050 { 2051 //printf("MsCoffObj_bytes(seg=%d, offset=x%llx, nbytes=%d, p=x%x)\n", seg, offset, nbytes, p); 2052 //raise(SIGSEGV); 2053 assert(buf != null); 2054 } 2055 const save = buf.length(); 2056 //dbg_printf("MsCoffObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n", 2057 //seg,offset,nbytes,p); 2058 buf.position(cast(size_t)offset, nbytes); 2059 if (p) 2060 buf.write(p, nbytes); 2061 else // Zero out the bytes 2062 buf.writezeros(nbytes); 2063 2064 if (save > offset+nbytes) 2065 buf.setsize(save); 2066 else 2067 SegData[seg].SDoffset = offset+nbytes; 2068 return nbytes; 2069 } 2070 2071 /********************************************* 2072 * Add a relocation entry for seg/offset. 2073 */ 2074 2075 @trusted 2076 void MsCoffObj_addrel(segidx_t seg, targ_size_t offset, Symbol *targsym, 2077 uint targseg, int rtype, int val) 2078 { 2079 //printf("addrel()\n"); 2080 if (!targsym) 2081 { // Generate one 2082 targsym = symbol_generate(SC.static_, tstypes[TYint]); 2083 targsym.Sseg = targseg; 2084 targsym.Soffset = val; 2085 symbuf.write((&targsym)[0 .. 1]); 2086 } 2087 2088 Relocation rel = void; 2089 rel.offset = offset; 2090 rel.targsym = targsym; 2091 rel.targseg = targseg; 2092 rel.rtype = cast(ubyte)rtype; 2093 rel.funcsym = funcsym_p; 2094 rel.val = cast(short)val; 2095 seg_data *pseg = SegData[seg]; 2096 if (!pseg.SDrel) 2097 { 2098 pseg.SDrel = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2099 if (!pseg.SDrel) 2100 err_nomem(); 2101 } 2102 pseg.SDrel.write((&rel)[0 .. 1]); 2103 } 2104 2105 /**************************************** 2106 * Sort the relocation entry buffer. 2107 */ 2108 2109 extern (C) { 2110 @trusted 2111 private int mscoff_rel_fp(scope const(void*) e1, scope const(void*) e2) 2112 { Relocation *r1 = cast(Relocation *)e1; 2113 Relocation *r2 = cast(Relocation *)e2; 2114 2115 return cast(int)(r1.offset - r2.offset); 2116 } 2117 } 2118 2119 /******************************* 2120 * Refer to address that is in the data segment. 2121 * Input: 2122 * seg:offset = the address being fixed up 2123 * val = displacement from start of target segment 2124 * targetdatum = target segment number (DATA, CDATA or UDATA, etc.) 2125 * flags = CFoff, CFseg 2126 * Example: 2127 * int *abc = &def[3]; 2128 * to allocate storage: 2129 * MsCoffObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA); 2130 */ 2131 2132 @trusted 2133 void MsCoffObj_reftodatseg(segidx_t seg,targ_size_t offset,targ_size_t val, 2134 uint targetdatum,int flags) 2135 { 2136 OutBuffer *buf = SegData[seg].SDbuf; 2137 int save = cast(int)buf.length(); 2138 buf.setsize(cast(uint)offset); 2139 static if (0) 2140 { 2141 printf("MsCoffObj_reftodatseg(seg:offset=%d:x%llx, val=x%llx, targetdatum %x, flags %x )\n", 2142 seg,offset,val,targetdatum,flags); 2143 } 2144 assert(seg != 0); 2145 if (SegData[seg].isCode() && SegData[targetdatum].isCode()) 2146 { 2147 assert(0); 2148 } 2149 MsCoffObj_addrel(seg, offset, null, targetdatum, RELaddr, 0); 2150 if (I64) 2151 { 2152 if (flags & CFoffset64) 2153 { 2154 buf.write64(val); 2155 if (save > offset + 8) 2156 buf.setsize(save); 2157 return; 2158 } 2159 } 2160 buf.write32(cast(int)val); 2161 if (save > offset + 4) 2162 buf.setsize(save); 2163 } 2164 2165 /******************************* 2166 * Refer to address that is in the current function code (funcsym_p). 2167 * Only offsets are output, regardless of the memory model. 2168 * Used to put values in switch address tables. 2169 * Input: 2170 * seg = where the address is going (CODE or DATA) 2171 * offset = offset within seg 2172 * val = displacement from start of this module 2173 */ 2174 2175 @trusted 2176 void MsCoffObj_reftocodeseg(segidx_t seg,targ_size_t offset,targ_size_t val) 2177 { 2178 //printf("MsCoffObj_reftocodeseg(seg=%d, offset=x%lx, val=x%lx )\n",seg,cast(uint)offset,cast(uint)val); 2179 assert(seg > 0); 2180 OutBuffer *buf = SegData[seg].SDbuf; 2181 int save = cast(int)buf.length(); 2182 buf.setsize(cast(uint)offset); 2183 val -= funcsym_p.Soffset; 2184 if (I32) 2185 MsCoffObj_addrel(seg, offset, funcsym_p, 0, RELaddr, 0); 2186 // MsCoffObj_addrel(seg, offset, funcsym_p, 0, RELaddr); 2187 // if (I64) 2188 // buf.write64(val); 2189 // else 2190 buf.write32(cast(int)val); 2191 if (save > offset + 4) 2192 buf.setsize(save); 2193 } 2194 2195 /******************************* 2196 * Refer to an identifier. 2197 * Params: 2198 * seg = where the address is going (CODE or DATA) 2199 * offset = offset within seg 2200 * s = Symbol table entry for identifier 2201 * val = displacement from identifier 2202 * flags = CFselfrel: self-relative 2203 * CFseg: get segment 2204 * CFoff: get offset 2205 * CFpc32: [RIP] addressing, val is 0, -1, -2 or -4 2206 * CFoffset64: 8 byte offset for 64 bit builds 2207 * Returns: 2208 * number of bytes in reference (4 or 8) 2209 */ 2210 2211 @trusted 2212 int MsCoffObj_reftoident(segidx_t seg, targ_size_t offset, Symbol *s, targ_size_t val, 2213 int flags) 2214 { 2215 int refsize = (flags & CFoffset64) ? 8 : 4; 2216 if (flags & CFseg) 2217 refsize += 2; 2218 static if (0) 2219 { 2220 printf("\nMsCoffObj_reftoident('%s' seg %d, offset x%llx, val x%llx, flags x%x)\n", 2221 s.Sident.ptr,seg,cast(ulong)offset,cast(ulong)val,flags); 2222 //printf("refsize = %d\n", refsize); 2223 //dbg_printf("Sseg = %d, Sxtrnnum = %d\n",s.Sseg,s.Sxtrnnum); 2224 //symbol_print(s); 2225 } 2226 assert(seg > 0); 2227 if (s.Sclass != SC.locstat && !s.Sxtrnnum) 2228 { // It may get defined later as public or local, so defer 2229 size_t numbyteswritten = addtofixlist(s, offset, seg, val, flags); 2230 assert(numbyteswritten == refsize); 2231 } 2232 else 2233 { 2234 if (I64 || I32) 2235 { 2236 //if (s.Sclass != SCcomdat) 2237 //val += s.Soffset; 2238 int v = 0; 2239 if (flags & CFpc32) 2240 { 2241 v = -((flags & CFREL) >> 24); 2242 assert(v >= -5 && v <= 0); 2243 } 2244 if (flags & CFselfrel) 2245 { 2246 MsCoffObj_addrel(seg, offset, s, 0, RELrel, v); 2247 } 2248 else if ((flags & (CFseg | CFoff)) == (CFseg | CFoff)) 2249 { 2250 MsCoffObj_addrel(seg, offset, s, 0, RELaddr32, v); 2251 MsCoffObj_addrel(seg, offset + 4, s, 0, RELseg, v); 2252 refsize = 6; // 4 bytes for offset, 2 for section 2253 } 2254 else 2255 { 2256 MsCoffObj_addrel(seg, offset, s, 0, RELaddr, v); 2257 } 2258 } 2259 else 2260 { 2261 if (SegData[seg].isCode() && flags & CFselfrel) 2262 { 2263 seg_data *pseg = SegData[jumpTableSeg]; 2264 val -= offset + 4; 2265 MsCoffObj_addrel(seg, offset, null, jumpTableSeg, RELrel, 0); 2266 } 2267 else if (SegData[seg].isCode() && 2268 ((s.Sclass != SC.extern_ && SegData[s.Sseg].isCode()) || s.Sclass == SC.locstat || 2269 s.Sclass == SC.static_)) 2270 { 2271 val += s.Soffset; 2272 MsCoffObj_addrel(seg, offset, null, s.Sseg, RELaddr, 0); 2273 } 2274 else if (SegData[seg].isCode() && !tyfunc(s.ty())) 2275 { 2276 seg_data *pseg = SegData[pointersSeg]; 2277 2278 if (!indirectsymbuf2) 2279 { 2280 indirectsymbuf2 = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2281 if (!indirectsymbuf2) 2282 err_nomem(); 2283 } 2284 else 2285 { // Look through indirectsym to see if it is already there 2286 int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof); 2287 Symbol **psym = cast(Symbol **)indirectsymbuf2.buf; 2288 for (int i = 0; i < n; i++) 2289 { // Linear search, pretty pathetic 2290 if (s == psym[i]) 2291 { val = i * 4; 2292 goto L2; 2293 } 2294 } 2295 } 2296 2297 val = pseg.SDbuf.length(); 2298 pseg.SDbuf.writezeros(_tysize[TYnptr]); 2299 2300 // Add symbol s to indirectsymbuf2 2301 indirectsymbuf2.write((&s)[0 .. 1]); 2302 2303 L2: 2304 //printf("MsCoffObj_reftoident: seg = %d, offset = x%x, s = %s, val = x%x, pointersSeg = %d\n", seg, offset, s.Sident.ptr, val, pointersSeg); 2305 MsCoffObj_addrel(seg, offset, null, pointersSeg, RELaddr, 0); 2306 } 2307 else 2308 { //val -= s.Soffset; 2309 // MsCoffObj_addrel(seg, offset, s, 0, RELaddr, 0); 2310 } 2311 } 2312 2313 OutBuffer *buf = SegData[seg].SDbuf; 2314 int save = cast(int)buf.length(); 2315 buf.setsize(cast(uint)offset); 2316 //printf("offset = x%llx, val = x%llx\n", offset, val); 2317 if (refsize == 8) 2318 buf.write64(val); 2319 else if (refsize == 4) 2320 buf.write32(cast(int)val); 2321 else if (refsize == 6) 2322 { 2323 buf.write32(cast(int)val); 2324 buf.write16(0); 2325 } 2326 else 2327 assert(0); 2328 if (save > offset + refsize) 2329 buf.setsize(save); 2330 } 2331 return refsize; 2332 } 2333 2334 /***************************************** 2335 * Generate far16 thunk. 2336 * Input: 2337 * s Symbol to generate a thunk for 2338 */ 2339 2340 void MsCoffObj_far16thunk(Symbol *s) 2341 { 2342 //dbg_printf("MsCoffObj_far16thunk('%s')\n", s.Sident.ptr); 2343 assert(0); 2344 } 2345 2346 /************************************** 2347 * Mark object file as using floating point. 2348 */ 2349 2350 @trusted 2351 void MsCoffObj_fltused() 2352 { 2353 //dbg_printf("MsCoffObj_fltused()\n"); 2354 /* Otherwise, we'll get the dreaded 2355 * "runtime error R6002 - floating point support not loaded" 2356 */ 2357 if (!floatused) 2358 { 2359 MsCoffObj_external_def("_fltused"); 2360 floatused = 1; 2361 } 2362 } 2363 2364 2365 @trusted 2366 int elf_align(int size, int foffset) 2367 { 2368 if (size <= 1) 2369 return foffset; 2370 int offset = (foffset + size - 1) & ~(size - 1); 2371 //printf("offset = x%lx, foffset = x%lx, size = x%lx\n", offset, foffset, cast(int)size); 2372 if (offset > foffset) 2373 fobjbuf.writezeros(offset - foffset); 2374 return offset; 2375 } 2376 2377 /*************************************** 2378 * Stuff pointer to ModuleInfo in its own segment. 2379 * Input: 2380 * scc symbol for ModuleInfo 2381 */ 2382 @trusted 2383 void MsCoffObj_moduleinfo(Symbol *scc) 2384 { 2385 int align_ = I64 ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES; 2386 2387 /* Module info sections 2388 */ 2389 const int seg = 2390 MsCoffObj_getsegment(".minfo$B", IMAGE_SCN_CNT_INITIALIZED_DATA | 2391 align_ | 2392 IMAGE_SCN_MEM_READ); 2393 //printf("MsCoffObj_moduleinfo(%s) seg = %d:x%x\n", scc.Sident.ptr, seg, Offset(seg)); 2394 2395 int flags = CFoff; 2396 if (I64) 2397 flags |= CFoffset64; 2398 SegData[seg].SDoffset += MsCoffObj_reftoident(seg, Offset(seg), scc, 0, flags); 2399 } 2400 2401 /********************************** 2402 * Reset code seg to existing seg. 2403 * Used after a COMDAT for a function is done. 2404 */ 2405 2406 @trusted 2407 void MsCoffObj_setcodeseg(int seg) 2408 { 2409 assert(0 < seg && seg < SegData.length); 2410 cseg = seg; 2411 } 2412 2413 Symbol *MsCoffObj_tlv_bootstrap() 2414 { 2415 // specific for Mach-O 2416 assert(0); 2417 } 2418 2419 /***************************************** 2420 * write a reference to a mutable pointer into the object file 2421 * Params: 2422 * s = symbol that contains the pointer 2423 * soff = offset of the pointer inside the Symbol's memory 2424 */ 2425 @trusted 2426 void MsCoffObj_write_pointerRef(Symbol* s, uint soff) 2427 { 2428 if (!ptrref_buf) 2429 { 2430 ptrref_buf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2431 if (!ptrref_buf) 2432 err_nomem(); 2433 } 2434 2435 // defer writing pointer references until the symbols are written out 2436 ptrref_buf.write((&s)[0 .. 1]); 2437 ptrref_buf.write32(soff); 2438 } 2439 2440 /***************************************** 2441 * flush a single pointer reference saved by write_pointerRef 2442 * to the object file 2443 * Params: 2444 * s = symbol that contains the pointer 2445 * soff = offset of the pointer inside the Symbol's memory 2446 */ 2447 @trusted 2448 extern (D) private void objflush_pointerRef(Symbol* s, uint soff) 2449 { 2450 bool isTls = (s.Sfl == FLtlsdata); 2451 const(char)* segname = isTls ? ".tp$B" : ".dp$B"; 2452 int attr = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; 2453 int seg = MsCoffObj_getsegment(segname, attr); 2454 2455 targ_size_t offset = SegData[seg].SDoffset; 2456 MsCoffObj_addrel(seg, offset, s, cast(uint)offset, RELaddr32, 0); 2457 OutBuffer* buf = SegData[seg].SDbuf; 2458 buf.setsize(cast(uint)offset); 2459 buf.write32(soff); 2460 SegData[seg].SDoffset = buf.length(); 2461 } 2462 2463 /***************************************** 2464 * flush all pointer references saved by write_pointerRef 2465 * to the object file 2466 */ 2467 @trusted 2468 extern (D) private void objflush_pointerRefs() 2469 { 2470 if (!ptrref_buf) 2471 return; 2472 2473 ubyte *p = ptrref_buf.buf; 2474 ubyte *end = ptrref_buf.buf + ptrref_buf.length(); 2475 while (p < end) 2476 { 2477 Symbol* s = *cast(Symbol**)p; 2478 p += s.sizeof; 2479 uint soff = *cast(uint*)p; 2480 p += soff.sizeof; 2481 objflush_pointerRef(s, soff); 2482 } 2483 ptrref_buf.reset(); 2484 }