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