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