1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 2009-2020 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 static if (TARGET_WINDOS) 55 { 56 57 extern (C) char* strupr(char*); 58 59 private __gshared Outbuffer *fobjbuf; 60 61 enum DEST_LEN = (IDMAX + IDOHD + 1); 62 char *obj_mangle2(Symbol *s,char *dest); 63 64 65 int elf_align(int size, int foffset); 66 67 /****************************************** 68 */ 69 70 // The object file is built ib several separate pieces 71 72 __gshared private 73 { 74 75 // String Table - String table for all other names 76 Outbuffer *string_table; 77 78 // Section Headers 79 public Outbuffer *ScnhdrBuf; // Buffer to build section table in 80 81 // The -1 is because it is 1 based indexing 82 IMAGE_SECTION_HEADER* ScnhdrTab() { return cast(IMAGE_SECTION_HEADER *)ScnhdrBuf.buf - 1; } 83 84 int scnhdr_cnt; // Number of sections in table 85 enum SCNHDR_TAB_INITSIZE = 16; // Initial number of sections in buffer 86 enum SCNHDR_TAB_INC = 4; // Number of sections to increment buffer by 87 88 enum SYM_TAB_INIT = 100; // Initial number of symbol entries in buffer 89 enum SYM_TAB_INC = 50; // Number of symbols to increment buffer by 90 91 // The symbol table 92 Outbuffer *symbuf; 93 94 Outbuffer *syment_buf; // array of struct syment 95 96 segidx_t segidx_drectve = UNKNOWN; // contents of ".drectve" section 97 segidx_t segidx_debugS = UNKNOWN; 98 segidx_t segidx_xdata = UNKNOWN; 99 segidx_t segidx_pdata = UNKNOWN; 100 101 int jumpTableSeg; // segment index for __jump_table 102 103 Outbuffer *indirectsymbuf2; // indirect symbol table of Symbol*'s 104 int pointersSeg; // segment index for __pointers 105 106 Outbuffer *ptrref_buf; // buffer for pointer references 107 108 int floatused; 109 110 /* If an MsCoffObj_external_def() happens, set this to the string index, 111 * to be added last to the symbol table. 112 * Obviously, there can be only one. 113 */ 114 IDXSTR extdef; 115 116 // Each compiler segment is a section 117 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes 118 // into SegData[] 119 // New compiler segments are added to end. 120 121 /****************************** 122 * Returns !=0 if this segment is a code segment. 123 */ 124 125 int seg_data_isCode(const ref seg_data sd) 126 { 127 return (ScnhdrTab[sd.SDshtidx].Characteristics & IMAGE_SCN_CNT_CODE) != 0; 128 } 129 130 public: 131 132 // already in cgobj.c (should be part of objmod?): 133 // seg_data **SegData; 134 extern Rarray!(seg_data*) SegData; 135 segidx_t seg_tlsseg = UNKNOWN; 136 segidx_t seg_tlsseg_bss = UNKNOWN; 137 138 } 139 140 /******************************************************* 141 * Because the mscoff relocations cannot be computed until after 142 * all the segments are written out, and we need more information 143 * than the mscoff relocations provide, make our own relocation 144 * type. Later, translate to mscoff relocation structure. 145 */ 146 147 enum 148 { 149 RELaddr = 0, // straight address 150 RELrel = 1, // relative to location to be fixed up 151 RELseg = 2, // 2 byte section 152 RELaddr32 = 3, // 4 byte offset 153 } 154 155 struct Relocation 156 { // Relocations are attached to the struct seg_data they refer to 157 targ_size_t offset; // location in segment to be fixed up 158 Symbol *funcsym; // function in which offset lies, if any 159 Symbol *targsym; // if !=null, then location is to be fixed up 160 // to address of this symbol 161 uint targseg; // if !=0, then location is to be fixed up 162 // to address of start of this segment 163 ubyte rtype; // RELxxxx 164 short val; // 0, -1, -2, -3, -4, -5 165 } 166 167 168 /******************************* 169 * Output a string into a string table 170 * Input: 171 * strtab = string table for entry 172 * str = string to add 173 * 174 * Returns offset into the specified string table. 175 */ 176 177 IDXSTR MsCoffObj_addstr(Outbuffer *strtab, const(char)* str) 178 { 179 //printf("MsCoffObj_addstr(strtab = %p str = '%s')\n",strtab,str); 180 IDXSTR idx = cast(IDXSTR)strtab.length(); // remember starting offset 181 strtab.writeString(str); 182 //printf("\tidx %d, new size %d\n",idx,strtab.length()); 183 return idx; 184 } 185 186 /************************** 187 * Output read only data and generate a symbol for it. 188 * 189 */ 190 191 Symbol * MsCoffObj_sym_cdata(tym_t ty,char *p,int len) 192 { 193 //printf("MsCoffObj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA)); 194 alignOffset(CDATA, tysize(ty)); 195 Symbol *s = symboldata(Offset(CDATA), ty); 196 s.Sseg = CDATA; 197 MsCoffObj_pubdef(CDATA, s, Offset(CDATA)); 198 MsCoffObj_bytes(CDATA, Offset(CDATA), len, p); 199 200 s.Sfl = FLdata; //FLextern; 201 return s; 202 } 203 204 /************************** 205 * Ouput read only data for data 206 * 207 */ 208 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 int MsCoffObj_data_readonly(char *p, int len) 232 { 233 segidx_t pseg; 234 235 return MsCoffObj_data_readonly(p, len, &pseg); 236 } 237 238 /***************************** 239 * Get segment for readonly string literals. 240 * The linker will pool strings in this section. 241 * Params: 242 * sz = number of bytes per character (1, 2, or 4) 243 * Returns: 244 * segment index 245 */ 246 int MsCoffObj_string_literal_segment(uint sz) 247 { 248 assert(0); 249 } 250 251 /****************************** 252 * Start a .obj file. 253 * Called before any other obj_xxx routines. 254 * One source file can generate multiple .obj files. 255 */ 256 257 Obj MsCoffObj_init(Outbuffer *objbuf, const(char)* filename, const(char)* csegname) 258 { 259 //printf("MsCoffObj_init()\n"); 260 Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj)); 261 262 cseg = CODE; 263 fobjbuf = objbuf; 264 assert(objbuf.length() == 0); 265 266 floatused = 0; 267 268 segidx_drectve = UNKNOWN; 269 seg_tlsseg = UNKNOWN; 270 seg_tlsseg_bss = UNKNOWN; 271 272 segidx_pdata = UNKNOWN; 273 segidx_xdata = UNKNOWN; 274 segidx_debugS = UNKNOWN; 275 276 // Initialize buffers 277 278 if (!string_table) 279 { 280 string_table = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 281 assert(string_table); 282 string_table.reserve(2048); 283 } 284 string_table.reset(); 285 string_table.write32(4); // first 4 bytes are length of string table 286 287 if (symbuf) 288 { 289 Symbol **p = cast(Symbol **)symbuf.buf; 290 const size_t n = symbuf.length() / (Symbol *).sizeof; 291 for (size_t i = 0; i < n; ++i) 292 symbol_reset(p[i]); 293 symbuf.reset(); 294 } 295 else 296 { 297 symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 298 assert(symbuf); 299 symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 300 } 301 302 if (!syment_buf) 303 { 304 syment_buf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 305 assert(syment_buf); 306 syment_buf.reserve(SymbolTable32.sizeof * SYM_TAB_INIT); 307 } 308 syment_buf.reset(); 309 310 extdef = 0; 311 pointersSeg = 0; 312 313 // Initialize segments for CODE, DATA, UDATA and CDATA 314 if (!ScnhdrBuf) 315 { 316 ScnhdrBuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 317 assert(ScnhdrBuf); 318 ScnhdrBuf.reserve(SCNHDR_TAB_INITSIZE * (IMAGE_SECTION_HEADER).sizeof); 319 } 320 ScnhdrBuf.reset(); 321 scnhdr_cnt = 0; 322 323 /* Define sections. Although the order should not matter, we duplicate 324 * the same order VC puts out just to avoid trouble. 325 */ 326 327 int alignText = I64 ? IMAGE_SCN_ALIGN_16BYTES : IMAGE_SCN_ALIGN_8BYTES; 328 int alignData = IMAGE_SCN_ALIGN_16BYTES; 329 MsCoffObj_addScnhdr(".data$B", IMAGE_SCN_CNT_INITIALIZED_DATA | 330 alignData | 331 IMAGE_SCN_MEM_READ | 332 IMAGE_SCN_MEM_WRITE); // DATA 333 MsCoffObj_addScnhdr(".text", IMAGE_SCN_CNT_CODE | 334 alignText | 335 IMAGE_SCN_MEM_EXECUTE | 336 IMAGE_SCN_MEM_READ); // CODE 337 MsCoffObj_addScnhdr(".bss$B", IMAGE_SCN_CNT_UNINITIALIZED_DATA | 338 alignData | 339 IMAGE_SCN_MEM_READ | 340 IMAGE_SCN_MEM_WRITE); // UDATA 341 MsCoffObj_addScnhdr(".rdata", IMAGE_SCN_CNT_INITIALIZED_DATA | 342 alignData | 343 IMAGE_SCN_MEM_READ); // CONST 344 345 SegData.reset(); 346 SegData.push(); 347 348 enum 349 { 350 SHI_DATA = 1, 351 SHI_TEXT = 2, 352 SHI_UDATA = 3, 353 SHI_CDATA = 4, 354 } 355 356 MsCoffObj_getsegment2(SHI_TEXT); 357 assert(SegData[CODE].SDseg == CODE); 358 359 MsCoffObj_getsegment2(SHI_DATA); 360 assert(SegData[DATA].SDseg == DATA); 361 362 MsCoffObj_getsegment2(SHI_CDATA); 363 assert(SegData[CDATA].SDseg == CDATA); 364 365 MsCoffObj_getsegment2(SHI_UDATA); 366 assert(SegData[UDATA].SDseg == UDATA); 367 368 if (config.fulltypes) 369 cv8_initfile(filename); 370 assert(objbuf.length() == 0); 371 return obj; 372 } 373 374 /************************** 375 * Start a module within a .obj file. 376 * There can be multiple modules within a single .obj file. 377 * 378 * Input: 379 * filename: Name of source file 380 * csegname: User specified default code segment name 381 */ 382 383 void MsCoffObj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname) 384 { 385 //dbg_printf("MsCoffObj_initfile(filename = %s, modname = %s)\n",filename,modname); 386 version (SCPP) 387 { 388 static if (TARGET_LINUX) 389 { 390 if (csegname && *csegname && strcmp(csegname,".text")) 391 { // Define new section and make it the default for cseg segment 392 // NOTE: cseg is initialized to CODE 393 IDXSEC newsecidx; 394 Elf32_Shdr *newtextsec; 395 IDXSYM newsymidx; 396 assert(!I64); // fix later 397 SegData[cseg].SDshtidx = newsecidx = 398 elf_newsection(csegname,0,SHT_PROGDEF,SHF_ALLOC|SHF_EXECINSTR); 399 newtextsec = &ScnhdrTab[newsecidx]; 400 newtextsec.sh_addralign = 4; 401 SegData[cseg].SDsymidx = 402 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, newsecidx); 403 } 404 } 405 } 406 if (config.fulltypes) 407 cv8_initmodule(filename, modname); 408 } 409 410 /************************************ 411 * Patch pseg/offset by adding in the vmaddr difference from 412 * pseg/offset to start of seg. 413 */ 414 415 int32_t *patchAddr(int seg, targ_size_t offset) 416 { 417 return cast(int32_t *)(fobjbuf.buf + ScnhdrTab[SegData[seg].SDshtidx].PointerToRawData + offset); 418 } 419 420 int32_t *patchAddr64(int seg, targ_size_t offset) 421 { 422 return cast(int32_t *)(fobjbuf.buf + ScnhdrTab[SegData[seg].SDshtidx].PointerToRawData + offset); 423 } 424 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 obj_filename(const(char)* modname) 1092 { 1093 //dbg_printf("obj_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 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 char *obj_mangle2(Symbol *s,char *dest) 1685 { 1686 size_t len; 1687 const(char)* name; 1688 1689 //printf("MsCoffObj_mangle(s = %p, '%s'), mangle = x%x\n",s,s.Sident.ptr,type_mangle(s.Stype)); 1690 symbol_debug(s); 1691 assert(dest); 1692 1693 version (SCPP) 1694 name = CPP ? cpp_mangle(s) : s.Sident.ptr; 1695 else version (MARS) 1696 // C++ name mangling is handled by front end 1697 name = s.Sident.ptr; 1698 else 1699 name = s.Sident.ptr; 1700 1701 len = strlen(name); // # of bytes in name 1702 //dbg_printf("len %d\n",len); 1703 switch (type_mangle(s.Stype)) 1704 { 1705 case mTYman_pas: // if upper case 1706 case mTYman_for: 1707 if (len >= DEST_LEN) 1708 dest = cast(char *)mem_malloc(len + 1); 1709 memcpy(dest,name,len + 1); // copy in name and ending 0 1710 strupr(dest); // to upper case 1711 break; 1712 case mTYman_std: 1713 if (!(config.flags4 & CFG4oldstdmangle) && 1714 config.exe == EX_WIN32 && tyfunc(s.ty()) && 1715 !variadic(s.Stype)) 1716 { 1717 char *pstr = unsstr(type_paramsize(s.Stype)); 1718 size_t pstrlen = strlen(pstr); 1719 size_t prelen = I32 ? 1 : 0; 1720 size_t destlen = prelen + len + 1 + pstrlen + 1; 1721 1722 if (destlen > DEST_LEN) 1723 dest = cast(char *)mem_malloc(destlen); 1724 dest[0] = '_'; 1725 memcpy(dest + prelen,name,len); 1726 dest[prelen + len] = '@'; 1727 memcpy(dest + prelen + 1 + len, pstr, pstrlen + 1); 1728 break; 1729 } 1730 goto case; 1731 1732 case mTYman_cpp: 1733 case mTYman_sys: 1734 case_mTYman_c64: 1735 case 0: 1736 if (len >= DEST_LEN) 1737 dest = cast(char *)mem_malloc(len + 1); 1738 memcpy(dest,name,len+1);// copy in name and trailing 0 1739 break; 1740 1741 case mTYman_c: 1742 case mTYman_d: 1743 if(I64) 1744 goto case_mTYman_c64; 1745 // Prepend _ to identifier 1746 if (len >= DEST_LEN - 1) 1747 dest = cast(char *)mem_malloc(1 + len + 1); 1748 dest[0] = '_'; 1749 memcpy(dest + 1,name,len+1);// copy in name and trailing 0 1750 break; 1751 1752 default: 1753 debug 1754 { 1755 printf("mangling %x\n",type_mangle(s.Stype)); 1756 symbol_print(s); 1757 } 1758 printf("%d\n", type_mangle(s.Stype)); 1759 assert(0); 1760 } 1761 //dbg_printf("\t %s\n",dest); 1762 return dest; 1763 } 1764 1765 /******************************* 1766 * Export a function name. 1767 */ 1768 1769 void MsCoffObj_export_symbol(Symbol *s,uint argsize) 1770 { 1771 char[DEST_LEN+1] dest = void; 1772 char *destr = obj_mangle2(s, dest.ptr); 1773 1774 int seg = MsCoffObj_seg_drectve(); 1775 //printf("MsCoffObj_export_symbol(%s,%d)\n",s.Sident.ptr,argsize); 1776 SegData[seg].SDbuf.write(" /EXPORT:".ptr, 9); 1777 SegData[seg].SDbuf.write(dest.ptr, cast(uint)strlen(dest.ptr)); 1778 } 1779 1780 /******************************* 1781 * Update data information about symbol 1782 * align for output and assign segment 1783 * if not already specified. 1784 * 1785 * Input: 1786 * sdata data symbol 1787 * datasize output size 1788 * seg default seg if not known 1789 * Returns: 1790 * actual seg 1791 */ 1792 1793 segidx_t MsCoffObj_data_start(Symbol *sdata, targ_size_t datasize, segidx_t seg) 1794 { 1795 targ_size_t alignbytes; 1796 1797 //printf("MsCoffObj_data_start(%s,size %d,seg %d)\n",sdata.Sident.ptr,(int)datasize,seg); 1798 //symbol_print(sdata); 1799 1800 assert(sdata.Sseg); 1801 if (sdata.Sseg == UNKNOWN) // if we don't know then there 1802 sdata.Sseg = seg; // wasn't any segment override 1803 else 1804 seg = sdata.Sseg; 1805 targ_size_t offset = Offset(seg); 1806 if (sdata.Salignment > 0) 1807 { if (SegData[seg].SDalignment < sdata.Salignment) 1808 SegData[seg].SDalignment = sdata.Salignment; 1809 alignbytes = ((offset + sdata.Salignment - 1) & ~(sdata.Salignment - 1)) - offset; 1810 } 1811 else 1812 alignbytes = _align(datasize, offset) - offset; 1813 if (alignbytes) 1814 MsCoffObj_lidata(seg, offset, alignbytes); 1815 sdata.Soffset = offset + alignbytes; 1816 return seg; 1817 } 1818 1819 /******************************* 1820 * Update function info before codgen 1821 * 1822 * If code for this function is in a different segment 1823 * than the current default in cseg, switch cseg to new segment. 1824 */ 1825 1826 void MsCoffObj_func_start(Symbol *sfunc) 1827 { 1828 //printf("MsCoffObj_func_start(%s)\n",sfunc.Sident.ptr); 1829 symbol_debug(sfunc); 1830 1831 assert(sfunc.Sseg); 1832 if (sfunc.Sseg == UNKNOWN) 1833 sfunc.Sseg = CODE; 1834 //printf("sfunc.Sseg %d CODE %d cseg %d Coffset x%x\n",sfunc.Sseg,CODE,cseg,Offset(cseg)); 1835 cseg = sfunc.Sseg; 1836 assert(cseg == CODE || cseg > UDATA); 1837 MsCoffObj_pubdef(cseg, sfunc, Offset(cseg)); 1838 sfunc.Soffset = Offset(cseg); 1839 1840 if (config.fulltypes) 1841 cv8_func_start(sfunc); 1842 } 1843 1844 /******************************* 1845 * Update function info after codgen 1846 */ 1847 1848 void MsCoffObj_func_term(Symbol *sfunc) 1849 { 1850 //dbg_printf("MsCoffObj_func_term(%s) offset %x, Coffset %x symidx %d\n", 1851 // sfunc.Sident.ptr, sfunc.Soffset,Offset(cseg),sfunc.Sxtrnnum); 1852 1853 if (config.fulltypes) 1854 cv8_func_term(sfunc); 1855 } 1856 1857 /******************************** 1858 * Output a public definition. 1859 * Params: 1860 * seg = segment index that symbol is defined in 1861 * s = symbol 1862 * offset = offset of name within segment 1863 */ 1864 1865 void MsCoffObj_pubdef(segidx_t seg, Symbol *s, targ_size_t offset) 1866 { 1867 //printf("MsCoffObj_pubdef(%d:x%x s=%p, %s)\n", seg, cast(int)offset, s, s.Sident.ptr); 1868 //symbol_print(s); 1869 1870 symbol_debug(s); 1871 1872 s.Soffset = offset; 1873 s.Sseg = seg; 1874 switch (s.Sclass) 1875 { 1876 case SCglobal: 1877 case SCinline: 1878 symbuf.write((&s)[0 .. 1]); 1879 break; 1880 case SCcomdat: 1881 case SCcomdef: 1882 symbuf.write((&s)[0 .. 1]); 1883 break; 1884 default: 1885 symbuf.write((&s)[0 .. 1]); 1886 break; 1887 } 1888 //printf("%p\n", *(void**)symbuf.buf); 1889 s.Sxtrnnum = 1; 1890 } 1891 1892 void MsCoffObj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize) 1893 { 1894 MsCoffObj_pubdef(seg, s, offset); 1895 } 1896 1897 /******************************* 1898 * Output an external symbol for name. 1899 * Input: 1900 * name Name to do EXTDEF on 1901 * (Not to be mangled) 1902 * Returns: 1903 * Symbol table index of the definition 1904 * NOTE: Numbers will not be linear. 1905 */ 1906 1907 int MsCoffObj_external_def(const(char)* name) 1908 { 1909 //printf("MsCoffObj_external_def('%s')\n",name); 1910 assert(name); 1911 Symbol *s = symbol_name(name, SCextern, tspvoid); 1912 symbuf.write((&s)[0 .. 1]); 1913 return 0; 1914 } 1915 1916 1917 /******************************* 1918 * Output an external for existing symbol. 1919 * Input: 1920 * s Symbol to do EXTDEF on 1921 * (Name is to be mangled) 1922 * Returns: 1923 * Symbol table index of the definition 1924 * NOTE: Numbers will not be linear. 1925 */ 1926 1927 int MsCoffObj_external(Symbol *s) 1928 { 1929 //printf("MsCoffObj_external('%s') %x\n",s.Sident.ptr,s.Svalue); 1930 symbol_debug(s); 1931 symbuf.write((&s)[0 .. 1]); 1932 s.Sxtrnnum = 1; 1933 return 1; 1934 } 1935 1936 /******************************* 1937 * Output a common block definition. 1938 * Params: 1939 * s = Symbol for common block 1940 * size = size in bytes of each elem 1941 * count = number of elems 1942 * Returns: 1943 * Symbol table index for symbol 1944 */ 1945 1946 int MsCoffObj_common_block(Symbol *s,targ_size_t size,targ_size_t count) 1947 { 1948 //printf("MsCoffObj_common_block('%s', size=%d, count=%d)\n",s.Sident.ptr,size,count); 1949 symbol_debug(s); 1950 1951 // can't have code or thread local comdef's 1952 assert(!(s.ty() & mTYthread)); 1953 1954 s.Sfl = FLudata; 1955 uint align_ = 16; 1956 s.Sseg = MsCoffObj_getsegment(".bss$B", IMAGE_SCN_CNT_UNINITIALIZED_DATA | 1957 IMAGE_SCN_LNK_COMDAT | 1958 IMAGE_SCN_ALIGN_16BYTES | 1959 IMAGE_SCN_MEM_READ | 1960 IMAGE_SCN_MEM_WRITE); 1961 if (s.Salignment > align_) 1962 { 1963 SegData[s.Sseg].SDalignment = s.Salignment; 1964 assert(s.Salignment >= -1); 1965 } 1966 s.Soffset = SegData[s.Sseg].SDoffset; 1967 SegData[s.Sseg].SDsym = s; 1968 SegData[s.Sseg].SDoffset += count * size; 1969 1970 MsCoffObj_pubdef(s.Sseg, s, s.Soffset); 1971 searchfixlist(s); // backpatch any refs to this symbol 1972 1973 return 1; // should return void 1974 } 1975 1976 int MsCoffObj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count) 1977 { 1978 return MsCoffObj_common_block(s, size, count); 1979 } 1980 1981 /*************************************** 1982 * Append an iterated data block of 0s. 1983 * (uninitialized data only) 1984 */ 1985 1986 void MsCoffObj_write_zeros(seg_data *pseg, targ_size_t count) 1987 { 1988 MsCoffObj_lidata(pseg.SDseg, pseg.SDoffset, count); 1989 } 1990 1991 /*************************************** 1992 * Output an iterated data block of 0s. 1993 * 1994 * For boundary alignment and initialization 1995 */ 1996 1997 void MsCoffObj_lidata(segidx_t seg,targ_size_t offset,targ_size_t count) 1998 { 1999 //printf("MsCoffObj_lidata(%d,%x,%d)\n",seg,offset,count); 2000 size_t idx = SegData[seg].SDshtidx; 2001 if ((ScnhdrTab[idx].Characteristics) & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 2002 { // Use SDoffset to record size of bss section 2003 SegData[seg].SDoffset += count; 2004 } 2005 else 2006 { 2007 MsCoffObj_bytes(seg, offset, cast(uint)count, null); 2008 } 2009 } 2010 2011 /*********************************** 2012 * Append byte to segment. 2013 */ 2014 2015 void MsCoffObj_write_byte(seg_data *pseg, uint byte_) 2016 { 2017 MsCoffObj_byte(pseg.SDseg, pseg.SDoffset, byte_); 2018 } 2019 2020 /************************************ 2021 * Output byte_ to object file. 2022 */ 2023 2024 void MsCoffObj_byte(segidx_t seg,targ_size_t offset,uint byte_) 2025 { 2026 Outbuffer *buf = SegData[seg].SDbuf; 2027 int save = cast(int)buf.length(); 2028 //dbg_printf("MsCoffObj_byte(seg=%d, offset=x%lx, byte=x%x)\n",seg,offset,byte_); 2029 buf.setsize(cast(uint)offset); 2030 buf.writeByte(byte_); 2031 if (save > offset+1) 2032 buf.setsize(save); 2033 else 2034 SegData[seg].SDoffset = offset+1; 2035 //dbg_printf("\tsize now %d\n",buf.length()); 2036 } 2037 2038 /*********************************** 2039 * Append bytes to segment. 2040 */ 2041 2042 void MsCoffObj_write_bytes(seg_data *pseg, uint nbytes, void *p) 2043 { 2044 MsCoffObj_bytes(pseg.SDseg, pseg.SDoffset, nbytes, p); 2045 } 2046 2047 /************************************ 2048 * Output bytes to object file. 2049 * Returns: 2050 * nbytes 2051 */ 2052 2053 uint MsCoffObj_bytes(segidx_t seg, targ_size_t offset, uint nbytes, void *p) 2054 { 2055 static if (0) 2056 { 2057 if (!(seg >= 0 && seg < SegData.length)) 2058 { printf("MsCoffObj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length); 2059 *cast(char*)0=0; 2060 } 2061 } 2062 assert(seg >= 0 && seg < SegData.length); 2063 Outbuffer *buf = SegData[seg].SDbuf; 2064 if (buf == null) 2065 { 2066 //printf("MsCoffObj_bytes(seg=%d, offset=x%llx, nbytes=%d, p=x%x)\n", seg, offset, nbytes, p); 2067 //raise(SIGSEGV); 2068 assert(buf != null); 2069 } 2070 int save = cast(int)buf.length(); 2071 //dbg_printf("MsCoffObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n", 2072 //seg,offset,nbytes,p); 2073 buf.position(cast(size_t)offset, nbytes); 2074 if (p) 2075 buf.write(p, nbytes); 2076 else // Zero out the bytes 2077 buf.writezeros(nbytes); 2078 2079 if (save > offset+nbytes) 2080 buf.setsize(save); 2081 else 2082 SegData[seg].SDoffset = offset+nbytes; 2083 return nbytes; 2084 } 2085 2086 /********************************************* 2087 * Add a relocation entry for seg/offset. 2088 */ 2089 2090 void MsCoffObj_addrel(segidx_t seg, targ_size_t offset, Symbol *targsym, 2091 uint targseg, int rtype, int val) 2092 { 2093 //printf("addrel()\n"); 2094 if (!targsym) 2095 { // Generate one 2096 targsym = symbol_generate(SCstatic, tstypes[TYint]); 2097 targsym.Sseg = targseg; 2098 targsym.Soffset = val; 2099 symbuf.write((&targsym)[0 .. 1]); 2100 } 2101 2102 Relocation rel = void; 2103 rel.offset = offset; 2104 rel.targsym = targsym; 2105 rel.targseg = targseg; 2106 rel.rtype = cast(ubyte)rtype; 2107 rel.funcsym = funcsym_p; 2108 rel.val = cast(short)val; 2109 seg_data *pseg = SegData[seg]; 2110 if (!pseg.SDrel) 2111 { 2112 pseg.SDrel = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 2113 assert(pseg.SDrel); 2114 } 2115 pseg.SDrel.write((&rel)[0 .. 1]); 2116 } 2117 2118 /**************************************** 2119 * Sort the relocation entry buffer. 2120 */ 2121 2122 extern (C) { 2123 private int rel_fp(scope const(void*) e1, scope const(void*) e2) 2124 { Relocation *r1 = cast(Relocation *)e1; 2125 Relocation *r2 = cast(Relocation *)e2; 2126 2127 return cast(int)(r1.offset - r2.offset); 2128 } 2129 } 2130 2131 void mach_relsort(Outbuffer *buf) 2132 { 2133 qsort(buf.buf, buf.length() / (Relocation).sizeof, (Relocation).sizeof, &rel_fp); 2134 } 2135 2136 /******************************* 2137 * Refer to address that is in the data segment. 2138 * Input: 2139 * seg:offset = the address being fixed up 2140 * val = displacement from start of target segment 2141 * targetdatum = target segment number (DATA, CDATA or UDATA, etc.) 2142 * flags = CFoff, CFseg 2143 * Example: 2144 * int *abc = &def[3]; 2145 * to allocate storage: 2146 * MsCoffObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA); 2147 */ 2148 2149 void MsCoffObj_reftodatseg(segidx_t seg,targ_size_t offset,targ_size_t val, 2150 uint targetdatum,int flags) 2151 { 2152 Outbuffer *buf = SegData[seg].SDbuf; 2153 int save = cast(int)buf.length(); 2154 buf.setsize(cast(uint)offset); 2155 static if (0) 2156 { 2157 printf("MsCoffObj_reftodatseg(seg:offset=%d:x%llx, val=x%llx, targetdatum %x, flags %x )\n", 2158 seg,offset,val,targetdatum,flags); 2159 } 2160 assert(seg != 0); 2161 if (SegData[seg].isCode() && SegData[targetdatum].isCode()) 2162 { 2163 assert(0); 2164 } 2165 MsCoffObj_addrel(seg, offset, null, targetdatum, RELaddr, 0); 2166 if (I64) 2167 { 2168 if (flags & CFoffset64) 2169 { 2170 buf.write64(val); 2171 if (save > offset + 8) 2172 buf.setsize(save); 2173 return; 2174 } 2175 } 2176 buf.write32(cast(int)val); 2177 if (save > offset + 4) 2178 buf.setsize(save); 2179 } 2180 2181 /******************************* 2182 * Refer to address that is in the current function code (funcsym_p). 2183 * Only offsets are output, regardless of the memory model. 2184 * Used to put values in switch address tables. 2185 * Input: 2186 * seg = where the address is going (CODE or DATA) 2187 * offset = offset within seg 2188 * val = displacement from start of this module 2189 */ 2190 2191 void MsCoffObj_reftocodeseg(segidx_t seg,targ_size_t offset,targ_size_t val) 2192 { 2193 //printf("MsCoffObj_reftocodeseg(seg=%d, offset=x%lx, val=x%lx )\n",seg,cast(uint)offset,cast(uint)val); 2194 assert(seg > 0); 2195 Outbuffer *buf = SegData[seg].SDbuf; 2196 int save = cast(int)buf.length(); 2197 buf.setsize(cast(uint)offset); 2198 val -= funcsym_p.Soffset; 2199 if (I32) 2200 MsCoffObj_addrel(seg, offset, funcsym_p, 0, RELaddr, 0); 2201 // MsCoffObj_addrel(seg, offset, funcsym_p, 0, RELaddr); 2202 // if (I64) 2203 // buf.write64(val); 2204 // else 2205 buf.write32(cast(int)val); 2206 if (save > offset + 4) 2207 buf.setsize(save); 2208 } 2209 2210 /******************************* 2211 * Refer to an identifier. 2212 * Params: 2213 * seg = where the address is going (CODE or DATA) 2214 * offset = offset within seg 2215 * s = Symbol table entry for identifier 2216 * val = displacement from identifier 2217 * flags = CFselfrel: self-relative 2218 * CFseg: get segment 2219 * CFoff: get offset 2220 * CFpc32: [RIP] addressing, val is 0, -1, -2 or -4 2221 * CFoffset64: 8 byte offset for 64 bit builds 2222 * Returns: 2223 * number of bytes in reference (4 or 8) 2224 */ 2225 2226 int MsCoffObj_reftoident(segidx_t seg, targ_size_t offset, Symbol *s, targ_size_t val, 2227 int flags) 2228 { 2229 int refsize = (flags & CFoffset64) ? 8 : 4; 2230 if (flags & CFseg) 2231 refsize += 2; 2232 static if (0) 2233 { 2234 printf("\nMsCoffObj_reftoident('%s' seg %d, offset x%llx, val x%llx, flags x%x)\n", 2235 s.Sident.ptr,seg,cast(ulong)offset,cast(ulong)val,flags); 2236 //printf("refsize = %d\n", refsize); 2237 //dbg_printf("Sseg = %d, Sxtrnnum = %d\n",s.Sseg,s.Sxtrnnum); 2238 //symbol_print(s); 2239 } 2240 assert(seg > 0); 2241 if (s.Sclass != SClocstat && !s.Sxtrnnum) 2242 { // It may get defined later as public or local, so defer 2243 size_t numbyteswritten = addtofixlist(s, offset, seg, val, flags); 2244 assert(numbyteswritten == refsize); 2245 } 2246 else 2247 { 2248 if (I64 || I32) 2249 { 2250 //if (s.Sclass != SCcomdat) 2251 //val += s.Soffset; 2252 int v = 0; 2253 if (flags & CFpc32) 2254 { 2255 v = -((flags & CFREL) >> 24); 2256 assert(v >= -5 && v <= 0); 2257 } 2258 if (flags & CFselfrel) 2259 { 2260 MsCoffObj_addrel(seg, offset, s, 0, RELrel, v); 2261 } 2262 else if ((flags & (CFseg | CFoff)) == (CFseg | CFoff)) 2263 { 2264 MsCoffObj_addrel(seg, offset, s, 0, RELaddr32, v); 2265 MsCoffObj_addrel(seg, offset + 4, s, 0, RELseg, v); 2266 refsize = 6; // 4 bytes for offset, 2 for section 2267 } 2268 else 2269 { 2270 MsCoffObj_addrel(seg, offset, s, 0, RELaddr, v); 2271 } 2272 } 2273 else 2274 { 2275 if (SegData[seg].isCode() && flags & CFselfrel) 2276 { 2277 seg_data *pseg = SegData[jumpTableSeg]; 2278 val -= offset + 4; 2279 MsCoffObj_addrel(seg, offset, null, jumpTableSeg, RELrel, 0); 2280 } 2281 else if (SegData[seg].isCode() && 2282 ((s.Sclass != SCextern && SegData[s.Sseg].isCode()) || s.Sclass == SClocstat || s.Sclass == SCstatic)) 2283 { 2284 val += s.Soffset; 2285 MsCoffObj_addrel(seg, offset, null, s.Sseg, RELaddr, 0); 2286 } 2287 else if (SegData[seg].isCode() && !tyfunc(s.ty())) 2288 { 2289 seg_data *pseg = SegData[pointersSeg]; 2290 2291 if (!indirectsymbuf2) 2292 { 2293 indirectsymbuf2 = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 2294 assert(indirectsymbuf2); 2295 } 2296 else 2297 { // Look through indirectsym to see if it is already there 2298 int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof); 2299 Symbol **psym = cast(Symbol **)indirectsymbuf2.buf; 2300 for (int i = 0; i < n; i++) 2301 { // Linear search, pretty pathetic 2302 if (s == psym[i]) 2303 { val = i * 4; 2304 goto L2; 2305 } 2306 } 2307 } 2308 2309 val = pseg.SDbuf.length(); 2310 pseg.SDbuf.writezeros(_tysize[TYnptr]); 2311 2312 // Add symbol s to indirectsymbuf2 2313 indirectsymbuf2.write((&s)[0 .. 1]); 2314 2315 L2: 2316 //printf("MsCoffObj_reftoident: seg = %d, offset = x%x, s = %s, val = x%x, pointersSeg = %d\n", seg, offset, s.Sident.ptr, val, pointersSeg); 2317 MsCoffObj_addrel(seg, offset, null, pointersSeg, RELaddr, 0); 2318 } 2319 else 2320 { //val -= s.Soffset; 2321 // MsCoffObj_addrel(seg, offset, s, 0, RELaddr, 0); 2322 } 2323 } 2324 2325 Outbuffer *buf = SegData[seg].SDbuf; 2326 int save = cast(int)buf.length(); 2327 buf.setsize(cast(uint)offset); 2328 //printf("offset = x%llx, val = x%llx\n", offset, val); 2329 if (refsize == 8) 2330 buf.write64(val); 2331 else if (refsize == 4) 2332 buf.write32(cast(int)val); 2333 else if (refsize == 6) 2334 { 2335 buf.write32(cast(int)val); 2336 buf.write16(0); 2337 } 2338 else 2339 assert(0); 2340 if (save > offset + refsize) 2341 buf.setsize(save); 2342 } 2343 return refsize; 2344 } 2345 2346 /***************************************** 2347 * Generate far16 thunk. 2348 * Input: 2349 * s Symbol to generate a thunk for 2350 */ 2351 2352 void MsCoffObj_far16thunk(Symbol *s) 2353 { 2354 //dbg_printf("MsCoffObj_far16thunk('%s')\n", s.Sident.ptr); 2355 assert(0); 2356 } 2357 2358 /************************************** 2359 * Mark object file as using floating point. 2360 */ 2361 2362 void MsCoffObj_fltused() 2363 { 2364 //dbg_printf("MsCoffObj_fltused()\n"); 2365 /* Otherwise, we'll get the dreaded 2366 * "runtime error R6002 - floating point support not loaded" 2367 */ 2368 if (!floatused) 2369 { 2370 MsCoffObj_external_def("_fltused"); 2371 floatused = 1; 2372 } 2373 } 2374 2375 2376 int elf_align(int size, int foffset) 2377 { 2378 if (size <= 1) 2379 return foffset; 2380 int offset = (foffset + size - 1) & ~(size - 1); 2381 //printf("offset = x%lx, foffset = x%lx, size = x%lx\n", offset, foffset, (int)size); 2382 if (offset > foffset) 2383 fobjbuf.writezeros(offset - foffset); 2384 return offset; 2385 } 2386 2387 /*************************************** 2388 * Stuff pointer to ModuleInfo in its own segment. 2389 * Input: 2390 * scc symbol for ModuleInfo 2391 */ 2392 2393 version (MARS) 2394 { 2395 2396 void MsCoffObj_moduleinfo(Symbol *scc) 2397 { 2398 int align_ = I64 ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES; 2399 2400 /* Module info sections 2401 */ 2402 const int seg = 2403 MsCoffObj_getsegment(".minfo$B", IMAGE_SCN_CNT_INITIALIZED_DATA | 2404 align_ | 2405 IMAGE_SCN_MEM_READ); 2406 //printf("MsCoffObj_moduleinfo(%s) seg = %d:x%x\n", scc.Sident.ptr, seg, Offset(seg)); 2407 2408 int flags = CFoff; 2409 if (I64) 2410 flags |= CFoffset64; 2411 SegData[seg].SDoffset += MsCoffObj_reftoident(seg, Offset(seg), scc, 0, flags); 2412 } 2413 2414 } 2415 2416 /********************************** 2417 * Reset code seg to existing seg. 2418 * Used after a COMDAT for a function is done. 2419 */ 2420 2421 void MsCoffObj_setcodeseg(int seg) 2422 { 2423 assert(0 < seg && seg < SegData.length); 2424 cseg = seg; 2425 } 2426 2427 Symbol *MsCoffObj_tlv_bootstrap() 2428 { 2429 // specific for Mach-O 2430 assert(0); 2431 } 2432 2433 /***************************************** 2434 * write a reference to a mutable pointer into the object file 2435 * Params: 2436 * s = symbol that contains the pointer 2437 * soff = offset of the pointer inside the Symbol's memory 2438 */ 2439 void MsCoffObj_write_pointerRef(Symbol* s, uint soff) 2440 { 2441 if (!ptrref_buf) 2442 { 2443 ptrref_buf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 2444 assert(ptrref_buf); 2445 } 2446 2447 // defer writing pointer references until the symbols are written out 2448 ptrref_buf.write((&s)[0 .. 1]); 2449 ptrref_buf.write32(soff); 2450 } 2451 2452 /***************************************** 2453 * flush a single pointer reference saved by write_pointerRef 2454 * to the object file 2455 * Params: 2456 * s = symbol that contains the pointer 2457 * soff = offset of the pointer inside the Symbol's memory 2458 */ 2459 extern (D) private void objflush_pointerRef(Symbol* s, uint soff) 2460 { 2461 bool isTls = (s.Sfl == FLtlsdata); 2462 const(char)* segname = isTls ? ".tp$B" : ".dp$B"; 2463 int attr = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; 2464 int seg = MsCoffObj_getsegment(segname, attr); 2465 2466 targ_size_t offset = SegData[seg].SDoffset; 2467 MsCoffObj_addrel(seg, offset, s, cast(uint)offset, RELaddr32, 0); 2468 Outbuffer* buf = SegData[seg].SDbuf; 2469 buf.setsize(cast(uint)offset); 2470 buf.write32(soff); 2471 SegData[seg].SDoffset = buf.length(); 2472 } 2473 2474 /***************************************** 2475 * flush all pointer references saved by write_pointerRef 2476 * to the object file 2477 */ 2478 extern (D) private void objflush_pointerRefs() 2479 { 2480 if (!ptrref_buf) 2481 return; 2482 2483 ubyte *p = ptrref_buf.buf; 2484 ubyte *end = ptrref_buf.buf + ptrref_buf.length(); 2485 while (p < end) 2486 { 2487 Symbol* s = *cast(Symbol**)p; 2488 p += s.sizeof; 2489 uint soff = *cast(uint*)p; 2490 p += soff.sizeof; 2491 objflush_pointerRef(s, soff); 2492 } 2493 ptrref_buf.reset(); 2494 } 2495 2496 } 2497 2498 }