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