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/machobj.d, backend/machobj.d)
9  */
10 
11 module dmd.backend.machobj;
12 
13 version (SCPP)
14     version = COMPILE;
15 version (MARS)
16     version = COMPILE;
17 
18 version (COMPILE)
19 {
20 
21 import core.stdc.ctype;
22 import core.stdc.stdint;
23 import core.stdc.stdio;
24 import core.stdc.stdlib;
25 import core.stdc.string;
26 
27 import dmd.backend.cc;
28 import dmd.backend.cdef;
29 import dmd.backend.code;
30 import dmd.backend.code_x86;
31 import dmd.backend.mem;
32 import dmd.backend.aarray;
33 import dmd.backend.dlist;
34 import dmd.backend.el;
35 import dmd.backend.global;
36 import dmd.backend.obj;
37 import dmd.backend.oper;
38 import dmd.backend.outbuf;
39 import dmd.backend.ty;
40 import dmd.backend.type;
41 
42 extern (C++):
43 
44 nothrow:
45 
46 alias _compare_fp_t = extern(C) nothrow int function(const void*, const void*);
47 extern(C) void qsort(void* base, size_t nmemb, size_t size, _compare_fp_t compar);
48 
49 static if (MACHOBJ)
50 {
51 
52 import dmd.backend.dwarf;
53 import dmd.backend.mach;
54 
55 alias nlist = dmd.backend.mach.nlist;   // avoid conflict with dmd.backend.dlist.nlist
56 
57 /****************************************
58  * Sort the relocation entry buffer.
59  * put before nothrow because qsort was not marked nothrow until version 2.086
60  */
61 
62 extern (C) {
63 private int rel_fp(scope const(void*) e1, scope const(void*) e2)
64 {   Relocation *r1 = cast(Relocation *)e1;
65     Relocation *r2 = cast(Relocation *)e2;
66 
67     return cast(int)(r1.offset - r2.offset);
68 }
69 }
70 
71 void mach_relsort(Outbuffer *buf)
72 {
73     qsort(buf.buf, buf.length() / Relocation.sizeof, Relocation.sizeof, &rel_fp);
74 }
75 
76 // for x86_64
77 enum
78 {
79     X86_64_RELOC_UNSIGNED         = 0,
80     X86_64_RELOC_SIGNED           = 1,
81     X86_64_RELOC_BRANCH           = 2,
82     X86_64_RELOC_GOT_LOAD         = 3,
83     X86_64_RELOC_GOT              = 4,
84     X86_64_RELOC_SUBTRACTOR       = 5,
85     X86_64_RELOC_SIGNED_1         = 6,
86     X86_64_RELOC_SIGNED_2         = 7,
87     X86_64_RELOC_SIGNED_4         = 8,
88     X86_64_RELOC_TLV              = 9, // for thread local variables
89 }
90 
91 private __gshared Outbuffer *fobjbuf;
92 
93 enum DEST_LEN = (IDMAX + IDOHD + 1);
94 char *obj_mangle2(Symbol *s,char *dest);
95 
96 extern __gshared int except_table_seg;        // segment of __gcc_except_tab
97 extern __gshared int eh_frame_seg;            // segment of __eh_frame
98 
99 
100 /******************************************
101  */
102 
103 /// Returns: a reference to the global offset table
104 Symbol* Obj_getGOTsym()
105 {
106     __gshared Symbol *GOTsym;
107     if (!GOTsym)
108     {
109         GOTsym = symbol_name("_GLOBAL_OFFSET_TABLE_",SCglobal,tspvoid);
110     }
111     return GOTsym;
112 }
113 
114 void Obj_refGOTsym()
115 {
116     assert(0);
117 }
118 
119 // The object file is built is several separate pieces
120 
121 
122 // String Table  - String table for all other names
123 private __gshared Outbuffer *symtab_strings;
124 
125 // Section Headers
126 __gshared Outbuffer  *SECbuf;             // Buffer to build section table in
127 section* SecHdrTab() { return cast(section *)SECbuf.buf; }
128 section_64* SecHdrTab64() { return cast(section_64 *)SECbuf.buf; }
129 
130 __gshared
131 {
132 
133 // The relocation for text and data seems to get lost.
134 // Try matching the order gcc output them
135 // This means defining the sections and then removing them if they are
136 // not used.
137 private int section_cnt;         // Number of sections in table
138 enum SEC_TAB_INIT = 16;          // Initial number of sections in buffer
139 enum SEC_TAB_INC  = 4;           // Number of sections to increment buffer by
140 
141 enum SYM_TAB_INIT = 100;         // Initial number of symbol entries in buffer
142 enum SYM_TAB_INC  = 50;          // Number of symbols to increment buffer by
143 
144 /* Three symbol tables, because the different types of symbols
145  * are grouped into 3 different types (and a 4th for comdef's).
146  */
147 
148 private Outbuffer *local_symbuf;
149 private Outbuffer *public_symbuf;
150 private Outbuffer *extern_symbuf;
151 }
152 
153 private void reset_symbols(Outbuffer *buf)
154 {
155     Symbol **p = cast(Symbol **)buf.buf;
156     const size_t n = buf.length() / (Symbol *).sizeof;
157     for (size_t i = 0; i < n; ++i)
158         symbol_reset(p[i]);
159 }
160 
161 __gshared
162 {
163 
164 struct Comdef { Symbol *sym; targ_size_t size; int count; }
165 private Outbuffer *comdef_symbuf;        // Comdef's are stored here
166 
167 private Outbuffer *indirectsymbuf1;      // indirect symbol table of Symbol*'s
168 private int jumpTableSeg;                // segment index for __jump_table
169 
170 private Outbuffer *indirectsymbuf2;      // indirect symbol table of Symbol*'s
171 private int pointersSeg;                 // segment index for __pointers
172 
173 /* If an Obj_external_def() happens, set this to the string index,
174  * to be added last to the symbol table.
175  * Obviously, there can be only one.
176  */
177 private IDXSTR extdef;
178 }
179 
180 static if (0)
181 {
182 enum
183 {
184     STI_FILE  = 1,            // Where file symbol table entry is
185     STI_TEXT  = 2,
186     STI_DATA  = 3,
187     STI_BSS   = 4,
188     STI_GCC   = 5,            // Where "gcc2_compiled" symbol is */
189     STI_RODAT = 6,            // Symbol for readonly data
190     STI_COM   = 8,
191 }
192 }
193 
194 // Each compiler segment is a section
195 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes
196 //      into SegData[]
197 //      New compiler segments are added to end.
198 
199 /******************************
200  * Returns !=0 if this segment is a code segment.
201  */
202 
203 int seg_data_isCode(const ref seg_data sd)
204 {
205     // The codegen assumes that code.data references are indirect,
206     // but when CDATA is treated as code reftoident will emit a direct
207     // relocation.
208     if (&sd == SegData[CDATA])
209         return false;
210 
211     if (I64)
212     {
213         //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab64[sd.SDshtidx].flags);
214         return strcmp(SecHdrTab64[sd.SDshtidx].segname.ptr, "__TEXT") == 0;
215     }
216     else
217     {
218         //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab[sd.SDshtidx].flags);
219         return strcmp(SecHdrTab[sd.SDshtidx].segname.ptr, "__TEXT") == 0;
220     }
221 }
222 
223 
224 __gshared
225 {
226 seg_data **SegData;
227 int seg_count;
228 int seg_max;
229 
230 /**
231  * Section index for the __thread_vars/__tls_data section.
232  *
233  * This section is used for the variable symbol for TLS variables.
234  */
235 int seg_tlsseg = UNKNOWN;
236 
237 /**
238  * Section index for the __thread_bss section.
239  *
240  * This section is used for the data symbol ($tlv$init) for TLS variables
241  * without an initializer.
242  */
243 int seg_tlsseg_bss = UNKNOWN;
244 
245 /**
246  * Section index for the __thread_data section.
247  *
248  * This section is used for the data symbol ($tlv$init) for TLS variables
249  * with an initializer.
250  */
251 int seg_tlsseg_data = UNKNOWN;
252 }
253 
254 /*******************************************************
255  * Because the Mach-O relocations cannot be computed until after
256  * all the segments are written out, and we need more information
257  * than the Mach-O relocations provide, make our own relocation
258  * type. Later, translate to Mach-O relocation structure.
259  */
260 
261 enum
262 {
263     RELaddr = 0,      // straight address
264     RELrel  = 1,      // relative to location to be fixed up
265 }
266 
267 struct Relocation
268 {   // Relocations are attached to the struct seg_data they refer to
269     targ_size_t offset; // location in segment to be fixed up
270     Symbol *funcsym;    // function in which offset lies, if any
271     Symbol *targsym;    // if !=null, then location is to be fixed up
272                         // to address of this symbol
273     uint targseg;       // if !=0, then location is to be fixed up
274                         // to address of start of this segment
275     ubyte rtype;        // RELxxxx
276     ubyte flag;         // 1: emit SUBTRACTOR/UNSIGNED pair
277     short val;          // 0, -1, -2, -4
278 }
279 
280 
281 /*******************************
282  * Output a string into a string table
283  * Input:
284  *      strtab  =       string table for entry
285  *      str     =       string to add
286  *
287  * Returns index into the specified string table.
288  */
289 
290 IDXSTR Obj_addstr(Outbuffer *strtab, const(char)* str)
291 {
292     //printf("Obj_addstr(strtab = %p str = '%s')\n",strtab,str);
293     IDXSTR idx = cast(IDXSTR)strtab.length();        // remember starting offset
294     strtab.writeString(str);
295     //printf("\tidx %d, new size %d\n",idx,strtab.length());
296     return idx;
297 }
298 
299 /*******************************
300  * Output a mangled string into the symbol string table
301  * Input:
302  *      str     =       string to add
303  *
304  * Returns index into the table.
305  */
306 
307 private IDXSTR elf_addmangled(Symbol *s)
308 {
309     //printf("elf_addmangled(%s)\n", s.Sident);
310     char[DEST_LEN] dest = void;
311     char *destr;
312     const(char)* name;
313     IDXSTR namidx;
314 
315     namidx = cast(IDXSTR)symtab_strings.length();
316     destr = obj_mangle2(s, dest.ptr);
317     name = destr;
318     if (CPP && name[0] == '_' && name[1] == '_')
319     {
320         if (strncmp(name,"__ct__",6) == 0)
321             name += 4;
322 static if (0)
323 {
324         switch(name[2])
325         {
326             case 'c':
327                 if (strncmp(name,"__ct__",6) == 0)
328                     name += 4;
329                 break;
330             case 'd':
331                 if (strcmp(name,"__dl__FvP") == 0)
332                     name = "__builtin_delete";
333                 break;
334             case 'v':
335                 //if (strcmp(name,"__vec_delete__FvPiUIPi") == 0)
336                     //name = "__builtin_vec_del";
337                 //else
338                 //if (strcmp(name,"__vn__FPUI") == 0)
339                     //name = "__builtin_vec_new";
340                 break;
341             case 'n':
342                 if (strcmp(name,"__nw__FPUI") == 0)
343                     name = "__builtin_new";
344                 break;
345 
346             default:
347                 break;
348         }
349 }
350     }
351     else if (tyfunc(s.ty()) && s.Sfunc && s.Sfunc.Fredirect)
352         name = s.Sfunc.Fredirect;
353     symtab_strings.writeString(name);
354     if (destr != dest.ptr)                  // if we resized result
355         mem_free(destr);
356     //dbg_printf("\telf_addmagled symtab_strings %s namidx %d len %d size %d\n",name, namidx,len,symtab_strings.length());
357     return namidx;
358 }
359 
360 /**************************
361  * Ouput read only data and generate a symbol for it.
362  *
363  */
364 
365 Symbol * Obj_sym_cdata(tym_t ty,char *p,int len)
366 {
367     Symbol *s;
368 
369 static if (0)
370 {
371     if (I64)
372     {
373         alignOffset(DATA, tysize(ty));
374         s = symboldata(Offset(DATA), ty);
375         SegData[DATA].SDbuf.write(p,len);
376         s.Sseg = DATA;
377         s.Soffset = Offset(DATA);   // Remember its offset into DATA section
378         Offset(DATA) += len;
379 
380         s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
381         return s;
382     }
383 }
384     //printf("Obj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA));
385     alignOffset(CDATA, tysize(ty));
386     s = symboldata(Offset(CDATA), ty);
387     s.Sseg = CDATA;
388     //Obj_pubdef(CDATA, s, Offset(CDATA));
389     Obj_bytes(CDATA, Offset(CDATA), len, p);
390 
391     s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
392     return s;
393 }
394 
395 /**************************
396  * Ouput read only data for data
397  *
398  */
399 
400 int Obj_data_readonly(char *p, int len, int *pseg)
401 {
402     int oldoff = cast(int)Offset(CDATA);
403     SegData[CDATA].SDbuf.reserve(len);
404     SegData[CDATA].SDbuf.writen(p,len);
405     Offset(CDATA) += len;
406     *pseg = CDATA;
407     return oldoff;
408 }
409 
410 int Obj_data_readonly(char *p, int len)
411 {
412     int pseg;
413 
414     return Obj_data_readonly(p, len, &pseg);
415 }
416 
417 /*****************************
418  * Get segment for readonly string literals.
419  * The linker will pool strings in this section.
420  * Params:
421  *    sz = number of bytes per character (1, 2, or 4)
422  * Returns:
423  *    segment index
424  */
425 int Obj_string_literal_segment(uint sz)
426 {
427     if (sz == 1)
428     {
429         return Obj_getsegment("__cstring", "__TEXT", 0, S_CSTRING_LITERALS);
430     }
431     return CDATA;  // no special handling for other wstring, dstring; use __const
432 }
433 
434 /******************************
435  * Perform initialization that applies to all .o output files.
436  *      Called before any other obj_xxx routines
437  */
438 
439 Obj Obj_init(Outbuffer *objbuf, const(char)* filename, const(char)* csegname)
440 {
441     //printf("Obj_init()\n");
442     Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj));
443 
444     cseg = CODE;
445     fobjbuf = objbuf;
446 
447     seg_tlsseg = UNKNOWN;
448     seg_tlsseg_bss = UNKNOWN;
449     seg_tlsseg_data = UNKNOWN;
450 
451     // Initialize buffers
452 
453     if (symtab_strings)
454         symtab_strings.setsize(1);
455     else
456     {
457         symtab_strings = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
458         assert(symtab_strings);
459         symtab_strings.reserve(2048);
460         symtab_strings.writeByte(0);
461     }
462 
463     if (!local_symbuf)
464     {
465         local_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
466         assert(local_symbuf);
467         local_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
468     }
469     local_symbuf.reset();
470 
471     if (public_symbuf)
472     {
473         reset_symbols(public_symbuf);
474         public_symbuf.reset();
475     }
476     else
477     {
478         public_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
479         assert(public_symbuf);
480         public_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
481     }
482 
483     if (extern_symbuf)
484     {
485         reset_symbols(extern_symbuf);
486         extern_symbuf.reset();
487     }
488     else
489     {
490         extern_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
491         assert(extern_symbuf);
492         extern_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
493     }
494 
495     if (!comdef_symbuf)
496     {
497         comdef_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
498         assert(comdef_symbuf);
499         comdef_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
500     }
501     comdef_symbuf.reset();
502 
503     extdef = 0;
504 
505     if (indirectsymbuf1)
506         indirectsymbuf1.reset();
507     jumpTableSeg = 0;
508 
509     if (indirectsymbuf2)
510         indirectsymbuf2.reset();
511     pointersSeg = 0;
512 
513     // Initialize segments for CODE, DATA, UDATA and CDATA
514     size_t struct_section_size = I64 ? section_64.sizeof : section.sizeof;
515     if (SECbuf)
516     {
517         SECbuf.setsize(cast(uint)struct_section_size);
518     }
519     else
520     {
521         SECbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
522         assert(SECbuf);
523         SECbuf.reserve(cast(uint)(SEC_TAB_INIT * struct_section_size));
524         // Ignore the first section - section numbers start at 1
525         SECbuf.writezeros(cast(uint)struct_section_size);
526     }
527     section_cnt = 1;
528 
529     seg_count = 0;
530     int align_ = I64 ? 4 : 2;            // align to 16 bytes for floating point
531     Obj_getsegment("__text",  "__TEXT", 2, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS);
532     Obj_getsegment("__data",  "__DATA", align_, S_REGULAR);     // DATA
533     Obj_getsegment("__const", "__TEXT", 2, S_REGULAR);         // CDATA
534     Obj_getsegment("__bss",   "__DATA", 4, S_ZEROFILL);        // UDATA
535     Obj_getsegment("__const", "__DATA", align_, S_REGULAR);     // CDATAREL
536 
537     dwarf_initfile(filename);
538     return obj;
539 }
540 
541 /**************************
542  * Initialize the start of object output for this particular .o file.
543  *
544  * Input:
545  *      filename:       Name of source file
546  *      csegname:       User specified default code segment name
547  */
548 
549 void Obj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname)
550 {
551     //dbg_printf("Obj_initfile(filename = %s, modname = %s)\n",filename,modname);
552 version (SCPP)
553 {
554     if (csegname && *csegname && strcmp(csegname,".text"))
555     {   // Define new section and make it the default for cseg segment
556         // NOTE: cseg is initialized to CODE
557         IDXSEC newsecidx;
558         Elf32_Shdr *newtextsec;
559         IDXSYM newsymidx;
560         assert(!I64);      // fix later
561         SegData[cseg].SDshtidx = newsecidx =
562             elf_newsection(csegname,0,SHT_PROGDEF,SHF_ALLOC|SHF_EXECINSTR);
563         newtextsec = &SecHdrTab[newsecidx];
564         newtextsec.sh_addralign = 4;
565         SegData[cseg].SDsymidx =
566             elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, newsecidx);
567     }
568 }
569     if (config.fulltypes)
570         dwarf_initmodule(filename, modname);
571 }
572 
573 /************************************
574  * Patch pseg/offset by adding in the vmaddr difference from
575  * pseg/offset to start of seg.
576  */
577 
578 int32_t *patchAddr(int seg, targ_size_t offset)
579 {
580     return cast(int32_t *)(fobjbuf.buf + SecHdrTab[SegData[seg].SDshtidx].offset + offset);
581 }
582 
583 int32_t *patchAddr64(int seg, targ_size_t offset)
584 {
585     return cast(int32_t *)(fobjbuf.buf + SecHdrTab64[SegData[seg].SDshtidx].offset + offset);
586 }
587 
588 void patch(seg_data *pseg, targ_size_t offset, int seg, targ_size_t value)
589 {
590     //printf("patch(offset = x%04x, seg = %d, value = x%llx)\n", (uint)offset, seg, value);
591     if (I64)
592     {
593         int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab64[pseg.SDshtidx].offset + offset);
594 static if (0)
595 {
596         printf("\taddr1 = x%llx\n\taddr2 = x%llx\n\t*p = x%llx\n\tdelta = x%llx\n",
597             SecHdrTab64[pseg.SDshtidx].addr,
598             SecHdrTab64[SegData[seg].SDshtidx].addr,
599             *p,
600             SecHdrTab64[SegData[seg].SDshtidx].addr -
601             (SecHdrTab64[pseg.SDshtidx].addr + offset));
602 }
603         *p += SecHdrTab64[SegData[seg].SDshtidx].addr -
604               (SecHdrTab64[pseg.SDshtidx].addr - value);
605     }
606     else
607     {
608         int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab[pseg.SDshtidx].offset + offset);
609 static if (0)
610 {
611         printf("\taddr1 = x%x\n\taddr2 = x%x\n\t*p = x%x\n\tdelta = x%x\n",
612             SecHdrTab[pseg.SDshtidx].addr,
613             SecHdrTab[SegData[seg].SDshtidx].addr,
614             *p,
615             SecHdrTab[SegData[seg].SDshtidx].addr -
616             (SecHdrTab[pseg.SDshtidx].addr + offset));
617 }
618         *p += SecHdrTab[SegData[seg].SDshtidx].addr -
619               (SecHdrTab[pseg.SDshtidx].addr - value);
620     }
621 }
622 
623 /***************************
624  * Number symbols so they are
625  * ordered as locals, public and then extern/comdef
626  */
627 
628 void mach_numbersyms()
629 {
630     //printf("mach_numbersyms()\n");
631     int n = 0;
632 
633     int dim;
634     dim = cast(int)(local_symbuf.length() / (Symbol *).sizeof);
635     for (int i = 0; i < dim; i++)
636     {   Symbol *s = (cast(Symbol **)local_symbuf.buf)[i];
637         s.Sxtrnnum = n;
638         n++;
639     }
640 
641     dim = cast(int)(public_symbuf.length() / (Symbol *).sizeof);
642     for (int i = 0; i < dim; i++)
643     {   Symbol *s = (cast(Symbol **)public_symbuf.buf)[i];
644         s.Sxtrnnum = n;
645         n++;
646     }
647 
648     dim = cast(int)(extern_symbuf.length() / (Symbol *).sizeof);
649     for (int i = 0; i < dim; i++)
650     {   Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i];
651         s.Sxtrnnum = n;
652         n++;
653     }
654 
655     dim = cast(int)(comdef_symbuf.length() / Comdef.sizeof);
656     for (int i = 0; i < dim; i++)
657     {   Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i;
658         c.sym.Sxtrnnum = n;
659         n++;
660     }
661 }
662 
663 
664 /***************************
665  * Fixup and terminate object file.
666  */
667 
668 void Obj_termfile()
669 {
670     //dbg_printf("Obj_termfile\n");
671     if (configv.addlinenumbers)
672     {
673         dwarf_termmodule();
674     }
675 }
676 
677 /*********************************
678  * Terminate package.
679  */
680 
681 void Obj_term(const(char)* objfilename)
682 {
683     //printf("Obj_term()\n");
684 version (SCPP)
685 {
686     if (!errcnt)
687     {
688         outfixlist();           // backpatches
689     }
690 }
691 else
692 {
693     outfixlist();           // backpatches
694 }
695 
696     if (configv.addlinenumbers)
697     {
698         dwarf_termfile();
699     }
700 
701 version (SCPP)
702 {
703     if (errcnt)
704         return;
705 }
706 
707     /* Write out the object file in the following order:
708      *  header
709      *  commands
710      *          segment_command
711      *                  { sections }
712      *          symtab_command
713      *          dysymtab_command
714      *  { segment contents }
715      *  { relocations }
716      *  symbol table
717      *  string table
718      *  indirect symbol table
719      */
720 
721     uint foffset;
722     uint headersize;
723     uint sizeofcmds;
724 
725     // Write out the bytes for the header
726     if (I64)
727     {
728         mach_header_64 header = void;
729 
730         header.magic = MH_MAGIC_64;
731         header.cputype = CPU_TYPE_X86_64;
732         header.cpusubtype = CPU_SUBTYPE_I386_ALL;
733         header.filetype = MH_OBJECT;
734         header.ncmds = 3;
735         header.sizeofcmds = cast(uint)(segment_command_64.sizeof +
736                                 (section_cnt - 1) * section_64.sizeof +
737                             symtab_command.sizeof +
738                             dysymtab_command.sizeof);
739         header.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
740         header.reserved = 0;
741         fobjbuf.write(&header, header.sizeof);
742         foffset = header.sizeof;       // start after header
743         headersize = header.sizeof;
744         sizeofcmds = header.sizeofcmds;
745 
746         // Write the actual data later
747         fobjbuf.writezeros(header.sizeofcmds);
748         foffset += header.sizeofcmds;
749     }
750     else
751     {
752         mach_header header = void;
753 
754         header.magic = MH_MAGIC;
755         header.cputype = CPU_TYPE_I386;
756         header.cpusubtype = CPU_SUBTYPE_I386_ALL;
757         header.filetype = MH_OBJECT;
758         header.ncmds = 3;
759         header.sizeofcmds = cast(uint)(segment_command.sizeof +
760                                 (section_cnt - 1) * section.sizeof +
761                             symtab_command.sizeof +
762                             dysymtab_command.sizeof);
763         header.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
764         fobjbuf.write(&header, header.sizeof);
765         foffset = header.sizeof;       // start after header
766         headersize = header.sizeof;
767         sizeofcmds = header.sizeofcmds;
768 
769         // Write the actual data later
770         fobjbuf.writezeros(header.sizeofcmds);
771         foffset += header.sizeofcmds;
772     }
773 
774     segment_command segment_cmd = void;
775     segment_command_64 segment_cmd64 = void;
776     symtab_command symtab_cmd = void;
777     dysymtab_command dysymtab_cmd = void;
778 
779     memset(&segment_cmd, 0, segment_cmd.sizeof);
780     memset(&segment_cmd64, 0, segment_cmd64.sizeof);
781     memset(&symtab_cmd, 0, symtab_cmd.sizeof);
782     memset(&dysymtab_cmd, 0, dysymtab_cmd.sizeof);
783 
784     if (I64)
785     {
786         segment_cmd64.cmd = LC_SEGMENT_64;
787         segment_cmd64.cmdsize = cast(uint)(segment_cmd64.sizeof +
788                                     (section_cnt - 1) * section_64.sizeof);
789         segment_cmd64.nsects = section_cnt - 1;
790         segment_cmd64.maxprot = 7;
791         segment_cmd64.initprot = 7;
792     }
793     else
794     {
795         segment_cmd.cmd = LC_SEGMENT;
796         segment_cmd.cmdsize = cast(uint)(segment_cmd.sizeof +
797                                     (section_cnt - 1) * section.sizeof);
798         segment_cmd.nsects = section_cnt - 1;
799         segment_cmd.maxprot = 7;
800         segment_cmd.initprot = 7;
801     }
802 
803     symtab_cmd.cmd = LC_SYMTAB;
804     symtab_cmd.cmdsize = symtab_cmd.sizeof;
805 
806     dysymtab_cmd.cmd = LC_DYSYMTAB;
807     dysymtab_cmd.cmdsize = dysymtab_cmd.sizeof;
808 
809     /* If a __pointers section was emitted, need to set the .reserved1
810      * field to the symbol index in the indirect symbol table of the
811      * start of the __pointers symbols.
812      */
813     if (pointersSeg)
814     {
815         seg_data *pseg = SegData[pointersSeg];
816         if (I64)
817         {
818             section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section
819             psechdr.reserved1 = cast(uint)(indirectsymbuf1
820                 ? indirectsymbuf1.length() / (Symbol *).sizeof
821                 : 0);
822         }
823         else
824         {
825             section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section
826             psechdr.reserved1 = cast(uint)(indirectsymbuf1
827                 ? indirectsymbuf1.length() / (Symbol *).sizeof
828                 : 0);
829         }
830     }
831 
832     // Walk through sections determining size and file offsets
833 
834     //
835     // First output individual section data associate with program
836     //  code and data
837     //
838     foffset = elf_align(I64 ? 8 : 4, foffset);
839     if (I64)
840         segment_cmd64.fileoff = foffset;
841     else
842         segment_cmd.fileoff = foffset;
843     uint vmaddr = 0;
844 
845     //printf("Setup offsets and sizes foffset %d\n\tsection_cnt %d, seg_count %d\n",foffset,section_cnt,seg_count);
846     // Zero filled segments go at the end, so go through segments twice
847     for (int i = 0; i < 2; i++)
848     {
849         for (int seg = 1; seg <= seg_count; seg++)
850         {
851             seg_data *pseg = SegData[seg];
852             if (I64)
853             {
854                 section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section
855 
856                 // Do zero-fill the second time through this loop
857                 if (i ^ (psechdr.flags == S_ZEROFILL))
858                     continue;
859 
860                 int align_ = 1 << psechdr._align;
861                 while (psechdr._align > 0 && align_ < pseg.SDalignment)
862                 {
863                     psechdr._align += 1;
864                     align_ <<= 1;
865                 }
866                 foffset = elf_align(align_, foffset);
867                 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
868                 if (psechdr.flags == S_ZEROFILL)
869                 {
870                     psechdr.offset = 0;
871                     psechdr.size = pseg.SDoffset; // accumulated size
872                 }
873                 else
874                 {
875                     psechdr.offset = foffset;
876                     psechdr.size = 0;
877                     //printf("\tsection name %s,", psechdr.sectname);
878                     if (pseg.SDbuf && pseg.SDbuf.length())
879                     {
880                         //printf("\tsize %d\n", pseg.SDbuf.length());
881                         psechdr.size = pseg.SDbuf.length();
882                         fobjbuf.write(pseg.SDbuf.buf, cast(uint)psechdr.size);
883                         foffset += psechdr.size;
884                     }
885                 }
886                 psechdr.addr = vmaddr;
887                 vmaddr += psechdr.size;
888                 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size);
889             }
890             else
891             {
892                 section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section
893 
894                 // Do zero-fill the second time through this loop
895                 if (i ^ (psechdr.flags == S_ZEROFILL))
896                     continue;
897 
898                 int align_ = 1 << psechdr._align;
899                 while (psechdr._align > 0 && align_ < pseg.SDalignment)
900                 {
901                     psechdr._align += 1;
902                     align_ <<= 1;
903                 }
904                 foffset = elf_align(align_, foffset);
905                 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
906                 if (psechdr.flags == S_ZEROFILL)
907                 {
908                     psechdr.offset = 0;
909                     psechdr.size = cast(uint)pseg.SDoffset; // accumulated size
910                 }
911                 else
912                 {
913                     psechdr.offset = foffset;
914                     psechdr.size = 0;
915                     //printf("\tsection name %s,", psechdr.sectname);
916                     if (pseg.SDbuf && pseg.SDbuf.length())
917                     {
918                         //printf("\tsize %d\n", pseg.SDbuf.length());
919                         psechdr.size = cast(uint)pseg.SDbuf.length();
920                         fobjbuf.write(pseg.SDbuf.buf, psechdr.size);
921                         foffset += psechdr.size;
922                     }
923                 }
924                 psechdr.addr = vmaddr;
925                 vmaddr += psechdr.size;
926                 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size);
927             }
928         }
929     }
930 
931     if (I64)
932     {
933         segment_cmd64.vmsize = vmaddr;
934         segment_cmd64.filesize = foffset - segment_cmd64.fileoff;
935         /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an
936          * error, and is happening sometimes.
937          */
938         if (segment_cmd64.filesize > vmaddr)
939             segment_cmd64.vmsize = segment_cmd64.filesize;
940     }
941     else
942     {
943         segment_cmd.vmsize = vmaddr;
944         segment_cmd.filesize = foffset - segment_cmd.fileoff;
945         /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an
946          * error, and is happening sometimes.
947          */
948         if (segment_cmd.filesize > vmaddr)
949             segment_cmd.vmsize = segment_cmd.filesize;
950     }
951 
952     // Put out relocation data
953     mach_numbersyms();
954     for (int seg = 1; seg <= seg_count; seg++)
955     {
956         seg_data *pseg = SegData[seg];
957         section *psechdr = null;
958         section_64 *psechdr64 = null;
959         if (I64)
960         {
961             psechdr64 = &SecHdrTab64[pseg.SDshtidx];   // corresponding section
962             //printf("psechdr.addr = x%llx\n", psechdr64.addr);
963         }
964         else
965         {
966             psechdr = &SecHdrTab[pseg.SDshtidx];   // corresponding section
967             //printf("psechdr.addr = x%x\n", psechdr.addr);
968         }
969         foffset = elf_align(I64 ? 8 : 4, foffset);
970         uint reloff = foffset;
971         uint nreloc = 0;
972         if (pseg.SDrel)
973         {   Relocation *r = cast(Relocation *)pseg.SDrel.buf;
974             Relocation *rend = cast(Relocation *)(pseg.SDrel.buf + pseg.SDrel.length());
975             for (; r != rend; r++)
976             {   Symbol *s = r.targsym;
977                 const(char)* rs = r.rtype == RELaddr ? "addr" : "rel";
978                 //printf("%d:x%04llx : tseg %d tsym %s REL%s\n", seg, r.offset, r.targseg, s ? s.Sident.ptr : "0", rs);
979                 relocation_info rel;
980                 scattered_relocation_info srel;
981                 if (s)
982                 {
983                     //printf("Relocation\n");
984                     //symbol_print(s);
985                     if (r.flag == 1)
986                     {
987                         if (I64)
988                         {
989                             rel.r_type = X86_64_RELOC_SUBTRACTOR;
990                             rel.r_address = cast(int)r.offset;
991                             rel.r_symbolnum = r.funcsym.Sxtrnnum;
992                             rel.r_pcrel = 0;
993                             rel.r_length = 3;
994                             rel.r_extern = 1;
995                             fobjbuf.write(&rel, rel.sizeof);
996                             foffset += (rel).sizeof;
997                             ++nreloc;
998 
999                             rel.r_type = X86_64_RELOC_UNSIGNED;
1000                             rel.r_symbolnum = s.Sxtrnnum;
1001                             fobjbuf.write(&rel, rel.sizeof);
1002                             foffset += rel.sizeof;
1003                             ++nreloc;
1004 
1005                             // patch with fdesym.Soffset - offset
1006                             int64_t *p = cast(int64_t *)patchAddr64(seg, r.offset);
1007                             *p += r.funcsym.Soffset - r.offset;
1008                             continue;
1009                         }
1010                         else
1011                         {
1012                             // address = segment + offset
1013                             int targ_address = cast(int)(SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset);
1014                             int fixup_address = cast(int)(psechdr.addr + r.offset);
1015 
1016                             srel.r_scattered = 1;
1017                             srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF;
1018                             srel.r_address = cast(uint)r.offset;
1019                             srel.r_pcrel = 0;
1020                             srel.r_length = 2;
1021                             srel.r_value = targ_address;
1022                             fobjbuf.write((&srel)[0 .. 1]);
1023                             foffset += srel.sizeof;
1024                             ++nreloc;
1025 
1026                             srel.r_type = GENERIC_RELOC_PAIR;
1027                             srel.r_address = 0;
1028                             srel.r_value = fixup_address;
1029                             fobjbuf.write(&srel, srel.sizeof);
1030                             foffset += srel.sizeof;
1031                             ++nreloc;
1032 
1033                             int32_t *p = patchAddr(seg, r.offset);
1034                             *p += targ_address - fixup_address;
1035                             continue;
1036                         }
1037                     }
1038                     else if (pseg.isCode())
1039                     {
1040                         if (I64)
1041                         {
1042                             rel.r_type = (r.rtype == RELrel)
1043                                     ? X86_64_RELOC_BRANCH
1044                                     : X86_64_RELOC_SIGNED;
1045                             if (r.val == -1)
1046                                 rel.r_type = X86_64_RELOC_SIGNED_1;
1047                             else if (r.val == -2)
1048                                 rel.r_type = X86_64_RELOC_SIGNED_2;
1049                             if (r.val == -4)
1050                                 rel.r_type = X86_64_RELOC_SIGNED_4;
1051 
1052                             if (s.Sclass == SCextern ||
1053                                 s.Sclass == SCcomdef ||
1054                                 s.Sclass == SCcomdat ||
1055                                 s.Sclass == SCglobal)
1056                             {
1057                                 if (I64 && (s.ty() & mTYLINK) == mTYthread && r.rtype == RELaddr)
1058                                     rel.r_type = X86_64_RELOC_TLV;
1059                                 else if ((s.Sfl == FLfunc || s.Sfl == FLextern || s.Sclass == SCglobal || s.Sclass == SCcomdat || s.Sclass == SCcomdef) && r.rtype == RELaddr)
1060                                 {
1061                                     rel.r_type = X86_64_RELOC_GOT_LOAD;
1062                                     if (seg == eh_frame_seg ||
1063                                         seg == except_table_seg)
1064                                         rel.r_type = X86_64_RELOC_GOT;
1065                                 }
1066                                 rel.r_address = cast(int)r.offset;
1067                                 rel.r_symbolnum = s.Sxtrnnum;
1068                                 rel.r_pcrel = 1;
1069                                 rel.r_length = 2;
1070                                 rel.r_extern = 1;
1071                                 fobjbuf.write(&rel, rel.sizeof);
1072                                 foffset += rel.sizeof;
1073                                 nreloc++;
1074                                 continue;
1075                             }
1076                             else
1077                             {
1078                                 rel.r_address = cast(int)r.offset;
1079                                 rel.r_symbolnum = s.Sseg;
1080                                 rel.r_pcrel = 1;
1081                                 rel.r_length = 2;
1082                                 rel.r_extern = 0;
1083                                 fobjbuf.write(&rel, rel.sizeof);
1084                                 foffset += rel.sizeof;
1085                                 nreloc++;
1086 
1087                                 int32_t *p = patchAddr64(seg, r.offset);
1088                                 // Absolute address; add in addr of start of targ seg
1089 //printf("*p = x%x, .addr = x%x, Soffset = x%x\n", *p, cast(int)SecHdrTab64[SegData[s.Sseg].SDshtidx].addr, cast(int)s.Soffset);
1090 //printf("pseg = x%x, r.offset = x%x\n", (int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset);
1091                                 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1092                                 *p += s.Soffset;
1093                                 *p -= SecHdrTab64[pseg.SDshtidx].addr + r.offset + 4;
1094                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1095                                 continue;
1096                             }
1097                         }
1098                     }
1099                     else
1100                     {
1101                         if (s.Sclass == SCextern ||
1102                             s.Sclass == SCcomdef ||
1103                             s.Sclass == SCcomdat)
1104                         {
1105                             rel.r_address = cast(int)r.offset;
1106                             rel.r_symbolnum = s.Sxtrnnum;
1107                             rel.r_pcrel = 0;
1108                             rel.r_length = 2;
1109                             rel.r_extern = 1;
1110                             rel.r_type = GENERIC_RELOC_VANILLA;
1111                             if (I64)
1112                             {
1113                                 rel.r_type = X86_64_RELOC_UNSIGNED;
1114                                 rel.r_length = 3;
1115                             }
1116                             fobjbuf.write(&rel, rel.sizeof);
1117                             foffset += rel.sizeof;
1118                             nreloc++;
1119                             continue;
1120                         }
1121                         else
1122                         {
1123                             rel.r_address = cast(int)r.offset;
1124                             rel.r_symbolnum = s.Sseg;
1125                             rel.r_pcrel = 0;
1126                             rel.r_length = 2;
1127                             rel.r_extern = 0;
1128                             rel.r_type = GENERIC_RELOC_VANILLA;
1129                             if (I64)
1130                             {
1131                                 rel.r_type = X86_64_RELOC_UNSIGNED;
1132                                 rel.r_length = 3;
1133                                 if (0 && s.Sseg != seg)
1134                                     rel.r_type = X86_64_RELOC_BRANCH;
1135                             }
1136                             fobjbuf.write(&rel, rel.sizeof);
1137                             foffset += rel.sizeof;
1138                             nreloc++;
1139                             if (I64)
1140                             {
1141                                 rel.r_length = 3;
1142                                 int32_t *p = patchAddr64(seg, r.offset);
1143                                 // Absolute address; add in addr of start of targ seg
1144                                 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr + s.Soffset;
1145                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1146                             }
1147                             else
1148                             {
1149                                 int32_t *p = patchAddr(seg, r.offset);
1150                                 // Absolute address; add in addr of start of targ seg
1151                                 *p += SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset;
1152                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1153                             }
1154                             continue;
1155                         }
1156                     }
1157                 }
1158                 else if (r.rtype == RELaddr && pseg.isCode())
1159                 {
1160                     srel.r_scattered = 1;
1161 
1162                     srel.r_address = cast(uint)r.offset;
1163                     srel.r_length = 2;
1164                     if (I64)
1165                     {
1166                         int32_t *p64 = patchAddr64(seg, r.offset);
1167                         srel.r_type = X86_64_RELOC_GOT;
1168                         srel.r_value = cast(int)(SecHdrTab64[SegData[r.targseg].SDshtidx].addr + *p64);
1169                         //printf("SECTDIFF: x%llx + x%llx = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value);
1170                     }
1171                     else
1172                     {
1173                         int32_t *p = patchAddr(seg, r.offset);
1174                         srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF;
1175                         srel.r_value = SecHdrTab[SegData[r.targseg].SDshtidx].addr + *p;
1176                         //printf("SECTDIFF: x%x + x%x = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value);
1177                     }
1178                     srel.r_pcrel = 0;
1179                     fobjbuf.write(&srel, srel.sizeof);
1180                     foffset += srel.sizeof;
1181                     nreloc++;
1182 
1183                     srel.r_address = 0;
1184                     srel.r_length = 2;
1185                     if (I64)
1186                     {
1187                         srel.r_type = X86_64_RELOC_SIGNED;
1188                         srel.r_value = cast(int)(SecHdrTab64[pseg.SDshtidx].addr +
1189                                 r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1190                     }
1191                     else
1192                     {
1193                         srel.r_type = GENERIC_RELOC_PAIR;
1194                         if (r.funcsym)
1195                             srel.r_value = cast(int)(SecHdrTab[pseg.SDshtidx].addr +
1196                                     r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1197                         else
1198                             srel.r_value = cast(int)(psechdr.addr + r.offset);
1199                         //printf("srel.r_value = x%x, psechdr.addr = x%x, r.offset = x%x\n",
1200                             //cast(int)srel.r_value, cast(int)psechdr.addr, cast(int)r.offset);
1201                     }
1202                     srel.r_pcrel = 0;
1203                     fobjbuf.write(&srel, srel.sizeof);
1204                     foffset += srel.sizeof;
1205                     nreloc++;
1206 
1207                     // Recalc due to possible realloc of fobjbuf.buf
1208                     if (I64)
1209                     {
1210                         int32_t *p64 = patchAddr64(seg, r.offset);
1211                         //printf("address = x%x, p64 = %p *p64 = x%llx\n", r.offset, p64, *p64);
1212                         *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr -
1213                               (SecHdrTab64[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1214                     }
1215                     else
1216                     {
1217                         int32_t *p = patchAddr(seg, r.offset);
1218                         //printf("address = x%x, p = %p *p = x%x\n", r.offset, p, *p);
1219                         if (r.funcsym)
1220                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr -
1221                                   (SecHdrTab[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1222                         else
1223                             // targ_address - fixup_address
1224                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr -
1225                                   (psechdr.addr + r.offset);
1226                     }
1227                     continue;
1228                 }
1229                 else
1230                 {
1231                     rel.r_address = cast(int)r.offset;
1232                     rel.r_symbolnum = r.targseg;
1233                     rel.r_pcrel = (r.rtype == RELaddr) ? 0 : 1;
1234                     rel.r_length = 2;
1235                     rel.r_extern = 0;
1236                     rel.r_type = GENERIC_RELOC_VANILLA;
1237                     if (I64)
1238                     {
1239                         rel.r_type = X86_64_RELOC_UNSIGNED;
1240                         rel.r_length = 3;
1241                         if (0 && r.targseg != seg)
1242                             rel.r_type = X86_64_RELOC_BRANCH;
1243                     }
1244                     fobjbuf.write(&rel, rel.sizeof);
1245                     foffset += rel.sizeof;
1246                     nreloc++;
1247                     if (I64)
1248                     {
1249                         int32_t *p64 = patchAddr64(seg, r.offset);
1250                         //int64_t before = *p64;
1251                         if (rel.r_pcrel)
1252                             // Relative address
1253                             patch(pseg, r.offset, r.targseg, 0);
1254                         else
1255                         {   // Absolute address; add in addr of start of targ seg
1256 //printf("*p = x%x, targ.addr = x%x\n", *p64, cast(int)SecHdrTab64[SegData[r.targseg].SDshtidx].addr);
1257 //printf("pseg = x%x, r.offset = x%x\n", cast(int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset);
1258                             *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr;
1259                             //*p64 -= SecHdrTab64[pseg.SDshtidx].addr;
1260                         }
1261                         //printf("%d:x%04x before = x%04llx, after = x%04llx pcrel = %d\n", seg, r.offset, before, *p64, rel.r_pcrel);
1262                     }
1263                     else
1264                     {
1265                         int32_t *p = patchAddr(seg, r.offset);
1266                         //int32_t before = *p;
1267                         if (rel.r_pcrel)
1268                             // Relative address
1269                             patch(pseg, r.offset, r.targseg, 0);
1270                         else
1271                             // Absolute address; add in addr of start of targ seg
1272                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr;
1273                         //printf("%d:x%04x before = x%04x, after = x%04x pcrel = %d\n", seg, r.offset, before, *p, rel.r_pcrel);
1274                     }
1275                     continue;
1276                 }
1277             }
1278         }
1279         if (nreloc)
1280         {
1281             if (I64)
1282             {
1283                 psechdr64.reloff = reloff;
1284                 psechdr64.nreloc = nreloc;
1285             }
1286             else
1287             {
1288                 psechdr.reloff = reloff;
1289                 psechdr.nreloc = nreloc;
1290             }
1291         }
1292     }
1293 
1294     // Put out symbol table
1295     foffset = elf_align(I64 ? 8 : 4, foffset);
1296     symtab_cmd.symoff = foffset;
1297     dysymtab_cmd.ilocalsym = 0;
1298     dysymtab_cmd.nlocalsym  = cast(uint)(local_symbuf.length() / (Symbol *).sizeof);
1299     dysymtab_cmd.iextdefsym = dysymtab_cmd.nlocalsym;
1300     dysymtab_cmd.nextdefsym = cast(uint)(public_symbuf.length() / (Symbol *).sizeof);
1301     dysymtab_cmd.iundefsym = dysymtab_cmd.iextdefsym + dysymtab_cmd.nextdefsym;
1302     int nexterns = cast(int)(extern_symbuf.length() / (Symbol *).sizeof);
1303     int ncomdefs = cast(int)(comdef_symbuf.length() / Comdef.sizeof);
1304     dysymtab_cmd.nundefsym  = nexterns + ncomdefs;
1305     symtab_cmd.nsyms =  dysymtab_cmd.nlocalsym +
1306                         dysymtab_cmd.nextdefsym +
1307                         dysymtab_cmd.nundefsym;
1308     fobjbuf.reserve(cast(uint)(symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof)));
1309     for (int i = 0; i < dysymtab_cmd.nlocalsym; i++)
1310     {   Symbol *s = (cast(Symbol **)local_symbuf.buf)[i];
1311         nlist_64 sym = void;
1312         sym.n_strx = elf_addmangled(s);
1313         sym.n_type = N_SECT;
1314         sym.n_desc = 0;
1315         if (s.Sclass == SCcomdat)
1316             sym.n_desc = N_WEAK_DEF;
1317         sym.n_sect = cast(ubyte)s.Sseg;
1318         if (I64)
1319         {
1320             sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1321             fobjbuf.write(&sym, sym.sizeof);
1322         }
1323         else
1324         {
1325             nlist sym32 = void;
1326             sym32.n_strx = sym.n_strx;
1327             sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr);
1328             sym32.n_type = sym.n_type;
1329             sym32.n_desc = sym.n_desc;
1330             sym32.n_sect = sym.n_sect;
1331             fobjbuf.write(&sym32, sym32.sizeof);
1332         }
1333     }
1334     for (int i = 0; i < dysymtab_cmd.nextdefsym; i++)
1335     {   Symbol *s = (cast(Symbol **)public_symbuf.buf)[i];
1336 
1337         //printf("Writing public symbol %d:x%x %s\n", s.Sseg, s.Soffset, s.Sident);
1338         nlist_64 sym = void;
1339         sym.n_strx = elf_addmangled(s);
1340         sym.n_type = N_EXT | N_SECT;
1341         if (s.Sflags & SFLhidden)
1342             sym.n_type |= N_PEXT; // private extern
1343         sym.n_desc = 0;
1344         if (s.Sclass == SCcomdat)
1345             sym.n_desc = N_WEAK_DEF;
1346         sym.n_sect = cast(ubyte)s.Sseg;
1347         if (I64)
1348         {
1349             sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1350             fobjbuf.write(&sym, sym.sizeof);
1351         }
1352         else
1353         {
1354             nlist sym32 = void;
1355             sym32.n_strx = sym.n_strx;
1356             sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr);
1357             sym32.n_type = sym.n_type;
1358             sym32.n_desc = sym.n_desc;
1359             sym32.n_sect = sym.n_sect;
1360             fobjbuf.write(&sym32, sym32.sizeof);
1361         }
1362     }
1363     for (int i = 0; i < nexterns; i++)
1364     {   Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i];
1365         nlist_64 sym = void;
1366         sym.n_strx = elf_addmangled(s);
1367         sym.n_value = s.Soffset;
1368         sym.n_type = N_EXT | N_UNDF;
1369         sym.n_desc = tyfunc(s.ty()) ? REFERENCE_FLAG_UNDEFINED_LAZY
1370                                      : REFERENCE_FLAG_UNDEFINED_NON_LAZY;
1371         sym.n_sect = 0;
1372         if (I64)
1373             fobjbuf.write(&sym, sym.sizeof);
1374         else
1375         {
1376             nlist sym32 = void;
1377             sym32.n_strx = sym.n_strx;
1378             sym32.n_value = cast(uint)sym.n_value;
1379             sym32.n_type = sym.n_type;
1380             sym32.n_desc = sym.n_desc;
1381             sym32.n_sect = sym.n_sect;
1382             fobjbuf.write(&sym32, sym32.sizeof);
1383         }
1384     }
1385     for (int i = 0; i < ncomdefs; i++)
1386     {   Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i;
1387         nlist_64 sym = void;
1388         sym.n_strx = elf_addmangled(c.sym);
1389         sym.n_value = c.size * c.count;
1390         sym.n_type = N_EXT | N_UNDF;
1391         int align_;
1392         if (c.size < 2)
1393             align_ = 0;          // align_ is expressed as power of 2
1394         else if (c.size < 4)
1395             align_ = 1;
1396         else if (c.size < 8)
1397             align_ = 2;
1398         else if (c.size < 16)
1399             align_ = 3;
1400         else
1401             align_ = 4;
1402         sym.n_desc = cast(ushort)(align_ << 8);
1403         sym.n_sect = 0;
1404         if (I64)
1405             fobjbuf.write(&sym, sym.sizeof);
1406         else
1407         {
1408             nlist sym32 = void;
1409             sym32.n_strx = sym.n_strx;
1410             sym32.n_value = cast(uint)sym.n_value;
1411             sym32.n_type = sym.n_type;
1412             sym32.n_desc = sym.n_desc;
1413             sym32.n_sect = sym.n_sect;
1414             fobjbuf.write(&sym32, sym32.sizeof);
1415         }
1416     }
1417     if (extdef)
1418     {
1419         nlist_64 sym = void;
1420         sym.n_strx = extdef;
1421         sym.n_value = 0;
1422         sym.n_type = N_EXT | N_UNDF;
1423         sym.n_desc = 0;
1424         sym.n_sect = 0;
1425         if (I64)
1426             fobjbuf.write(&sym, sym.sizeof);
1427         else
1428         {
1429             nlist sym32 = void;
1430             sym32.n_strx = sym.n_strx;
1431             sym32.n_value = cast(uint)sym.n_value;
1432             sym32.n_type = sym.n_type;
1433             sym32.n_desc = sym.n_desc;
1434             sym32.n_sect = sym.n_sect;
1435             fobjbuf.write(&sym32, sym32.sizeof);
1436         }
1437         symtab_cmd.nsyms++;
1438     }
1439     foffset += symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof);
1440 
1441     // Put out string table
1442     foffset = elf_align(I64 ? 8 : 4, foffset);
1443     symtab_cmd.stroff = foffset;
1444     symtab_cmd.strsize = cast(uint)symtab_strings.length();
1445     fobjbuf.write(symtab_strings.buf, symtab_cmd.strsize);
1446     foffset += symtab_cmd.strsize;
1447 
1448     // Put out indirectsym table, which is in two parts
1449     foffset = elf_align(I64 ? 8 : 4, foffset);
1450     dysymtab_cmd.indirectsymoff = foffset;
1451     if (indirectsymbuf1)
1452     {
1453         dysymtab_cmd.nindirectsyms += indirectsymbuf1.length() / (Symbol *).sizeof;
1454         for (int i = 0; i < dysymtab_cmd.nindirectsyms; i++)
1455         {   Symbol *s = (cast(Symbol **)indirectsymbuf1.buf)[i];
1456             fobjbuf.write32(s.Sxtrnnum);
1457         }
1458     }
1459     if (indirectsymbuf2)
1460     {
1461         int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof);
1462         dysymtab_cmd.nindirectsyms += n;
1463         for (int i = 0; i < n; i++)
1464         {   Symbol *s = (cast(Symbol **)indirectsymbuf2.buf)[i];
1465             fobjbuf.write32(s.Sxtrnnum);
1466         }
1467     }
1468     foffset += dysymtab_cmd.nindirectsyms * 4;
1469 
1470     /* The correct offsets are now determined, so
1471      * rewind and fix the header.
1472      */
1473     fobjbuf.position(headersize, sizeofcmds);
1474     if (I64)
1475     {
1476         fobjbuf.write(&segment_cmd64, segment_cmd64.sizeof);
1477         fobjbuf.write(SECbuf.buf + section_64.sizeof, cast(uint)((section_cnt - 1) * section_64.sizeof));
1478     }
1479     else
1480     {
1481         fobjbuf.write(&segment_cmd, segment_cmd.sizeof);
1482         fobjbuf.write(SECbuf.buf + section.sizeof, cast(uint)((section_cnt - 1) * section.sizeof));
1483     }
1484     fobjbuf.write(&symtab_cmd, symtab_cmd.sizeof);
1485     fobjbuf.write(&dysymtab_cmd, dysymtab_cmd.sizeof);
1486     fobjbuf.position(foffset, 0);
1487 }
1488 
1489 /*****************************
1490  * Line number support.
1491  */
1492 
1493 /***************************
1494  * Record file and line number at segment and offset.
1495  * The actual .debug_line segment is put out by dwarf_termfile().
1496  * Params:
1497  *      srcpos = source file position
1498  *      seg = segment it corresponds to
1499  *      offset = offset within seg
1500  */
1501 
1502 void Obj_linnum(Srcpos srcpos, int seg, targ_size_t offset)
1503 {
1504     if (srcpos.Slinnum == 0)
1505         return;
1506 
1507 static if (0)
1508 {
1509     printf("Obj_linnum(seg=%d, offset=x%lx) ", seg, offset);
1510     srcpos.print("");
1511 }
1512 
1513 version (MARS)
1514 {
1515     if (!srcpos.Sfilename)
1516         return;
1517 }
1518 version (SCPP)
1519 {
1520     if (!srcpos.Sfilptr)
1521         return;
1522     sfile_debug(&srcpos_sfile(srcpos));
1523     Sfile *sf = *srcpos.Sfilptr;
1524 }
1525 
1526     size_t i;
1527     seg_data *pseg = SegData[seg];
1528 
1529     // Find entry i in SDlinnum_data[] that corresponds to srcpos filename
1530     for (i = 0; 1; i++)
1531     {
1532         if (i == pseg.SDlinnum_count)
1533         {   // Create new entry
1534             if (pseg.SDlinnum_count == pseg.SDlinnum_max)
1535             {   // Enlarge array
1536                 uint newmax = pseg.SDlinnum_max * 2 + 1;
1537                 //printf("realloc %d\n", newmax * linnum_data.sizeof);
1538                 pseg.SDlinnum_data = cast(linnum_data *)mem_realloc(
1539                     pseg.SDlinnum_data, newmax * linnum_data.sizeof);
1540                 memset(pseg.SDlinnum_data + pseg.SDlinnum_max, 0,
1541                     (newmax - pseg.SDlinnum_max) * linnum_data.sizeof);
1542                 pseg.SDlinnum_max = newmax;
1543             }
1544             pseg.SDlinnum_count++;
1545 version (MARS)
1546 {
1547             pseg.SDlinnum_data[i].filename = srcpos.Sfilename;
1548 }
1549 version (SCPP)
1550 {
1551             pseg.SDlinnum_data[i].filptr = sf;
1552 }
1553             break;
1554         }
1555 version (MARS)
1556 {
1557         if (pseg.SDlinnum_data[i].filename == srcpos.Sfilename)
1558             break;
1559 }
1560 version (SCPP)
1561 {
1562         if (pseg.SDlinnum_data[i].filptr == sf)
1563             break;
1564 }
1565     }
1566 
1567     linnum_data *ld = &pseg.SDlinnum_data[i];
1568 //    printf("i = %d, ld = x%x\n", i, ld);
1569     if (ld.linoff_count == ld.linoff_max)
1570     {
1571         if (!ld.linoff_max)
1572             ld.linoff_max = 8;
1573         ld.linoff_max *= 2;
1574         ld.linoff = cast(uint[2]*)mem_realloc(ld.linoff, ld.linoff_max * uint.sizeof * 2);
1575     }
1576     ld.linoff[ld.linoff_count][0] = srcpos.Slinnum;
1577     ld.linoff[ld.linoff_count][1] = cast(uint)offset;
1578     ld.linoff_count++;
1579 }
1580 
1581 
1582 /*******************************
1583  * Set start address
1584  */
1585 
1586 void Obj_startaddress(Symbol *s)
1587 {
1588     //dbg_printf("Obj_startaddress(Symbol *%s)\n",s.Sident);
1589     //obj.startaddress = s;
1590 }
1591 
1592 /*******************************
1593  * Output library name.
1594  */
1595 
1596 bool Obj_includelib(const(char)* name)
1597 {
1598     //dbg_printf("Obj_includelib(name *%s)\n",name);
1599     return false;
1600 }
1601 
1602 /*******************************
1603 * Output linker directive.
1604 */
1605 
1606 bool Obj_linkerdirective(const(char)* name)
1607 {
1608     return false;
1609 }
1610 
1611 /**********************************
1612  * Do we allow zero sized objects?
1613  */
1614 
1615 bool Obj_allowZeroSize()
1616 {
1617     return true;
1618 }
1619 
1620 /**************************
1621  * Embed string in executable.
1622  */
1623 
1624 void Obj_exestr(const(char)* p)
1625 {
1626     //dbg_printf("Obj_exestr(char *%s)\n",p);
1627 }
1628 
1629 /**************************
1630  * Embed string in obj.
1631  */
1632 
1633 void Obj_user(const(char)* p)
1634 {
1635     //dbg_printf("Obj_user(char *%s)\n",p);
1636 }
1637 
1638 /*******************************
1639  * Output a weak extern record.
1640  */
1641 
1642 void Obj_wkext(Symbol *s1,Symbol *s2)
1643 {
1644     //dbg_printf("Obj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr);
1645 }
1646 
1647 /*******************************
1648  * Output file name record.
1649  *
1650  * Currently assumes that obj_filename will not be called
1651  *      twice for the same file.
1652  */
1653 
1654 void obj_filename(const(char)* modname)
1655 {
1656     //dbg_printf("obj_filename(char *%s)\n",modname);
1657     // Not supported by Mach-O
1658 }
1659 
1660 /*******************************
1661  * Embed compiler version in .obj file.
1662  */
1663 
1664 void Obj_compiler()
1665 {
1666     //dbg_printf("Obj_compiler\n");
1667 }
1668 
1669 
1670 /**************************************
1671  * Symbol is the function that calls the static constructors.
1672  * Put a pointer to it into a special segment that the startup code
1673  * looks at.
1674  * Input:
1675  *      s       static constructor function
1676  *      dtor    !=0 if leave space for static destructor
1677  *      seg     1:      user
1678  *              2:      lib
1679  *              3:      compiler
1680  */
1681 
1682 void Obj_staticctor(Symbol *s, int, int)
1683 {
1684     Obj_setModuleCtorDtor(s, true);
1685 }
1686 
1687 /**************************************
1688  * Symbol is the function that calls the static destructors.
1689  * Put a pointer to it into a special segment that the exit code
1690  * looks at.
1691  * Input:
1692  *      s       static destructor function
1693  */
1694 
1695 void Obj_staticdtor(Symbol *s)
1696 {
1697     Obj_setModuleCtorDtor(s, false);
1698 }
1699 
1700 
1701 /***************************************
1702  * Stuff pointer to function in its own segment.
1703  * Used for static ctor and dtor lists.
1704  */
1705 
1706 void Obj_setModuleCtorDtor(Symbol *sfunc, bool isCtor)
1707 {
1708     const(char)* secname = isCtor ? "__mod_init_func" : "__mod_term_func";
1709     const int align_ = I64 ? 3 : 2; // align to _tysize[TYnptr]
1710     const int flags = isCtor ? S_MOD_INIT_FUNC_POINTERS : S_MOD_TERM_FUNC_POINTERS;
1711     IDXSEC seg = Obj_getsegment(secname, "__DATA", align_, flags);
1712 
1713     const int relflags = I64 ? CFoff | CFoffset64 : CFoff;
1714     const int sz = Obj_reftoident(seg, SegData[seg].SDoffset, sfunc, 0, relflags);
1715     SegData[seg].SDoffset += sz;
1716 }
1717 
1718 
1719 /***************************************
1720  * Stuff the following data (instance of struct FuncTable) in a separate segment:
1721  *      pointer to function
1722  *      pointer to ehsym
1723  *      length of function
1724  */
1725 
1726 void Obj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym)
1727 {
1728     //dbg_printf("Obj_ehtables(%s) \n",sfunc.Sident.ptr);
1729 
1730     /* BUG: this should go into a COMDAT if sfunc is in a COMDAT
1731      * otherwise the duplicates aren't removed.
1732      */
1733 
1734     int align_ = I64 ? 3 : 2;            // align to _tysize[TYnptr]
1735     // The size is (FuncTable).sizeof in deh2.d
1736     int seg = Obj_getsegment("__deh_eh", "__DATA", align_, S_REGULAR);
1737 
1738     Outbuffer *buf = SegData[seg].SDbuf;
1739     if (I64)
1740     {
1741         Obj_reftoident(seg, buf.length(), sfunc, 0, CFoff | CFoffset64);
1742         Obj_reftoident(seg, buf.length(), ehsym, 0, CFoff | CFoffset64);
1743         buf.write64(sfunc.Ssize);
1744     }
1745     else
1746     {
1747         Obj_reftoident(seg, buf.length(), sfunc, 0, CFoff);
1748         Obj_reftoident(seg, buf.length(), ehsym, 0, CFoff);
1749         buf.write32(cast(int)sfunc.Ssize);
1750     }
1751 }
1752 
1753 /*********************************************
1754  * Put out symbols that define the beginning/end of the .deh_eh section.
1755  * This gets called if this is the module with "main()" in it.
1756  */
1757 
1758 void Obj_ehsections()
1759 {
1760     //printf("Obj_ehsections()\n");
1761 }
1762 
1763 /*********************************
1764  * Setup for Symbol s to go into a COMDAT segment.
1765  * Output (if s is a function):
1766  *      cseg            segment index of new current code segment
1767  *      Offset(cseg)         starting offset in cseg
1768  * Returns:
1769  *      "segment index" of COMDAT
1770  */
1771 
1772 int Obj_comdatsize(Symbol *s, targ_size_t symsize)
1773 {
1774     return Obj_comdat(s);
1775 }
1776 
1777 int Obj_comdat(Symbol *s)
1778 {
1779     const(char)* sectname;
1780     const(char)* segname;
1781     int align_;
1782     int flags;
1783 
1784     //printf("Obj_comdat(Symbol* %s)\n",s.Sident.ptr);
1785     //symbol_print(s);
1786     symbol_debug(s);
1787 
1788     if (tyfunc(s.ty()))
1789     {
1790         sectname = "__textcoal_nt";
1791         segname = "__TEXT";
1792         align_ = 2;              // 4 byte alignment
1793         flags = S_COALESCED | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
1794         s.Sseg = Obj_getsegment(sectname, segname, align_, flags);
1795     }
1796     else if ((s.ty() & mTYLINK) == mTYthread)
1797     {
1798         s.Sfl = FLtlsdata;
1799         align_ = 4;
1800         if (I64)
1801             s.Sseg = objmod.tlsseg().SDseg;
1802         else
1803             s.Sseg = Obj_getsegment("__tlscoal_nt", "__DATA", align_, S_COALESCED);
1804         Obj_data_start(s, 1 << align_, s.Sseg);
1805     }
1806     else
1807     {
1808         s.Sfl = FLdata;
1809         sectname = "__datacoal_nt";
1810         segname = "__DATA";
1811         align_ = 4;              // 16 byte alignment
1812         s.Sseg = Obj_getsegment(sectname, segname, align_, S_COALESCED);
1813         Obj_data_start(s, 1 << align_, s.Sseg);
1814     }
1815                                 // find or create new segment
1816     if (s.Salignment > (1 << align_))
1817         SegData[s.Sseg].SDalignment = s.Salignment;
1818     s.Soffset = SegData[s.Sseg].SDoffset;
1819     if (s.Sfl == FLdata || s.Sfl == FLtlsdata)
1820     {   // Code symbols are 'published' by Obj_func_start()
1821 
1822         Obj_pubdef(s.Sseg,s,s.Soffset);
1823         searchfixlist(s);               // backpatch any refs to this symbol
1824     }
1825     return s.Sseg;
1826 }
1827 
1828 int Obj_readonly_comdat(Symbol *s)
1829 {
1830     assert(0);
1831 }
1832 
1833 /***********************************
1834  * Returns:
1835  *      jump table segment for function s
1836  */
1837 int Obj_jmpTableSegment(Symbol *s)
1838 {
1839     return (config.flags & CFGromable) ? cseg : CDATA;
1840 }
1841 
1842 /**********************************
1843  * Get segment.
1844  * Input:
1845  *      align_   segment alignment as power of 2
1846  * Returns:
1847  *      segment index of found or newly created segment
1848  */
1849 
1850 int Obj_getsegment(const(char)* sectname, const(char)* segname,
1851         int align_, int flags)
1852 {
1853     assert(strlen(sectname) <= 16);
1854     assert(strlen(segname)  <= 16);
1855     for (int seg = 1; seg <= seg_count; seg++)
1856     {   seg_data *pseg = SegData[seg];
1857         if (I64)
1858         {
1859             if (strncmp(SecHdrTab64[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 &&
1860                 strncmp(SecHdrTab64[pseg.SDshtidx].segname.ptr, segname, 16) == 0)
1861                 return seg;         // return existing segment
1862         }
1863         else
1864         {
1865             if (strncmp(SecHdrTab[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 &&
1866                 strncmp(SecHdrTab[pseg.SDshtidx].segname.ptr, segname, 16) == 0)
1867                 return seg;         // return existing segment
1868         }
1869     }
1870 
1871     int seg = ++seg_count;
1872     if (seg_count >= seg_max)
1873     {                           // need more room in segment table
1874         seg_max += 10;
1875         SegData = cast(seg_data **)mem_realloc(SegData,seg_max * (seg_data *).sizeof);
1876         memset(&SegData[seg_count], 0, (seg_max - seg_count) * (seg_data *).sizeof);
1877     }
1878     assert(seg_count < seg_max);
1879     if (SegData[seg])
1880     {   seg_data *pseg = SegData[seg];
1881         Outbuffer *b1 = pseg.SDbuf;
1882         Outbuffer *b2 = pseg.SDrel;
1883         memset(pseg, 0, seg_data.sizeof);
1884         if (b1)
1885             b1.reset();
1886         if (b2)
1887             b2.reset();
1888         pseg.SDbuf = b1;
1889         pseg.SDrel = b2;
1890     }
1891     else
1892     {
1893         seg_data *pseg = cast(seg_data *)mem_calloc(seg_data.sizeof);
1894         SegData[seg] = pseg;
1895         if (flags != S_ZEROFILL)
1896         {
1897             pseg.SDbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
1898             assert(pseg.SDbuf);
1899             pseg.SDbuf.reserve(4096);
1900         }
1901     }
1902 
1903     //dbg_printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf);
1904     seg_data *pseg = SegData[seg];
1905 
1906     pseg.SDseg = seg;
1907     pseg.SDoffset = 0;
1908 
1909     if (I64)
1910     {
1911         section_64 *sec = cast(section_64 *)
1912             SECbuf.writezeros(section_64.sizeof);
1913         strncpy(sec.sectname.ptr, sectname, 16);
1914         strncpy(sec.segname.ptr, segname, 16);
1915         sec._align = align_;
1916         sec.flags = flags;
1917     }
1918     else
1919     {
1920         section *sec = cast(section *)
1921             SECbuf.writezeros(section.sizeof);
1922         strncpy(sec.sectname.ptr, sectname, 16);
1923         strncpy(sec.segname.ptr, segname, 16);
1924         sec._align = align_;
1925         sec.flags = flags;
1926     }
1927 
1928     pseg.SDshtidx = section_cnt++;
1929     pseg.SDaranges_offset = 0;
1930     pseg.SDlinnum_count = 0;
1931 
1932     //printf("seg_count = %d\n", seg_count);
1933     return seg;
1934 }
1935 
1936 /**********************************
1937  * Reset code seg to existing seg.
1938  * Used after a COMDAT for a function is done.
1939  */
1940 
1941 void Obj_setcodeseg(int seg)
1942 {
1943     cseg = seg;
1944 }
1945 
1946 /********************************
1947  * Define a new code segment.
1948  * Input:
1949  *      name            name of segment, if null then revert to default
1950  *      suffix  0       use name as is
1951  *              1       append "_TEXT" to name
1952  * Output:
1953  *      cseg            segment index of new current code segment
1954  *      Offset(cseg)         starting offset in cseg
1955  * Returns:
1956  *      segment index of newly created code segment
1957  */
1958 
1959 int Obj_codeseg(const char *name,int suffix)
1960 {
1961     //dbg_printf("Obj_codeseg(%s,%x)\n",name,suffix);
1962 static if (0)
1963 {
1964     const(char)* sfx = (suffix) ? "_TEXT" : null;
1965 
1966     if (!name)                          // returning to default code segment
1967     {
1968         if (cseg != CODE)               // not the current default
1969         {
1970             SegData[cseg].SDoffset = Offset(cseg);
1971             Offset(cseg) = SegData[CODE].SDoffset;
1972             cseg = CODE;
1973         }
1974         return cseg;
1975     }
1976 
1977     int seg = ElfObj_getsegment(name, sfx, SHT_PROGDEF, SHF_ALLOC|SHF_EXECINSTR, 4);
1978                                     // find or create code segment
1979 
1980     cseg = seg;                         // new code segment index
1981     Offset(cseg) = 0;
1982     return seg;
1983 }
1984 else
1985 {
1986     return 0;
1987 }
1988 }
1989 
1990 /*********************************
1991  * Define segments for Thread Local Storage for 32bit.
1992  * Output:
1993  *      seg_tlsseg      set to segment number for TLS segment.
1994  * Returns:
1995  *      segment for TLS segment
1996  */
1997 
1998 seg_data *Obj_tlsseg()
1999 {
2000     //printf("Obj_tlsseg(\n");
2001     if (I32)
2002     {
2003         if (seg_tlsseg == UNKNOWN)
2004             seg_tlsseg = Obj_getsegment("__tls_data", "__DATA", 2, S_REGULAR);
2005         return SegData[seg_tlsseg];
2006     }
2007     else
2008     {
2009         if (seg_tlsseg == UNKNOWN)
2010             seg_tlsseg = Obj_getsegment("__thread_vars", "__DATA", 0, S_THREAD_LOCAL_VARIABLES);
2011         return SegData[seg_tlsseg];
2012     }
2013 }
2014 
2015 
2016 /*********************************
2017  * Define segments for Thread Local Storage.
2018  * Output:
2019  *      seg_tlsseg_bss  set to segment number for TLS segment.
2020  * Returns:
2021  *      segment for TLS segment
2022  */
2023 
2024 seg_data *Obj_tlsseg_bss()
2025 {
2026 
2027     if (I32)
2028     {
2029         /* Because DMD does not support native tls for Mach-O 32bit,
2030          * it's easier to support if we have all the tls in one segment.
2031          */
2032         return Obj_tlsseg();
2033     }
2034     else
2035     {
2036         // The alignment should actually be alignment of the largest variable in
2037         // the section, but this seems to work anyway.
2038         if (seg_tlsseg_bss == UNKNOWN)
2039             seg_tlsseg_bss = Obj_getsegment("__thread_bss", "__DATA", 3, S_THREAD_LOCAL_ZEROFILL);
2040         return SegData[seg_tlsseg_bss];
2041     }
2042 }
2043 
2044 /*********************************
2045  * Define segments for Thread Local Storage data.
2046  * Output:
2047  *      seg_tlsseg_data    set to segment number for TLS data segment.
2048  * Returns:
2049  *      segment for TLS data segment
2050  */
2051 
2052 seg_data *Obj_tlsseg_data()
2053 {
2054     //printf("Obj_tlsseg_data(\n");
2055     assert(I64);
2056 
2057     // The alignment should actually be alignment of the largest variable in
2058     // the section, but this seems to work anyway.
2059     if (seg_tlsseg_data == UNKNOWN)
2060         seg_tlsseg_data = Obj_getsegment("__thread_data", "__DATA", 4, S_THREAD_LOCAL_REGULAR);
2061     return SegData[seg_tlsseg_data];
2062 }
2063 
2064 /*******************************
2065  * Output an alias definition record.
2066  */
2067 
2068 void Obj_alias(const(char)* n1,const(char)* n2)
2069 {
2070     //printf("Obj_alias(%s,%s)\n",n1,n2);
2071     assert(0);
2072 static if (0)
2073 {
2074     uint len;
2075     char *buffer;
2076 
2077     buffer = cast(char *) alloca(strlen(n1) + strlen(n2) + 2 * ONS_OHD);
2078     len = obj_namestring(buffer,n1);
2079     len += obj_namestring(buffer + len,n2);
2080     objrecord(ALIAS,buffer,len);
2081 }
2082 }
2083 
2084 char *unsstr (uint value)
2085 {
2086     __gshared char[64] buffer = void;
2087 
2088     sprintf (buffer.ptr, "%d", value);
2089     return buffer.ptr;
2090 }
2091 
2092 /*******************************
2093  * Mangle a name.
2094  * Returns:
2095  *      mangled name
2096  */
2097 
2098 char *obj_mangle2(Symbol *s,char *dest)
2099 {
2100     size_t len;
2101     char *name;
2102 
2103     //printf("Obj_mangle(s = %p, '%s'), mangle = x%x\n",s,s.Sident.ptr,type_mangle(s.Stype));
2104     symbol_debug(s);
2105     assert(dest);
2106 version (SCPP)
2107 {
2108     name = CPP ? cpp_mangle(s) : s.Sident.ptr;
2109 }
2110 else version (MARS)
2111 {
2112     // C++ name mangling is handled by front end
2113     name = s.Sident.ptr;
2114 }
2115 else
2116 {
2117     name = s.Sident.ptr;
2118 }
2119     len = strlen(name);                 // # of bytes in name
2120     //dbg_printf("len %d\n",len);
2121     switch (type_mangle(s.Stype))
2122     {
2123         case mTYman_pas:                // if upper case
2124         case mTYman_for:
2125             if (len >= DEST_LEN)
2126                 dest = cast(char *)mem_malloc(len + 1);
2127             memcpy(dest,name,len + 1);  // copy in name and ending 0
2128             for (char *p = dest; *p; p++)
2129                 *p = cast(char)toupper(*p);
2130             break;
2131         case mTYman_std:
2132         {
2133 static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_DRAGONFLYBSD || TARGET_SOLARIS)
2134             bool cond = (tyfunc(s.ty()) && !variadic(s.Stype));
2135 else
2136             bool cond = (!(config.flags4 & CFG4oldstdmangle) &&
2137                 config.exe == EX_WIN32 && tyfunc(s.ty()) &&
2138                 !variadic(s.Stype));
2139 
2140             if (cond)
2141             {
2142                 char *pstr = unsstr(type_paramsize(s.Stype));
2143                 size_t pstrlen = strlen(pstr);
2144                 size_t destlen = len + 1 + pstrlen + 1;
2145 
2146                 if (destlen > DEST_LEN)
2147                     dest = cast(char *)mem_malloc(destlen);
2148                 memcpy(dest,name,len);
2149                 dest[len] = '@';
2150                 memcpy(dest + 1 + len, pstr, pstrlen + 1);
2151                 break;
2152             }
2153             goto case;
2154         }
2155         case mTYman_sys:
2156         case 0:
2157             if (len >= DEST_LEN)
2158                 dest = cast(char *)mem_malloc(len + 1);
2159             memcpy(dest,name,len+1);// copy in name and trailing 0
2160             break;
2161 
2162         case mTYman_c:
2163         case mTYman_cpp:
2164         case mTYman_d:
2165             if (len >= DEST_LEN - 1)
2166                 dest = cast(char *)mem_malloc(1 + len + 1);
2167             dest[0] = '_';
2168             memcpy(dest + 1,name,len+1);// copy in name and trailing 0
2169             break;
2170 
2171 
2172         default:
2173 debug
2174 {
2175             printf("mangling %x\n",type_mangle(s.Stype));
2176             symbol_print(s);
2177 }
2178             printf("%d\n", type_mangle(s.Stype));
2179             assert(0);
2180     }
2181     //dbg_printf("\t %s\n",dest);
2182     return dest;
2183 }
2184 
2185 /*******************************
2186  * Export a function name.
2187  */
2188 
2189 void Obj_export_symbol(Symbol *s,uint argsize)
2190 {
2191     //dbg_printf("Obj_export_symbol(%s,%d)\n",s.Sident.ptr,argsize);
2192 }
2193 
2194 /*******************************
2195  * Update data information about symbol
2196  *      align for output and assign segment
2197  *      if not already specified.
2198  *
2199  * Input:
2200  *      sdata           data symbol
2201  *      datasize        output size
2202  *      seg             default seg if not known
2203  * Returns:
2204  *      actual seg
2205  */
2206 
2207 int Obj_data_start(Symbol *sdata, targ_size_t datasize, int seg)
2208 {
2209     targ_size_t alignbytes;
2210 
2211     //printf("Obj_data_start(%s,size %llu,seg %d)\n",sdata.Sident.ptr,datasize,seg);
2212     //symbol_print(sdata);
2213 
2214     assert(sdata.Sseg);
2215     if (sdata.Sseg == UNKNOWN) // if we don't know then there
2216         sdata.Sseg = seg;      // wasn't any segment override
2217     else
2218         seg = sdata.Sseg;
2219     targ_size_t offset = Offset(seg);
2220     if (sdata.Salignment > 0)
2221     {   if (SegData[seg].SDalignment < sdata.Salignment)
2222             SegData[seg].SDalignment = sdata.Salignment;
2223         alignbytes = ((offset + sdata.Salignment - 1) & ~(sdata.Salignment - 1)) - offset;
2224     }
2225     else
2226         alignbytes = _align(datasize, offset) - offset;
2227     if (alignbytes)
2228         Obj_lidata(seg, offset, alignbytes);
2229     sdata.Soffset = offset + alignbytes;
2230     return seg;
2231 }
2232 
2233 /*******************************
2234  * Update function info before codgen
2235  *
2236  * If code for this function is in a different segment
2237  * than the current default in cseg, switch cseg to new segment.
2238  */
2239 
2240 void Obj_func_start(Symbol *sfunc)
2241 {
2242     //printf("Obj_func_start(%s)\n",sfunc.Sident.ptr);
2243     symbol_debug(sfunc);
2244 
2245     assert(sfunc.Sseg);
2246     if (sfunc.Sseg == UNKNOWN)
2247         sfunc.Sseg = CODE;
2248     //printf("sfunc.Sseg %d CODE %d cseg %d Coffset x%x\n",sfunc.Sseg,CODE,cseg,Offset(cseg));
2249     cseg = sfunc.Sseg;
2250     assert(cseg == CODE || cseg > UDATA);
2251     Obj_pubdef(cseg, sfunc, Offset(cseg));
2252     sfunc.Soffset = Offset(cseg);
2253 
2254     dwarf_func_start(sfunc);
2255 }
2256 
2257 /*******************************
2258  * Update function info after codgen
2259  */
2260 
2261 void Obj_func_term(Symbol *sfunc)
2262 {
2263     //dbg_printf("Obj_func_term(%s) offset %x, Coffset %x symidx %d\n",
2264 //          sfunc.Sident.ptr, sfunc.Soffset,Offset(cseg),sfunc.Sxtrnnum);
2265 
2266 static if (0)
2267 {
2268     // fill in the function size
2269     if (I64)
2270         SymbolTable64[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset;
2271     else
2272         SymbolTable[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset;
2273 }
2274     dwarf_func_term(sfunc);
2275 }
2276 
2277 /********************************
2278  * Output a public definition.
2279  * Input:
2280  *      seg =           segment index that symbol is defined in
2281  *      s .            symbol
2282  *      offset =        offset of name within segment
2283  */
2284 
2285 void Obj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize)
2286 {
2287     return Obj_pubdef(seg, s, offset);
2288 }
2289 
2290 void Obj_pubdef(int seg, Symbol *s, targ_size_t offset)
2291 {
2292     //printf("Obj_pubdef(%d:x%x s=%p, %s)\n", seg, offset, s, s.Sident.ptr);
2293     //symbol_print(s);
2294     symbol_debug(s);
2295 
2296     s.Soffset = offset;
2297     s.Sseg = seg;
2298     switch (s.Sclass)
2299     {
2300         case SCglobal:
2301         case SCinline:
2302             public_symbuf.write((&s)[0 .. 1]);
2303             break;
2304         case SCcomdat:
2305         case SCcomdef:
2306             public_symbuf.write((&s)[0 .. 1]);
2307             break;
2308         case SCstatic:
2309             if (s.Sflags & SFLhidden)
2310             {
2311                 public_symbuf.write((&s)[0 .. 1]);
2312                 break;
2313             }
2314             goto default;
2315         default:
2316             local_symbuf.write((&s)[0 .. 1]);
2317             break;
2318     }
2319     //printf("%p\n", *cast(void**)public_symbuf.buf);
2320     s.Sxtrnnum = 1;
2321 }
2322 
2323 /*******************************
2324  * Output an external symbol for name.
2325  * Input:
2326  *      name    Name to do EXTDEF on
2327  *              (Not to be mangled)
2328  * Returns:
2329  *      Symbol table index of the definition
2330  *      NOTE: Numbers will not be linear.
2331  */
2332 
2333 int Obj_external_def(const(char)* name)
2334 {
2335     //printf("Obj_external_def('%s')\n",name);
2336     assert(name);
2337     assert(extdef == 0);
2338     extdef = Obj_addstr(symtab_strings, name);
2339     return 0;
2340 }
2341 
2342 
2343 /*******************************
2344  * Output an external for existing symbol.
2345  * Input:
2346  *      s       Symbol to do EXTDEF on
2347  *              (Name is to be mangled)
2348  * Returns:
2349  *      Symbol table index of the definition
2350  *      NOTE: Numbers will not be linear.
2351  */
2352 
2353 int Obj_external(Symbol *s)
2354 {
2355     //printf("Obj_external('%s') %x\n",s.Sident.ptr,s.Svalue);
2356     symbol_debug(s);
2357     extern_symbuf.write((&s)[0 .. 1]);
2358     s.Sxtrnnum = 1;
2359     return 0;
2360 }
2361 
2362 /*******************************
2363  * Output a common block definition.
2364  * Input:
2365  *      p .    external identifier
2366  *      size    size in bytes of each elem
2367  *      count   number of elems
2368  * Returns:
2369  *      Symbol table index for symbol
2370  */
2371 
2372 int Obj_common_block(Symbol *s,targ_size_t size,targ_size_t count)
2373 {
2374     //printf("Obj_common_block('%s', size=%d, count=%d)\n",s.Sident.ptr,size,count);
2375     symbol_debug(s);
2376 
2377     // can't have code or thread local comdef's
2378     assert(!(s.ty() & (mTYcs | mTYthread)));
2379     // support for hidden comdefs not implemented
2380     assert(!(s.Sflags & SFLhidden));
2381 
2382     Comdef comdef = void;
2383     comdef.sym = s;
2384     comdef.size = size;
2385     comdef.count = cast(int)count;
2386     comdef_symbuf.write(&comdef, (comdef).sizeof);
2387     s.Sxtrnnum = 1;
2388     if (!s.Sseg)
2389         s.Sseg = UDATA;
2390     return 0;           // should return void
2391 }
2392 
2393 int Obj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count)
2394 {
2395     return Obj_common_block(s, size, count);
2396 }
2397 
2398 /***************************************
2399  * Append an iterated data block of 0s.
2400  * (uninitialized data only)
2401  */
2402 
2403 void Obj_write_zeros(seg_data *pseg, targ_size_t count)
2404 {
2405     Obj_lidata(pseg.SDseg, pseg.SDoffset, count);
2406 }
2407 
2408 /***************************************
2409  * Output an iterated data block of 0s.
2410  *
2411  *      For boundary alignment and initialization
2412  */
2413 
2414 void Obj_lidata(int seg,targ_size_t offset,targ_size_t count)
2415 {
2416     //printf("Obj_lidata(%d,%x,%d)\n",seg,offset,count);
2417     size_t idx = SegData[seg].SDshtidx;
2418     if ((I64 ? SecHdrTab64[idx].flags : SecHdrTab[idx].flags) == S_ZEROFILL)
2419     {   // Use SDoffset to record size of bss section
2420         SegData[seg].SDoffset += count;
2421     }
2422     else
2423     {
2424         Obj_bytes(seg, offset, cast(uint)count, null);
2425     }
2426 }
2427 
2428 /***********************************
2429  * Append byte to segment.
2430  */
2431 
2432 void Obj_write_byte(seg_data *pseg, uint byte_)
2433 {
2434     Obj_byte(pseg.SDseg, pseg.SDoffset, byte_);
2435 }
2436 
2437 /************************************
2438  * Output byte to object file.
2439  */
2440 
2441 void Obj_byte(int seg,targ_size_t offset,uint byte_)
2442 {
2443     Outbuffer *buf = SegData[seg].SDbuf;
2444     int save = cast(int)buf.length();
2445     //dbg_printf("Obj_byte(seg=%d, offset=x%lx, byte_=x%x)\n",seg,offset,byte_);
2446     buf.setsize(cast(uint)offset);
2447     buf.writeByte(byte_);
2448     if (save > offset+1)
2449         buf.setsize(save);
2450     else
2451         SegData[seg].SDoffset = offset+1;
2452     //dbg_printf("\tsize now %d\n",buf.length());
2453 }
2454 
2455 /***********************************
2456  * Append bytes to segment.
2457  */
2458 
2459 void Obj_write_bytes(seg_data *pseg, uint nbytes, void *p)
2460 {
2461     Obj_bytes(pseg.SDseg, pseg.SDoffset, nbytes, p);
2462 }
2463 
2464 /************************************
2465  * Output bytes to object file.
2466  * Returns:
2467  *      nbytes
2468  */
2469 
2470 uint Obj_bytes(int seg, targ_size_t offset, uint nbytes, void *p)
2471 {
2472 static if (0)
2473 {
2474     if (!(seg >= 0 && seg <= seg_count))
2475     {   printf("Obj_bytes: seg = %d, seg_count = %d\n", seg, seg_count);
2476         *cast(char*)0=0;
2477     }
2478 }
2479     assert(seg >= 0 && seg <= seg_count);
2480     Outbuffer *buf = SegData[seg].SDbuf;
2481     if (buf == null)
2482     {
2483         //dbg_printf("Obj_bytes(seg=%d, offset=x%llx, nbytes=%d, p=%p)\n", seg, offset, nbytes, p);
2484         //raise(SIGSEGV);
2485         assert(buf != null);
2486     }
2487     int save = cast(int)buf.length();
2488     //dbg_printf("Obj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n",
2489             //seg,offset,nbytes,p);
2490     buf.position(cast(size_t)offset, nbytes);
2491     if (p)
2492         buf.write(p, nbytes);
2493     else // Zero out the bytes
2494         buf.writezeros(nbytes);
2495 
2496     if (save > offset+nbytes)
2497         buf.setsize(save);
2498     else
2499         SegData[seg].SDoffset = offset+nbytes;
2500     return nbytes;
2501 }
2502 
2503 /*********************************************
2504  * Add a relocation entry for seg/offset.
2505  */
2506 
2507 void Obj_addrel(int seg, targ_size_t offset, Symbol *targsym,
2508         uint targseg, int rtype, int val = 0)
2509 {
2510     Relocation rel = void;
2511     rel.offset = offset;
2512     rel.targsym = targsym;
2513     rel.targseg = targseg;
2514     rel.rtype = cast(ubyte)rtype;
2515     rel.flag = 0;
2516     rel.funcsym = funcsym_p;
2517     rel.val = cast(short)val;
2518     seg_data *pseg = SegData[seg];
2519     if (!pseg.SDrel)
2520     {
2521         pseg.SDrel = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
2522         assert(pseg.SDrel);
2523     }
2524     pseg.SDrel.write(&rel, rel.sizeof);
2525 }
2526 
2527 /*******************************
2528  * Refer to address that is in the data segment.
2529  * Input:
2530  *      seg:offset =    the address being fixed up
2531  *      val =           displacement from start of target segment
2532  *      targetdatum =   target segment number (DATA, CDATA or UDATA, etc.)
2533  *      flags =         CFoff, CFseg
2534  * Example:
2535  *      int *abc = &def[3];
2536  *      to allocate storage:
2537  *              Obj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA);
2538  */
2539 
2540 void Obj_reftodatseg(int seg,targ_size_t offset,targ_size_t val,
2541         uint targetdatum,int flags)
2542 {
2543     Outbuffer *buf = SegData[seg].SDbuf;
2544     int save = cast(int)buf.length();
2545     buf.setsize(cast(uint)offset);
2546 static if (0)
2547 {
2548     printf("Obj_reftodatseg(seg:offset=%d:x%llx, val=x%llx, targetdatum %x, flags %x )\n",
2549         seg,offset,val,targetdatum,flags);
2550 }
2551     assert(seg != 0);
2552     if (SegData[seg].isCode() && SegData[targetdatum].isCode())
2553     {
2554         assert(0);
2555     }
2556     Obj_addrel(seg, offset, null, targetdatum, RELaddr);
2557     if (I64)
2558     {
2559         if (flags & CFoffset64)
2560         {
2561             buf.write64(val);
2562             if (save > offset + 8)
2563                 buf.setsize(save);
2564             return;
2565         }
2566     }
2567     buf.write32(cast(int)val);
2568     if (save > offset + 4)
2569         buf.setsize(save);
2570 }
2571 
2572 /*******************************
2573  * Refer to address that is in the current function code (funcsym_p).
2574  * Only offsets are output, regardless of the memory model.
2575  * Used to put values in switch address tables.
2576  * Input:
2577  *      seg =           where the address is going (CODE or DATA)
2578  *      offset =        offset within seg
2579  *      val =           displacement from start of this module
2580  */
2581 
2582 void Obj_reftocodeseg(int seg,targ_size_t offset,targ_size_t val)
2583 {
2584     //printf("Obj_reftocodeseg(seg=%d, offset=x%lx, val=x%lx )\n",seg,cast(uint)offset,cast(uint)val);
2585     assert(seg > 0);
2586     Outbuffer *buf = SegData[seg].SDbuf;
2587     int save = cast(int)buf.length();
2588     buf.setsize(cast(uint)offset);
2589     val -= funcsym_p.Soffset;
2590     Obj_addrel(seg, offset, funcsym_p, 0, RELaddr);
2591 //    if (I64)
2592 //        buf.write64(val);
2593 //    else
2594         buf.write32(cast(int)val);
2595     if (save > offset + 4)
2596         buf.setsize(save);
2597 }
2598 
2599 /*******************************
2600  * Refer to an identifier.
2601  * Input:
2602  *      seg =   where the address is going (CODE or DATA)
2603  *      offset =        offset within seg
2604  *      s .            Symbol table entry for identifier
2605  *      val =           displacement from identifier
2606  *      flags =         CFselfrel: self-relative
2607  *                      CFseg: get segment
2608  *                      CFoff: get offset
2609  *                      CFpc32: [RIP] addressing, val is 0, -1, -2 or -4
2610  *                      CFoffset64: 8 byte offset for 64 bit builds
2611  * Returns:
2612  *      number of bytes in reference (4 or 8)
2613  */
2614 
2615 int Obj_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val,
2616         int flags)
2617 {
2618     int retsize = (flags & CFoffset64) ? 8 : 4;
2619 static if (0)
2620 {
2621     printf("\nObj_reftoident('%s' seg %d, offset x%llx, val x%llx, flags x%x)\n",
2622         s.Sident.ptr,seg,cast(ulong)offset,cast(ulong)val,flags);
2623     printf("retsize = %d\n", retsize);
2624     //dbg_printf("Sseg = %d, Sxtrnnum = %d\n",s.Sseg,s.Sxtrnnum);
2625     symbol_print(s);
2626 }
2627     assert(seg > 0);
2628     if (s.Sclass != SClocstat && !s.Sxtrnnum)
2629     {   // It may get defined later as public or local, so defer
2630         size_t numbyteswritten = addtofixlist(s, offset, seg, val, flags);
2631         assert(numbyteswritten == retsize);
2632     }
2633     else
2634     {
2635         if (I64)
2636         {
2637             //if (s.Sclass != SCcomdat)
2638                 //val += s.Soffset;
2639             int v = 0;
2640             if (flags & CFpc32)
2641                 v = cast(int)val;
2642             if (flags & CFselfrel)
2643             {
2644                 Obj_addrel(seg, offset, s, 0, RELrel, v);
2645             }
2646             else
2647             {
2648                 Obj_addrel(seg, offset, s, 0, RELaddr, v);
2649             }
2650         }
2651         else
2652         {
2653             if (SegData[seg].isCode() && flags & CFselfrel)
2654             {
2655                 if (!jumpTableSeg)
2656                 {
2657                     jumpTableSeg =
2658                         Obj_getsegment("__jump_table", "__IMPORT",  0, S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE);
2659                 }
2660                 seg_data *pseg = SegData[jumpTableSeg];
2661                 if (I64)
2662                     SecHdrTab64[pseg.SDshtidx].reserved2 = 5;
2663                 else
2664                     SecHdrTab[pseg.SDshtidx].reserved2 = 5;
2665 
2666                 if (!indirectsymbuf1)
2667                 {
2668                     indirectsymbuf1 = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
2669                     assert(indirectsymbuf1);
2670                 }
2671                 else
2672                 {   // Look through indirectsym to see if it is already there
2673                     int n = cast(int)(indirectsymbuf1.length() / (Symbol *).sizeof);
2674                     Symbol **psym = cast(Symbol **)indirectsymbuf1.buf;
2675                     for (int i = 0; i < n; i++)
2676                     {   // Linear search, pretty pathetic
2677                         if (s == psym[i])
2678                         {   val = i * 5;
2679                             goto L1;
2680                         }
2681                     }
2682                 }
2683 
2684                 val = pseg.SDbuf.length();
2685                 static immutable char[5] halts = [ 0xF4,0xF4,0xF4,0xF4,0xF4 ];
2686                 pseg.SDbuf.write(halts.ptr, 5);
2687 
2688                 // Add symbol s to indirectsymbuf1
2689                 indirectsymbuf1.write((&s)[0 .. 1]);
2690              L1:
2691                 val -= offset + 4;
2692                 Obj_addrel(seg, offset, null, jumpTableSeg, RELrel);
2693             }
2694             else if (SegData[seg].isCode() &&
2695                      !(flags & CFindirect) &&
2696                     ((s.Sclass != SCextern && SegData[s.Sseg].isCode()) || s.Sclass == SClocstat || s.Sclass == SCstatic))
2697             {
2698                 val += s.Soffset;
2699                 Obj_addrel(seg, offset, null, s.Sseg, RELaddr);
2700             }
2701             else if ((flags & CFindirect) ||
2702                      SegData[seg].isCode() && !tyfunc(s.ty()))
2703             {
2704                 if (!pointersSeg)
2705                 {
2706                     pointersSeg =
2707                         Obj_getsegment("__pointers", "__IMPORT",  0, S_NON_LAZY_SYMBOL_POINTERS);
2708                 }
2709                 seg_data *pseg = SegData[pointersSeg];
2710 
2711                 if (!indirectsymbuf2)
2712                 {
2713                     indirectsymbuf2 = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
2714                     assert(indirectsymbuf2);
2715                 }
2716                 else
2717                 {   // Look through indirectsym to see if it is already there
2718                     int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof);
2719                     Symbol **psym = cast(Symbol **)indirectsymbuf2.buf;
2720                     for (int i = 0; i < n; i++)
2721                     {   // Linear search, pretty pathetic
2722                         if (s == psym[i])
2723                         {   val = i * 4;
2724                             goto L2;
2725                         }
2726                     }
2727                 }
2728 
2729                 val = pseg.SDbuf.length();
2730                 pseg.SDbuf.writezeros(_tysize[TYnptr]);
2731 
2732                 // Add symbol s to indirectsymbuf2
2733                 indirectsymbuf2.write((&s)[0 .. 1]);
2734 
2735              L2:
2736                 //printf("Obj_reftoident: seg = %d, offset = x%x, s = %s, val = x%x, pointersSeg = %d\n", seg, (int)offset, s.Sident.ptr, (int)val, pointersSeg);
2737                 if (flags & CFindirect)
2738                 {
2739                     Relocation rel = void;
2740                     rel.offset = offset;
2741                     rel.targsym = null;
2742                     rel.targseg = pointersSeg;
2743                     rel.rtype = RELaddr;
2744                     rel.flag = 0;
2745                     rel.funcsym = null;
2746                     rel.val = 0;
2747                     seg_data *pseg2 = SegData[seg];
2748                     if (!pseg2.SDrel)
2749                     {
2750                         pseg2.SDrel = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
2751                         assert(pseg2.SDrel);
2752                     }
2753                     pseg2.SDrel.write(&rel, rel.sizeof);
2754                 }
2755                 else
2756                     Obj_addrel(seg, offset, null, pointersSeg, RELaddr);
2757             }
2758             else
2759             {   //val -= s.Soffset;
2760                 Obj_addrel(seg, offset, s, 0, RELaddr);
2761             }
2762         }
2763 
2764         Outbuffer *buf = SegData[seg].SDbuf;
2765         int save = cast(int)buf.length();
2766         buf.position(cast(uint)offset, retsize);
2767         //printf("offset = x%llx, val = x%llx\n", offset, val);
2768         if (retsize == 8)
2769             buf.write64(val);
2770         else
2771             buf.write32(cast(int)val);
2772         if (save > offset + retsize)
2773             buf.setsize(save);
2774     }
2775     return retsize;
2776 }
2777 
2778 /*****************************************
2779  * Generate far16 thunk.
2780  * Input:
2781  *      s       Symbol to generate a thunk for
2782  */
2783 
2784 void Obj_far16thunk(Symbol *s)
2785 {
2786     //dbg_printf("Obj_far16thunk('%s')\n", s.Sident.ptr);
2787     assert(0);
2788 }
2789 
2790 /**************************************
2791  * Mark object file as using floating point.
2792  */
2793 
2794 void Obj_fltused()
2795 {
2796     //dbg_printf("Obj_fltused()\n");
2797 }
2798 
2799 /************************************
2800  * Close and delete .OBJ file.
2801  */
2802 
2803 void objfile_delete()
2804 {
2805     //remove(fobjname); // delete corrupt output file
2806 }
2807 
2808 /**********************************
2809  * Terminate.
2810  */
2811 
2812 void objfile_term()
2813 {
2814 static if(TERMCODE)
2815 {
2816     mem_free(fobjname);
2817     fobjname = null;
2818 }
2819 }
2820 
2821 /**********************************
2822   * Write to the object file
2823   */
2824 /+void objfile_write(FILE *fd, void *buffer, uint len)
2825 {
2826     fobjbuf.write(buffer, len);
2827 }+/
2828 
2829 int elf_align(targ_size_t size, int foffset)
2830 {
2831     if (size <= 1)
2832         return foffset;
2833     int offset = cast(int)((foffset + size - 1) & ~(size - 1));
2834     if (offset > foffset)
2835         fobjbuf.writezeros(offset - foffset);
2836     return offset;
2837 }
2838 
2839 /***************************************
2840  * Stuff pointer to ModuleInfo in its own segment.
2841  */
2842 
2843 version (MARS)
2844 {
2845 void Obj_moduleinfo(Symbol *scc)
2846 {
2847     int align_ = I64 ? 3 : 2; // align to _tysize[TYnptr]
2848 
2849     int seg = Obj_getsegment("__minfodata", "__DATA", align_, S_REGULAR);
2850     //printf("Obj_moduleinfo(%s) seg = %d:x%x\n", scc.Sident.ptr, seg, Offset(seg));
2851 
2852 static if (0)
2853 {
2854     type *t = type_fake(TYint);
2855     t.Tmangle = mTYman_c;
2856     char *p = cast(char *)malloc(5 + strlen(scc.Sident.ptr) + 1);
2857     strcpy(p, "SUPER");
2858     strcpy(p + 5, scc.Sident.ptr);
2859     Symbol *s_minfo_beg = symbol_name(p, SCglobal, t);
2860     Obj_pubdef(seg, s_minfo_beg, 0);
2861 }
2862 
2863     int flags = CFoff;
2864     if (I64)
2865         flags |= CFoffset64;
2866     SegData[seg].SDoffset += Obj_reftoident(seg, Offset(seg), scc, 0, flags);
2867 }
2868 }
2869 
2870 /*************************************
2871  */
2872 
2873 void Obj_gotref(Symbol *s)
2874 {
2875     //printf("Obj_gotref(%x '%s', %d)\n",s,s.Sident.ptr, s.Sclass);
2876     switch(s.Sclass)
2877     {
2878         case SCstatic:
2879         case SClocstat:
2880             s.Sfl = FLgotoff;
2881             break;
2882 
2883         case SCextern:
2884         case SCglobal:
2885         case SCcomdat:
2886         case SCcomdef:
2887             s.Sfl = FLgot;
2888             break;
2889 
2890         default:
2891             break;
2892     }
2893 }
2894 
2895 /**
2896  * Returns the symbol for the __tlv_bootstrap function.
2897  *
2898  * This function is used in the implementation of native thread local storage.
2899  * It's used as a placeholder in the TLV descriptors. The dynamic linker will
2900  * replace the placeholder with a real function at load time.
2901  */
2902 Symbol* Obj_tlv_bootstrap()
2903 {
2904     __gshared Symbol* tlv_bootstrap_sym;
2905     if (!tlv_bootstrap_sym)
2906         tlv_bootstrap_sym = symbol_name("__tlv_bootstrap", SCextern, type_fake(TYnfunc));
2907     return tlv_bootstrap_sym;
2908 }
2909 
2910 
2911 void Obj_write_pointerRef(Symbol* s, uint off)
2912 {
2913 }
2914 
2915 /******************************************
2916  * Generate fixup specific to .eh_frame and .gcc_except_table sections.
2917  * Params:
2918  *      seg = segment of where to write fixup
2919  *      offset = offset of where to write fixup
2920  *      s = fixup is a reference to this Symbol
2921  *      val = displacement from s
2922  * Returns:
2923  *      number of bytes written at seg:offset
2924  */
2925 int dwarf_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val)
2926 {
2927     //printf("dwarf_reftoident(seg=%d offset=x%x s=%s val=x%x\n", seg, (int)offset, s.Sident.ptr, (int)val);
2928     Obj_reftoident(seg, offset, s, val + 4, I64 ? CFoff : CFindirect);
2929     return 4;
2930 }
2931 
2932 /*****************************************
2933  * Generate LSDA and PC_Begin fixups in the __eh_frame segment encoded as DW_EH_PE_pcrel|ptr.
2934  * 64 bits
2935  *   LSDA
2936  *      [0] address x0071 symbolnum 6 pcrel 0 length 3 extern 1 type 5 RELOC_SUBTRACTOR __Z3foov.eh
2937  *      [1] address x0071 symbolnum 1 pcrel 0 length 3 extern 1 type 0 RELOC_UNSIGNED   GCC_except_table2
2938  *   PC_Begin:
2939  *      [2] address x0060 symbolnum 6 pcrel 0 length 3 extern 1 type 5 RELOC_SUBTRACTOR __Z3foov.eh
2940  *      [3] address x0060 symbolnum 5 pcrel 0 length 3 extern 1 type 0 RELOC_UNSIGNED   __Z3foov
2941  *      Want the result to be  &s - pc
2942  *      The fixup yields       &s - &fdesym + value
2943  *      Therefore              value = &fdesym - pc
2944  *      which is the same as   fdesym.Soffset - offset
2945  * 32 bits
2946  *   LSDA
2947  *      [6] address x0028 pcrel 0 length 2 value x0 type 4 RELOC_LOCAL_SECTDIFF
2948  *      [7] address x0000 pcrel 0 length 2 value x1dc type 1 RELOC_PAIR
2949  *   PC_Begin
2950  *      [8] address x0013 pcrel 0 length 2 value x228 type 4 RELOC_LOCAL_SECTDIFF
2951  *      [9] address x0000 pcrel 0 length 2 value x1c7 type 1 RELOC_PAIR
2952  * Params:
2953  *      dfseg = segment of where to write fixup (eh_frame segment)
2954  *      offset = offset of where to write fixup (eh_frame offset)
2955  *      s = fixup is a reference to this Symbol (GCC_except_table%d or function_name)
2956  *      val = displacement from s
2957  *      fdesym = function_name.eh
2958  * Returns:
2959  *      number of bytes written at seg:offset
2960  */
2961 int dwarf_eh_frame_fixup(int dfseg, targ_size_t offset, Symbol *s, targ_size_t val, Symbol *fdesym)
2962 {
2963     Outbuffer *buf = SegData[dfseg].SDbuf;
2964     assert(offset == buf.length());
2965     assert(fdesym.Sseg == dfseg);
2966     if (I64)
2967         buf.write64(val);  // add in 'value' later
2968     else
2969         buf.write32(cast(int)val);
2970 
2971     Relocation rel;
2972     rel.offset = offset;
2973     rel.targsym = s;
2974     rel.targseg = 0;
2975     rel.rtype = RELaddr;
2976     rel.flag = 1;
2977     rel.funcsym = fdesym;
2978     rel.val = 0;
2979     seg_data *pseg = SegData[dfseg];
2980     if (!pseg.SDrel)
2981     {
2982         pseg.SDrel = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
2983         assert(pseg.SDrel);
2984     }
2985     pseg.SDrel.write(&rel, rel.sizeof);
2986 
2987     return I64 ? 8 : 4;
2988 }
2989 
2990 }
2991 }