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