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