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