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