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