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.barray;
28 import dmd.backend.cc;
29 import dmd.backend.cdef;
30 import dmd.backend.code;
31 import dmd.backend.code_x86;
32 import dmd.backend.mem;
33 import dmd.backend.aarray;
34 import dmd.backend.dlist;
35 import dmd.backend.el;
36 import dmd.backend.global;
37 import dmd.backend.obj;
38 import dmd.backend.oper;
39 import dmd.backend.outbuf;
40 import dmd.backend.ty;
41 import dmd.backend.type;
42 
43 extern (C++):
44 
45 nothrow:
46 
47 alias _compare_fp_t = extern(C) nothrow int function(const void*, const void*);
48 extern(C) void qsort(void* base, size_t nmemb, size_t size, _compare_fp_t compar);
49 
50 static if (MACHOBJ)
51 {
52 
53 import dmd.backend.dwarf;
54 import dmd.backend.mach;
55 
56 alias nlist = dmd.backend.mach.nlist;   // avoid conflict with dmd.backend.dlist.nlist
57 
58 /****************************************
59  * Sort the relocation entry buffer.
60  * put before nothrow because qsort was not marked nothrow until version 2.086
61  */
62 
63 extern (C) {
64 private int rel_fp(scope const(void*) e1, scope const(void*) e2)
65 {   Relocation *r1 = cast(Relocation *)e1;
66     Relocation *r2 = cast(Relocation *)e2;
67 
68     return cast(int)(r1.offset - r2.offset);
69 }
70 }
71 
72 void mach_relsort(Outbuffer *buf)
73 {
74     qsort(buf.buf, buf.length() / Relocation.sizeof, Relocation.sizeof, &rel_fp);
75 }
76 
77 // for x86_64
78 enum
79 {
80     X86_64_RELOC_UNSIGNED         = 0,
81     X86_64_RELOC_SIGNED           = 1,
82     X86_64_RELOC_BRANCH           = 2,
83     X86_64_RELOC_GOT_LOAD         = 3,
84     X86_64_RELOC_GOT              = 4,
85     X86_64_RELOC_SUBTRACTOR       = 5,
86     X86_64_RELOC_SIGNED_1         = 6,
87     X86_64_RELOC_SIGNED_2         = 7,
88     X86_64_RELOC_SIGNED_4         = 8,
89     X86_64_RELOC_TLV              = 9, // for thread local variables
90 }
91 
92 private __gshared Outbuffer *fobjbuf;
93 
94 enum DEST_LEN = (IDMAX + IDOHD + 1);
95 char *obj_mangle2(Symbol *s,char *dest);
96 
97 extern __gshared int except_table_seg;        // segment of __gcc_except_tab
98 extern __gshared int eh_frame_seg;            // segment of __eh_frame
99 
100 
101 /******************************************
102  */
103 
104 /// Returns: a reference to the global offset table
105 Symbol* Obj_getGOTsym()
106 {
107     __gshared Symbol *GOTsym;
108     if (!GOTsym)
109     {
110         GOTsym = symbol_name("_GLOBAL_OFFSET_TABLE_",SCglobal,tspvoid);
111     }
112     return GOTsym;
113 }
114 
115 void Obj_refGOTsym()
116 {
117     assert(0);
118 }
119 
120 // The object file is built is several separate pieces
121 
122 
123 // String Table  - String table for all other names
124 private __gshared Outbuffer *symtab_strings;
125 
126 // Section Headers
127 __gshared Outbuffer  *SECbuf;             // Buffer to build section table in
128 section* SecHdrTab() { return cast(section *)SECbuf.buf; }
129 section_64* SecHdrTab64() { return cast(section_64 *)SECbuf.buf; }
130 
131 __gshared
132 {
133 
134 // The relocation for text and data seems to get lost.
135 // Try matching the order gcc output them
136 // This means defining the sections and then removing them if they are
137 // not used.
138 private int section_cnt;         // Number of sections in table
139 enum SEC_TAB_INIT = 16;          // Initial number of sections in buffer
140 enum SEC_TAB_INC  = 4;           // Number of sections to increment buffer by
141 
142 enum SYM_TAB_INIT = 100;         // Initial number of symbol entries in buffer
143 enum SYM_TAB_INC  = 50;          // Number of symbols to increment buffer by
144 
145 /* Three symbol tables, because the different types of symbols
146  * are grouped into 3 different types (and a 4th for comdef's).
147  */
148 
149 private Outbuffer *local_symbuf;
150 private Outbuffer *public_symbuf;
151 private Outbuffer *extern_symbuf;
152 }
153 
154 private void reset_symbols(Outbuffer *buf)
155 {
156     Symbol **p = cast(Symbol **)buf.buf;
157     const size_t n = buf.length() / (Symbol *).sizeof;
158     for (size_t i = 0; i < n; ++i)
159         symbol_reset(p[i]);
160 }
161 
162 __gshared
163 {
164 
165 struct Comdef { Symbol *sym; targ_size_t size; int count; }
166 private Outbuffer *comdef_symbuf;        // Comdef's are stored here
167 
168 private Outbuffer *indirectsymbuf1;      // indirect symbol table of Symbol*'s
169 private int jumpTableSeg;                // segment index for __jump_table
170 
171 private Outbuffer *indirectsymbuf2;      // indirect symbol table of Symbol*'s
172 private int pointersSeg;                 // segment index for __pointers
173 
174 /* If an Obj_external_def() happens, set this to the string index,
175  * to be added last to the symbol table.
176  * Obviously, there can be only one.
177  */
178 private IDXSTR extdef;
179 }
180 
181 static if (0)
182 {
183 enum
184 {
185     STI_FILE  = 1,            // Where file symbol table entry is
186     STI_TEXT  = 2,
187     STI_DATA  = 3,
188     STI_BSS   = 4,
189     STI_GCC   = 5,            // Where "gcc2_compiled" symbol is */
190     STI_RODAT = 6,            // Symbol for readonly data
191     STI_COM   = 8,
192 }
193 }
194 
195 // Each compiler segment is a section
196 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes
197 //      into SegData[]
198 //      New compiler segments are added to end.
199 
200 /******************************
201  * Returns !=0 if this segment is a code segment.
202  */
203 
204 int seg_data_isCode(const ref seg_data sd)
205 {
206     // The codegen assumes that code.data references are indirect,
207     // but when CDATA is treated as code reftoident will emit a direct
208     // relocation.
209     if (&sd == SegData[CDATA])
210         return false;
211 
212     if (I64)
213     {
214         //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab64[sd.SDshtidx].flags);
215         return strcmp(SecHdrTab64[sd.SDshtidx].segname.ptr, "__TEXT") == 0;
216     }
217     else
218     {
219         //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab[sd.SDshtidx].flags);
220         return strcmp(SecHdrTab[sd.SDshtidx].segname.ptr, "__TEXT") == 0;
221     }
222 }
223 
224 
225 __gshared
226 {
227 Rarray!(seg_data*) SegData;
228 
229 /**
230  * Section index for the __thread_vars/__tls_data section.
231  *
232  * This section is used for the variable symbol for TLS variables.
233  */
234 int seg_tlsseg = UNKNOWN;
235 
236 /**
237  * Section index for the __thread_bss section.
238  *
239  * This section is used for the data symbol ($tlv$init) for TLS variables
240  * without an initializer.
241  */
242 int seg_tlsseg_bss = UNKNOWN;
243 
244 /**
245  * Section index for the __thread_data section.
246  *
247  * This section is used for the data symbol ($tlv$init) for TLS variables
248  * with an initializer.
249  */
250 int seg_tlsseg_data = UNKNOWN;
251 
252 int seg_cstring = UNKNOWN;        // __cstring section
253 int seg_mod_init_func = UNKNOWN;  // __mod_init_func section
254 int seg_mod_term_func = UNKNOWN;  // __mod_term_func section
255 int seg_deh_eh = UNKNOWN;         // __deh_eh section
256 int seg_textcoal_nt = UNKNOWN;
257 int seg_tlscoal_nt = UNKNOWN;
258 int seg_datacoal_nt = UNKNOWN;
259 }
260 
261 /*******************************************************
262  * Because the Mach-O relocations cannot be computed until after
263  * all the segments are written out, and we need more information
264  * than the Mach-O relocations provide, make our own relocation
265  * type. Later, translate to Mach-O relocation structure.
266  */
267 
268 enum
269 {
270     RELaddr = 0,      // straight address
271     RELrel  = 1,      // relative to location to be fixed up
272 }
273 
274 struct Relocation
275 {   // Relocations are attached to the struct seg_data they refer to
276     targ_size_t offset; // location in segment to be fixed up
277     Symbol *funcsym;    // function in which offset lies, if any
278     Symbol *targsym;    // if !=null, then location is to be fixed up
279                         // to address of this symbol
280     uint targseg;       // if !=0, then location is to be fixed up
281                         // to address of start of this segment
282     ubyte rtype;        // RELxxxx
283     ubyte flag;         // 1: emit SUBTRACTOR/UNSIGNED pair
284     short val;          // 0, -1, -2, -4
285 }
286 
287 
288 /*******************************
289  * Output a string into a string table
290  * Input:
291  *      strtab  =       string table for entry
292  *      str     =       string to add
293  *
294  * Returns index into the specified string table.
295  */
296 
297 IDXSTR Obj_addstr(Outbuffer *strtab, const(char)* str)
298 {
299     //printf("Obj_addstr(strtab = %p str = '%s')\n",strtab,str);
300     IDXSTR idx = cast(IDXSTR)strtab.length();        // remember starting offset
301     strtab.writeString(str);
302     //printf("\tidx %d, new size %d\n",idx,strtab.length());
303     return idx;
304 }
305 
306 /*******************************
307  * Output a mangled string into the symbol string table
308  * Input:
309  *      str     =       string to add
310  *
311  * Returns index into the table.
312  */
313 
314 private IDXSTR elf_addmangled(Symbol *s)
315 {
316     //printf("elf_addmangled(%s)\n", s.Sident);
317     char[DEST_LEN] dest = void;
318     char *destr;
319     const(char)* name;
320     IDXSTR namidx;
321 
322     namidx = cast(IDXSTR)symtab_strings.length();
323     destr = obj_mangle2(s, dest.ptr);
324     name = destr;
325     if (CPP && name[0] == '_' && name[1] == '_')
326     {
327         if (strncmp(name,"__ct__",6) == 0)
328             name += 4;
329 static if (0)
330 {
331         switch(name[2])
332         {
333             case 'c':
334                 if (strncmp(name,"__ct__",6) == 0)
335                     name += 4;
336                 break;
337             case 'd':
338                 if (strcmp(name,"__dl__FvP") == 0)
339                     name = "__builtin_delete";
340                 break;
341             case 'v':
342                 //if (strcmp(name,"__vec_delete__FvPiUIPi") == 0)
343                     //name = "__builtin_vec_del";
344                 //else
345                 //if (strcmp(name,"__vn__FPUI") == 0)
346                     //name = "__builtin_vec_new";
347                 break;
348             case 'n':
349                 if (strcmp(name,"__nw__FPUI") == 0)
350                     name = "__builtin_new";
351                 break;
352 
353             default:
354                 break;
355         }
356 }
357     }
358     else if (tyfunc(s.ty()) && s.Sfunc && s.Sfunc.Fredirect)
359         name = s.Sfunc.Fredirect;
360     symtab_strings.writeString(name);
361     if (destr != dest.ptr)                  // if we resized result
362         mem_free(destr);
363     //dbg_printf("\telf_addmagled symtab_strings %s namidx %d len %d size %d\n",name, namidx,len,symtab_strings.length());
364     return namidx;
365 }
366 
367 /**************************
368  * Ouput read only data and generate a symbol for it.
369  *
370  */
371 
372 Symbol * Obj_sym_cdata(tym_t ty,char *p,int len)
373 {
374     Symbol *s;
375 
376 static if (0)
377 {
378     if (I64)
379     {
380         alignOffset(DATA, tysize(ty));
381         s = symboldata(Offset(DATA), ty);
382         SegData[DATA].SDbuf.write(p,len);
383         s.Sseg = DATA;
384         s.Soffset = Offset(DATA);   // Remember its offset into DATA section
385         Offset(DATA) += len;
386 
387         s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
388         return s;
389     }
390 }
391     //printf("Obj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA));
392     alignOffset(CDATA, tysize(ty));
393     s = symboldata(Offset(CDATA), ty);
394     s.Sseg = CDATA;
395     //Obj_pubdef(CDATA, s, Offset(CDATA));
396     Obj_bytes(CDATA, Offset(CDATA), len, p);
397 
398     s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
399     return s;
400 }
401 
402 /**************************
403  * Ouput read only data for data
404  *
405  */
406 
407 int Obj_data_readonly(char *p, int len, int *pseg)
408 {
409     int oldoff = cast(int)Offset(CDATA);
410     SegData[CDATA].SDbuf.reserve(len);
411     SegData[CDATA].SDbuf.writen(p,len);
412     Offset(CDATA) += len;
413     *pseg = CDATA;
414     return oldoff;
415 }
416 
417 int Obj_data_readonly(char *p, int len)
418 {
419     int pseg;
420 
421     return Obj_data_readonly(p, len, &pseg);
422 }
423 
424 /*****************************
425  * Get segment for readonly string literals.
426  * The linker will pool strings in this section.
427  * Params:
428  *    sz = number of bytes per character (1, 2, or 4)
429  * Returns:
430  *    segment index
431  */
432 int Obj_string_literal_segment(uint sz)
433 {
434     if (sz == 1)
435         return getsegment2(seg_cstring, "__cstring", "__TEXT", 0, S_CSTRING_LITERALS);
436 
437     return CDATA;  // no special handling for other wstring, dstring; use __const
438 }
439 
440 /******************************
441  * Perform initialization that applies to all .o output files.
442  *      Called before any other obj_xxx routines
443  */
444 
445 Obj Obj_init(Outbuffer *objbuf, const(char)* filename, const(char)* csegname)
446 {
447     //printf("Obj_init()\n");
448     Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj));
449 
450     cseg = CODE;
451     fobjbuf = objbuf;
452 
453     seg_tlsseg = UNKNOWN;
454     seg_tlsseg_bss = UNKNOWN;
455     seg_tlsseg_data = UNKNOWN;
456     seg_cstring = UNKNOWN;
457     seg_mod_init_func = UNKNOWN;
458     seg_mod_term_func = UNKNOWN;
459     seg_deh_eh = UNKNOWN;
460     seg_textcoal_nt = UNKNOWN;
461     seg_tlscoal_nt = UNKNOWN;
462     seg_datacoal_nt = UNKNOWN;
463 
464     // Initialize buffers
465 
466     if (symtab_strings)
467         symtab_strings.setsize(1);
468     else
469     {
470         symtab_strings = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
471         assert(symtab_strings);
472         symtab_strings.reserve(2048);
473         symtab_strings.writeByte(0);
474     }
475 
476     if (!local_symbuf)
477     {
478         local_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
479         assert(local_symbuf);
480         local_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
481     }
482     local_symbuf.reset();
483 
484     if (public_symbuf)
485     {
486         reset_symbols(public_symbuf);
487         public_symbuf.reset();
488     }
489     else
490     {
491         public_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
492         assert(public_symbuf);
493         public_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
494     }
495 
496     if (extern_symbuf)
497     {
498         reset_symbols(extern_symbuf);
499         extern_symbuf.reset();
500     }
501     else
502     {
503         extern_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
504         assert(extern_symbuf);
505         extern_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
506     }
507 
508     if (!comdef_symbuf)
509     {
510         comdef_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
511         assert(comdef_symbuf);
512         comdef_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
513     }
514     comdef_symbuf.reset();
515 
516     extdef = 0;
517 
518     if (indirectsymbuf1)
519         indirectsymbuf1.reset();
520     jumpTableSeg = 0;
521 
522     if (indirectsymbuf2)
523         indirectsymbuf2.reset();
524     pointersSeg = 0;
525 
526     // Initialize segments for CODE, DATA, UDATA and CDATA
527     size_t struct_section_size = I64 ? section_64.sizeof : section.sizeof;
528     if (SECbuf)
529     {
530         SECbuf.setsize(cast(uint)struct_section_size);
531     }
532     else
533     {
534         SECbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
535         assert(SECbuf);
536         SECbuf.reserve(cast(uint)(SEC_TAB_INIT * struct_section_size));
537         // Ignore the first section - section numbers start at 1
538         SECbuf.writezeros(cast(uint)struct_section_size);
539     }
540     section_cnt = 1;
541 
542     SegData.reset();   // recycle memory
543     SegData.push();    // element 0 is reserved
544 
545     int align_ = I64 ? 4 : 2;            // align to 16 bytes for floating point
546     Obj_getsegment("__text",  "__TEXT", 2, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS);
547     Obj_getsegment("__data",  "__DATA", align_, S_REGULAR);     // DATA
548     Obj_getsegment("__const", "__TEXT", 2, S_REGULAR);         // CDATA
549     Obj_getsegment("__bss",   "__DATA", 4, S_ZEROFILL);        // UDATA
550     Obj_getsegment("__const", "__DATA", align_, S_REGULAR);     // CDATAREL
551 
552     dwarf_initfile(filename);
553     return obj;
554 }
555 
556 /**************************
557  * Initialize the start of object output for this particular .o file.
558  *
559  * Input:
560  *      filename:       Name of source file
561  *      csegname:       User specified default code segment name
562  */
563 
564 void Obj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname)
565 {
566     //dbg_printf("Obj_initfile(filename = %s, modname = %s)\n",filename,modname);
567 version (SCPP)
568 {
569     if (csegname && *csegname && strcmp(csegname,".text"))
570     {   // Define new section and make it the default for cseg segment
571         // NOTE: cseg is initialized to CODE
572         IDXSEC newsecidx;
573         Elf32_Shdr *newtextsec;
574         IDXSYM newsymidx;
575         assert(!I64);      // fix later
576         SegData[cseg].SDshtidx = newsecidx =
577             elf_newsection(csegname,0,SHT_PROGDEF,SHF_ALLOC|SHF_EXECINSTR);
578         newtextsec = &SecHdrTab[newsecidx];
579         newtextsec.sh_addralign = 4;
580         SegData[cseg].SDsymidx =
581             elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, newsecidx);
582     }
583 }
584     if (config.fulltypes)
585         dwarf_initmodule(filename, modname);
586 }
587 
588 /************************************
589  * Patch pseg/offset by adding in the vmaddr difference from
590  * pseg/offset to start of seg.
591  */
592 
593 int32_t *patchAddr(int seg, targ_size_t offset)
594 {
595     return cast(int32_t *)(fobjbuf.buf + SecHdrTab[SegData[seg].SDshtidx].offset + offset);
596 }
597 
598 int32_t *patchAddr64(int seg, targ_size_t offset)
599 {
600     return cast(int32_t *)(fobjbuf.buf + SecHdrTab64[SegData[seg].SDshtidx].offset + offset);
601 }
602 
603 void patch(seg_data *pseg, targ_size_t offset, int seg, targ_size_t value)
604 {
605     //printf("patch(offset = x%04x, seg = %d, value = x%llx)\n", (uint)offset, seg, value);
606     if (I64)
607     {
608         int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab64[pseg.SDshtidx].offset + offset);
609 static if (0)
610 {
611         printf("\taddr1 = x%llx\n\taddr2 = x%llx\n\t*p = x%llx\n\tdelta = x%llx\n",
612             SecHdrTab64[pseg.SDshtidx].addr,
613             SecHdrTab64[SegData[seg].SDshtidx].addr,
614             *p,
615             SecHdrTab64[SegData[seg].SDshtidx].addr -
616             (SecHdrTab64[pseg.SDshtidx].addr + offset));
617 }
618         *p += SecHdrTab64[SegData[seg].SDshtidx].addr -
619               (SecHdrTab64[pseg.SDshtidx].addr - value);
620     }
621     else
622     {
623         int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab[pseg.SDshtidx].offset + offset);
624 static if (0)
625 {
626         printf("\taddr1 = x%x\n\taddr2 = x%x\n\t*p = x%x\n\tdelta = x%x\n",
627             SecHdrTab[pseg.SDshtidx].addr,
628             SecHdrTab[SegData[seg].SDshtidx].addr,
629             *p,
630             SecHdrTab[SegData[seg].SDshtidx].addr -
631             (SecHdrTab[pseg.SDshtidx].addr + offset));
632 }
633         *p += SecHdrTab[SegData[seg].SDshtidx].addr -
634               (SecHdrTab[pseg.SDshtidx].addr - value);
635     }
636 }
637 
638 /***************************
639  * Number symbols so they are
640  * ordered as locals, public and then extern/comdef
641  */
642 
643 void mach_numbersyms()
644 {
645     //printf("mach_numbersyms()\n");
646     int n = 0;
647 
648     int dim;
649     dim = cast(int)(local_symbuf.length() / (Symbol *).sizeof);
650     for (int i = 0; i < dim; i++)
651     {   Symbol *s = (cast(Symbol **)local_symbuf.buf)[i];
652         s.Sxtrnnum = n;
653         n++;
654     }
655 
656     dim = cast(int)(public_symbuf.length() / (Symbol *).sizeof);
657     for (int i = 0; i < dim; i++)
658     {   Symbol *s = (cast(Symbol **)public_symbuf.buf)[i];
659         s.Sxtrnnum = n;
660         n++;
661     }
662 
663     dim = cast(int)(extern_symbuf.length() / (Symbol *).sizeof);
664     for (int i = 0; i < dim; i++)
665     {   Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i];
666         s.Sxtrnnum = n;
667         n++;
668     }
669 
670     dim = cast(int)(comdef_symbuf.length() / Comdef.sizeof);
671     for (int i = 0; i < dim; i++)
672     {   Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i;
673         c.sym.Sxtrnnum = n;
674         n++;
675     }
676 }
677 
678 
679 /***************************
680  * Fixup and terminate object file.
681  */
682 
683 void Obj_termfile()
684 {
685     //dbg_printf("Obj_termfile\n");
686     if (configv.addlinenumbers)
687     {
688         dwarf_termmodule();
689     }
690 }
691 
692 /*********************************
693  * Terminate package.
694  */
695 
696 void Obj_term(const(char)* objfilename)
697 {
698     //printf("Obj_term()\n");
699 version (SCPP)
700 {
701     if (!errcnt)
702     {
703         outfixlist();           // backpatches
704     }
705 }
706 else
707 {
708     outfixlist();           // backpatches
709 }
710 
711     if (configv.addlinenumbers)
712     {
713         dwarf_termfile();
714     }
715 
716 version (SCPP)
717 {
718     if (errcnt)
719         return;
720 }
721 
722     /* Write out the object file in the following order:
723      *  header
724      *  commands
725      *          segment_command
726      *                  { sections }
727      *          symtab_command
728      *          dysymtab_command
729      *  { segment contents }
730      *  { relocations }
731      *  symbol table
732      *  string table
733      *  indirect symbol table
734      */
735 
736     uint foffset;
737     uint headersize;
738     uint sizeofcmds;
739 
740     // Write out the bytes for the header
741     if (I64)
742     {
743         mach_header_64 header = void;
744 
745         header.magic = MH_MAGIC_64;
746         header.cputype = CPU_TYPE_X86_64;
747         header.cpusubtype = CPU_SUBTYPE_I386_ALL;
748         header.filetype = MH_OBJECT;
749         header.ncmds = 3;
750         header.sizeofcmds = cast(uint)(segment_command_64.sizeof +
751                                 (section_cnt - 1) * section_64.sizeof +
752                             symtab_command.sizeof +
753                             dysymtab_command.sizeof);
754         header.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
755         header.reserved = 0;
756         fobjbuf.write(&header, header.sizeof);
757         foffset = header.sizeof;       // start after header
758         headersize = header.sizeof;
759         sizeofcmds = header.sizeofcmds;
760 
761         // Write the actual data later
762         fobjbuf.writezeros(header.sizeofcmds);
763         foffset += header.sizeofcmds;
764     }
765     else
766     {
767         mach_header header = void;
768 
769         header.magic = MH_MAGIC;
770         header.cputype = CPU_TYPE_I386;
771         header.cpusubtype = CPU_SUBTYPE_I386_ALL;
772         header.filetype = MH_OBJECT;
773         header.ncmds = 3;
774         header.sizeofcmds = cast(uint)(segment_command.sizeof +
775                                 (section_cnt - 1) * section.sizeof +
776                             symtab_command.sizeof +
777                             dysymtab_command.sizeof);
778         header.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
779         fobjbuf.write(&header, header.sizeof);
780         foffset = header.sizeof;       // start after header
781         headersize = header.sizeof;
782         sizeofcmds = header.sizeofcmds;
783 
784         // Write the actual data later
785         fobjbuf.writezeros(header.sizeofcmds);
786         foffset += header.sizeofcmds;
787     }
788 
789     segment_command segment_cmd = void;
790     segment_command_64 segment_cmd64 = void;
791     symtab_command symtab_cmd = void;
792     dysymtab_command dysymtab_cmd = void;
793 
794     memset(&segment_cmd, 0, segment_cmd.sizeof);
795     memset(&segment_cmd64, 0, segment_cmd64.sizeof);
796     memset(&symtab_cmd, 0, symtab_cmd.sizeof);
797     memset(&dysymtab_cmd, 0, dysymtab_cmd.sizeof);
798 
799     if (I64)
800     {
801         segment_cmd64.cmd = LC_SEGMENT_64;
802         segment_cmd64.cmdsize = cast(uint)(segment_cmd64.sizeof +
803                                     (section_cnt - 1) * section_64.sizeof);
804         segment_cmd64.nsects = section_cnt - 1;
805         segment_cmd64.maxprot = 7;
806         segment_cmd64.initprot = 7;
807     }
808     else
809     {
810         segment_cmd.cmd = LC_SEGMENT;
811         segment_cmd.cmdsize = cast(uint)(segment_cmd.sizeof +
812                                     (section_cnt - 1) * section.sizeof);
813         segment_cmd.nsects = section_cnt - 1;
814         segment_cmd.maxprot = 7;
815         segment_cmd.initprot = 7;
816     }
817 
818     symtab_cmd.cmd = LC_SYMTAB;
819     symtab_cmd.cmdsize = symtab_cmd.sizeof;
820 
821     dysymtab_cmd.cmd = LC_DYSYMTAB;
822     dysymtab_cmd.cmdsize = dysymtab_cmd.sizeof;
823 
824     /* If a __pointers section was emitted, need to set the .reserved1
825      * field to the symbol index in the indirect symbol table of the
826      * start of the __pointers symbols.
827      */
828     if (pointersSeg)
829     {
830         seg_data *pseg = SegData[pointersSeg];
831         if (I64)
832         {
833             section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section
834             psechdr.reserved1 = cast(uint)(indirectsymbuf1
835                 ? indirectsymbuf1.length() / (Symbol *).sizeof
836                 : 0);
837         }
838         else
839         {
840             section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section
841             psechdr.reserved1 = cast(uint)(indirectsymbuf1
842                 ? indirectsymbuf1.length() / (Symbol *).sizeof
843                 : 0);
844         }
845     }
846 
847     // Walk through sections determining size and file offsets
848 
849     //
850     // First output individual section data associate with program
851     //  code and data
852     //
853     foffset = elf_align(I64 ? 8 : 4, foffset);
854     if (I64)
855         segment_cmd64.fileoff = foffset;
856     else
857         segment_cmd.fileoff = foffset;
858     uint vmaddr = 0;
859 
860     //printf("Setup offsets and sizes foffset %d\n\tsection_cnt %d, SegData.length %d\n",foffset,section_cnt,SegData.length);
861     // Zero filled segments go at the end, so go through segments twice
862     for (int i = 0; i < 2; i++)
863     {
864         for (int seg = 1; seg < SegData.length; seg++)
865         {
866             seg_data *pseg = SegData[seg];
867             if (I64)
868             {
869                 section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section
870 
871                 // Do zero-fill the second time through this loop
872                 if (i ^ (psechdr.flags == S_ZEROFILL))
873                     continue;
874 
875                 int align_ = 1 << psechdr._align;
876                 while (psechdr._align > 0 && align_ < pseg.SDalignment)
877                 {
878                     psechdr._align += 1;
879                     align_ <<= 1;
880                 }
881                 foffset = elf_align(align_, foffset);
882                 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
883                 if (psechdr.flags == S_ZEROFILL)
884                 {
885                     psechdr.offset = 0;
886                     psechdr.size = pseg.SDoffset; // accumulated size
887                 }
888                 else
889                 {
890                     psechdr.offset = foffset;
891                     psechdr.size = 0;
892                     //printf("\tsection name %s,", psechdr.sectname);
893                     if (pseg.SDbuf && pseg.SDbuf.length())
894                     {
895                         //printf("\tsize %d\n", pseg.SDbuf.length());
896                         psechdr.size = pseg.SDbuf.length();
897                         fobjbuf.write(pseg.SDbuf.buf, cast(uint)psechdr.size);
898                         foffset += psechdr.size;
899                     }
900                 }
901                 psechdr.addr = vmaddr;
902                 vmaddr += psechdr.size;
903                 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size);
904             }
905             else
906             {
907                 section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section
908 
909                 // Do zero-fill the second time through this loop
910                 if (i ^ (psechdr.flags == S_ZEROFILL))
911                     continue;
912 
913                 int align_ = 1 << psechdr._align;
914                 while (psechdr._align > 0 && align_ < pseg.SDalignment)
915                 {
916                     psechdr._align += 1;
917                     align_ <<= 1;
918                 }
919                 foffset = elf_align(align_, foffset);
920                 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
921                 if (psechdr.flags == S_ZEROFILL)
922                 {
923                     psechdr.offset = 0;
924                     psechdr.size = cast(uint)pseg.SDoffset; // accumulated size
925                 }
926                 else
927                 {
928                     psechdr.offset = foffset;
929                     psechdr.size = 0;
930                     //printf("\tsection name %s,", psechdr.sectname);
931                     if (pseg.SDbuf && pseg.SDbuf.length())
932                     {
933                         //printf("\tsize %d\n", pseg.SDbuf.length());
934                         psechdr.size = cast(uint)pseg.SDbuf.length();
935                         fobjbuf.write(pseg.SDbuf.buf, psechdr.size);
936                         foffset += psechdr.size;
937                     }
938                 }
939                 psechdr.addr = vmaddr;
940                 vmaddr += psechdr.size;
941                 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size);
942             }
943         }
944     }
945 
946     if (I64)
947     {
948         segment_cmd64.vmsize = vmaddr;
949         segment_cmd64.filesize = foffset - segment_cmd64.fileoff;
950         /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an
951          * error, and is happening sometimes.
952          */
953         if (segment_cmd64.filesize > vmaddr)
954             segment_cmd64.vmsize = segment_cmd64.filesize;
955     }
956     else
957     {
958         segment_cmd.vmsize = vmaddr;
959         segment_cmd.filesize = foffset - segment_cmd.fileoff;
960         /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an
961          * error, and is happening sometimes.
962          */
963         if (segment_cmd.filesize > vmaddr)
964             segment_cmd.vmsize = segment_cmd.filesize;
965     }
966 
967     // Put out relocation data
968     mach_numbersyms();
969     for (int seg = 1; seg < SegData.length; seg++)
970     {
971         seg_data *pseg = SegData[seg];
972         section *psechdr = null;
973         section_64 *psechdr64 = null;
974         if (I64)
975         {
976             psechdr64 = &SecHdrTab64[pseg.SDshtidx];   // corresponding section
977             //printf("psechdr.addr = x%llx\n", psechdr64.addr);
978         }
979         else
980         {
981             psechdr = &SecHdrTab[pseg.SDshtidx];   // corresponding section
982             //printf("psechdr.addr = x%x\n", psechdr.addr);
983         }
984         foffset = elf_align(I64 ? 8 : 4, foffset);
985         uint reloff = foffset;
986         uint nreloc = 0;
987         if (pseg.SDrel)
988         {   Relocation *r = cast(Relocation *)pseg.SDrel.buf;
989             Relocation *rend = cast(Relocation *)(pseg.SDrel.buf + pseg.SDrel.length());
990             for (; r != rend; r++)
991             {   Symbol *s = r.targsym;
992                 const(char)* rs = r.rtype == RELaddr ? "addr" : "rel";
993                 //printf("%d:x%04llx : tseg %d tsym %s REL%s\n", seg, r.offset, r.targseg, s ? s.Sident.ptr : "0", rs);
994                 relocation_info rel;
995                 scattered_relocation_info srel;
996                 if (s)
997                 {
998                     //printf("Relocation\n");
999                     //symbol_print(s);
1000                     if (r.flag == 1)
1001                     {
1002                         if (I64)
1003                         {
1004                             rel.r_type = X86_64_RELOC_SUBTRACTOR;
1005                             rel.r_address = cast(int)r.offset;
1006                             rel.r_symbolnum = r.funcsym.Sxtrnnum;
1007                             rel.r_pcrel = 0;
1008                             rel.r_length = 3;
1009                             rel.r_extern = 1;
1010                             fobjbuf.write(&rel, rel.sizeof);
1011                             foffset += (rel).sizeof;
1012                             ++nreloc;
1013 
1014                             rel.r_type = X86_64_RELOC_UNSIGNED;
1015                             rel.r_symbolnum = s.Sxtrnnum;
1016                             fobjbuf.write(&rel, rel.sizeof);
1017                             foffset += rel.sizeof;
1018                             ++nreloc;
1019 
1020                             // patch with fdesym.Soffset - offset
1021                             int64_t *p = cast(int64_t *)patchAddr64(seg, r.offset);
1022                             *p += r.funcsym.Soffset - r.offset;
1023                             continue;
1024                         }
1025                         else
1026                         {
1027                             // address = segment + offset
1028                             int targ_address = cast(int)(SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset);
1029                             int fixup_address = cast(int)(psechdr.addr + r.offset);
1030 
1031                             srel.r_scattered = 1;
1032                             srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF;
1033                             srel.r_address = cast(uint)r.offset;
1034                             srel.r_pcrel = 0;
1035                             srel.r_length = 2;
1036                             srel.r_value = targ_address;
1037                             fobjbuf.write((&srel)[0 .. 1]);
1038                             foffset += srel.sizeof;
1039                             ++nreloc;
1040 
1041                             srel.r_type = GENERIC_RELOC_PAIR;
1042                             srel.r_address = 0;
1043                             srel.r_value = fixup_address;
1044                             fobjbuf.write(&srel, srel.sizeof);
1045                             foffset += srel.sizeof;
1046                             ++nreloc;
1047 
1048                             int32_t *p = patchAddr(seg, r.offset);
1049                             *p += targ_address - fixup_address;
1050                             continue;
1051                         }
1052                     }
1053                     else if (pseg.isCode())
1054                     {
1055                         if (I64)
1056                         {
1057                             rel.r_type = (r.rtype == RELrel)
1058                                     ? X86_64_RELOC_BRANCH
1059                                     : X86_64_RELOC_SIGNED;
1060                             if (r.val == -1)
1061                                 rel.r_type = X86_64_RELOC_SIGNED_1;
1062                             else if (r.val == -2)
1063                                 rel.r_type = X86_64_RELOC_SIGNED_2;
1064                             if (r.val == -4)
1065                                 rel.r_type = X86_64_RELOC_SIGNED_4;
1066 
1067                             if (s.Sclass == SCextern ||
1068                                 s.Sclass == SCcomdef ||
1069                                 s.Sclass == SCcomdat ||
1070                                 s.Sclass == SCglobal)
1071                             {
1072                                 if (I64 && (s.ty() & mTYLINK) == mTYthread && r.rtype == RELaddr)
1073                                     rel.r_type = X86_64_RELOC_TLV;
1074                                 else if ((s.Sfl == FLfunc || s.Sfl == FLextern || s.Sclass == SCglobal || s.Sclass == SCcomdat || s.Sclass == SCcomdef) && r.rtype == RELaddr)
1075                                 {
1076                                     rel.r_type = X86_64_RELOC_GOT_LOAD;
1077                                     if (seg == eh_frame_seg ||
1078                                         seg == except_table_seg)
1079                                         rel.r_type = X86_64_RELOC_GOT;
1080                                 }
1081                                 rel.r_address = cast(int)r.offset;
1082                                 rel.r_symbolnum = s.Sxtrnnum;
1083                                 rel.r_pcrel = 1;
1084                                 rel.r_length = 2;
1085                                 rel.r_extern = 1;
1086                                 fobjbuf.write(&rel, rel.sizeof);
1087                                 foffset += rel.sizeof;
1088                                 nreloc++;
1089                                 continue;
1090                             }
1091                             else
1092                             {
1093                                 rel.r_address = cast(int)r.offset;
1094                                 rel.r_symbolnum = s.Sseg;
1095                                 rel.r_pcrel = 1;
1096                                 rel.r_length = 2;
1097                                 rel.r_extern = 0;
1098                                 fobjbuf.write(&rel, rel.sizeof);
1099                                 foffset += rel.sizeof;
1100                                 nreloc++;
1101 
1102                                 int32_t *p = patchAddr64(seg, r.offset);
1103                                 // Absolute address; add in addr of start of targ seg
1104 //printf("*p = x%x, .addr = x%x, Soffset = x%x\n", *p, cast(int)SecHdrTab64[SegData[s.Sseg].SDshtidx].addr, cast(int)s.Soffset);
1105 //printf("pseg = x%x, r.offset = x%x\n", (int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset);
1106                                 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1107                                 *p += s.Soffset;
1108                                 *p -= SecHdrTab64[pseg.SDshtidx].addr + r.offset + 4;
1109                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1110                                 continue;
1111                             }
1112                         }
1113                     }
1114                     else
1115                     {
1116                         if (s.Sclass == SCextern ||
1117                             s.Sclass == SCcomdef ||
1118                             s.Sclass == SCcomdat)
1119                         {
1120                             rel.r_address = cast(int)r.offset;
1121                             rel.r_symbolnum = s.Sxtrnnum;
1122                             rel.r_pcrel = 0;
1123                             rel.r_length = 2;
1124                             rel.r_extern = 1;
1125                             rel.r_type = GENERIC_RELOC_VANILLA;
1126                             if (I64)
1127                             {
1128                                 rel.r_type = X86_64_RELOC_UNSIGNED;
1129                                 rel.r_length = 3;
1130                             }
1131                             fobjbuf.write(&rel, rel.sizeof);
1132                             foffset += rel.sizeof;
1133                             nreloc++;
1134                             continue;
1135                         }
1136                         else
1137                         {
1138                             rel.r_address = cast(int)r.offset;
1139                             rel.r_symbolnum = s.Sseg;
1140                             rel.r_pcrel = 0;
1141                             rel.r_length = 2;
1142                             rel.r_extern = 0;
1143                             rel.r_type = GENERIC_RELOC_VANILLA;
1144                             if (I64)
1145                             {
1146                                 rel.r_type = X86_64_RELOC_UNSIGNED;
1147                                 rel.r_length = 3;
1148                                 if (0 && s.Sseg != seg)
1149                                     rel.r_type = X86_64_RELOC_BRANCH;
1150                             }
1151                             fobjbuf.write(&rel, rel.sizeof);
1152                             foffset += rel.sizeof;
1153                             nreloc++;
1154                             if (I64)
1155                             {
1156                                 rel.r_length = 3;
1157                                 int32_t *p = patchAddr64(seg, r.offset);
1158                                 // Absolute address; add in addr of start of targ seg
1159                                 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr + s.Soffset;
1160                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1161                             }
1162                             else
1163                             {
1164                                 int32_t *p = patchAddr(seg, r.offset);
1165                                 // Absolute address; add in addr of start of targ seg
1166                                 *p += SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset;
1167                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1168                             }
1169                             continue;
1170                         }
1171                     }
1172                 }
1173                 else if (r.rtype == RELaddr && pseg.isCode())
1174                 {
1175                     srel.r_scattered = 1;
1176 
1177                     srel.r_address = cast(uint)r.offset;
1178                     srel.r_length = 2;
1179                     if (I64)
1180                     {
1181                         int32_t *p64 = patchAddr64(seg, r.offset);
1182                         srel.r_type = X86_64_RELOC_GOT;
1183                         srel.r_value = cast(int)(SecHdrTab64[SegData[r.targseg].SDshtidx].addr + *p64);
1184                         //printf("SECTDIFF: x%llx + x%llx = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value);
1185                     }
1186                     else
1187                     {
1188                         int32_t *p = patchAddr(seg, r.offset);
1189                         srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF;
1190                         srel.r_value = SecHdrTab[SegData[r.targseg].SDshtidx].addr + *p;
1191                         //printf("SECTDIFF: x%x + x%x = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value);
1192                     }
1193                     srel.r_pcrel = 0;
1194                     fobjbuf.write(&srel, srel.sizeof);
1195                     foffset += srel.sizeof;
1196                     nreloc++;
1197 
1198                     srel.r_address = 0;
1199                     srel.r_length = 2;
1200                     if (I64)
1201                     {
1202                         srel.r_type = X86_64_RELOC_SIGNED;
1203                         srel.r_value = cast(int)(SecHdrTab64[pseg.SDshtidx].addr +
1204                                 r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1205                     }
1206                     else
1207                     {
1208                         srel.r_type = GENERIC_RELOC_PAIR;
1209                         if (r.funcsym)
1210                             srel.r_value = cast(int)(SecHdrTab[pseg.SDshtidx].addr +
1211                                     r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1212                         else
1213                             srel.r_value = cast(int)(psechdr.addr + r.offset);
1214                         //printf("srel.r_value = x%x, psechdr.addr = x%x, r.offset = x%x\n",
1215                             //cast(int)srel.r_value, cast(int)psechdr.addr, cast(int)r.offset);
1216                     }
1217                     srel.r_pcrel = 0;
1218                     fobjbuf.write(&srel, srel.sizeof);
1219                     foffset += srel.sizeof;
1220                     nreloc++;
1221 
1222                     // Recalc due to possible realloc of fobjbuf.buf
1223                     if (I64)
1224                     {
1225                         int32_t *p64 = patchAddr64(seg, r.offset);
1226                         //printf("address = x%x, p64 = %p *p64 = x%llx\n", r.offset, p64, *p64);
1227                         *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr -
1228                               (SecHdrTab64[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1229                     }
1230                     else
1231                     {
1232                         int32_t *p = patchAddr(seg, r.offset);
1233                         //printf("address = x%x, p = %p *p = x%x\n", r.offset, p, *p);
1234                         if (r.funcsym)
1235                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr -
1236                                   (SecHdrTab[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1237                         else
1238                             // targ_address - fixup_address
1239                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr -
1240                                   (psechdr.addr + r.offset);
1241                     }
1242                     continue;
1243                 }
1244                 else
1245                 {
1246                     rel.r_address = cast(int)r.offset;
1247                     rel.r_symbolnum = r.targseg;
1248                     rel.r_pcrel = (r.rtype == RELaddr) ? 0 : 1;
1249                     rel.r_length = 2;
1250                     rel.r_extern = 0;
1251                     rel.r_type = GENERIC_RELOC_VANILLA;
1252                     if (I64)
1253                     {
1254                         rel.r_type = X86_64_RELOC_UNSIGNED;
1255                         rel.r_length = 3;
1256                         if (0 && r.targseg != seg)
1257                             rel.r_type = X86_64_RELOC_BRANCH;
1258                     }
1259                     fobjbuf.write(&rel, rel.sizeof);
1260                     foffset += rel.sizeof;
1261                     nreloc++;
1262                     if (I64)
1263                     {
1264                         int32_t *p64 = patchAddr64(seg, r.offset);
1265                         //int64_t before = *p64;
1266                         if (rel.r_pcrel)
1267                             // Relative address
1268                             patch(pseg, r.offset, r.targseg, 0);
1269                         else
1270                         {   // Absolute address; add in addr of start of targ seg
1271 //printf("*p = x%x, targ.addr = x%x\n", *p64, cast(int)SecHdrTab64[SegData[r.targseg].SDshtidx].addr);
1272 //printf("pseg = x%x, r.offset = x%x\n", cast(int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset);
1273                             *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr;
1274                             //*p64 -= SecHdrTab64[pseg.SDshtidx].addr;
1275                         }
1276                         //printf("%d:x%04x before = x%04llx, after = x%04llx pcrel = %d\n", seg, r.offset, before, *p64, rel.r_pcrel);
1277                     }
1278                     else
1279                     {
1280                         int32_t *p = patchAddr(seg, r.offset);
1281                         //int32_t before = *p;
1282                         if (rel.r_pcrel)
1283                             // Relative address
1284                             patch(pseg, r.offset, r.targseg, 0);
1285                         else
1286                             // Absolute address; add in addr of start of targ seg
1287                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr;
1288                         //printf("%d:x%04x before = x%04x, after = x%04x pcrel = %d\n", seg, r.offset, before, *p, rel.r_pcrel);
1289                     }
1290                     continue;
1291                 }
1292             }
1293         }
1294         if (nreloc)
1295         {
1296             if (I64)
1297             {
1298                 psechdr64.reloff = reloff;
1299                 psechdr64.nreloc = nreloc;
1300             }
1301             else
1302             {
1303                 psechdr.reloff = reloff;
1304                 psechdr.nreloc = nreloc;
1305             }
1306         }
1307     }
1308 
1309     // Put out symbol table
1310     foffset = elf_align(I64 ? 8 : 4, foffset);
1311     symtab_cmd.symoff = foffset;
1312     dysymtab_cmd.ilocalsym = 0;
1313     dysymtab_cmd.nlocalsym  = cast(uint)(local_symbuf.length() / (Symbol *).sizeof);
1314     dysymtab_cmd.iextdefsym = dysymtab_cmd.nlocalsym;
1315     dysymtab_cmd.nextdefsym = cast(uint)(public_symbuf.length() / (Symbol *).sizeof);
1316     dysymtab_cmd.iundefsym = dysymtab_cmd.iextdefsym + dysymtab_cmd.nextdefsym;
1317     int nexterns = cast(int)(extern_symbuf.length() / (Symbol *).sizeof);
1318     int ncomdefs = cast(int)(comdef_symbuf.length() / Comdef.sizeof);
1319     dysymtab_cmd.nundefsym  = nexterns + ncomdefs;
1320     symtab_cmd.nsyms =  dysymtab_cmd.nlocalsym +
1321                         dysymtab_cmd.nextdefsym +
1322                         dysymtab_cmd.nundefsym;
1323     fobjbuf.reserve(cast(uint)(symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof)));
1324     for (int i = 0; i < dysymtab_cmd.nlocalsym; i++)
1325     {   Symbol *s = (cast(Symbol **)local_symbuf.buf)[i];
1326         nlist_64 sym = void;
1327         sym.n_strx = elf_addmangled(s);
1328         sym.n_type = N_SECT;
1329         sym.n_desc = 0;
1330         if (s.Sclass == SCcomdat)
1331             sym.n_desc = N_WEAK_DEF;
1332         sym.n_sect = cast(ubyte)s.Sseg;
1333         if (I64)
1334         {
1335             sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1336             fobjbuf.write(&sym, sym.sizeof);
1337         }
1338         else
1339         {
1340             nlist sym32 = void;
1341             sym32.n_strx = sym.n_strx;
1342             sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr);
1343             sym32.n_type = sym.n_type;
1344             sym32.n_desc = sym.n_desc;
1345             sym32.n_sect = sym.n_sect;
1346             fobjbuf.write(&sym32, sym32.sizeof);
1347         }
1348     }
1349     for (int i = 0; i < dysymtab_cmd.nextdefsym; i++)
1350     {   Symbol *s = (cast(Symbol **)public_symbuf.buf)[i];
1351 
1352         //printf("Writing public symbol %d:x%x %s\n", s.Sseg, s.Soffset, s.Sident);
1353         nlist_64 sym = void;
1354         sym.n_strx = elf_addmangled(s);
1355         sym.n_type = N_EXT | N_SECT;
1356         if (s.Sflags & SFLhidden)
1357             sym.n_type |= N_PEXT; // private extern
1358         sym.n_desc = 0;
1359         if (s.Sclass == SCcomdat)
1360             sym.n_desc = N_WEAK_DEF;
1361         sym.n_sect = cast(ubyte)s.Sseg;
1362         if (I64)
1363         {
1364             sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1365             fobjbuf.write(&sym, sym.sizeof);
1366         }
1367         else
1368         {
1369             nlist sym32 = void;
1370             sym32.n_strx = sym.n_strx;
1371             sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr);
1372             sym32.n_type = sym.n_type;
1373             sym32.n_desc = sym.n_desc;
1374             sym32.n_sect = sym.n_sect;
1375             fobjbuf.write(&sym32, sym32.sizeof);
1376         }
1377     }
1378     for (int i = 0; i < nexterns; i++)
1379     {   Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i];
1380         nlist_64 sym = void;
1381         sym.n_strx = elf_addmangled(s);
1382         sym.n_value = s.Soffset;
1383         sym.n_type = N_EXT | N_UNDF;
1384         sym.n_desc = tyfunc(s.ty()) ? REFERENCE_FLAG_UNDEFINED_LAZY
1385                                      : REFERENCE_FLAG_UNDEFINED_NON_LAZY;
1386         sym.n_sect = 0;
1387         if (I64)
1388             fobjbuf.write(&sym, sym.sizeof);
1389         else
1390         {
1391             nlist sym32 = void;
1392             sym32.n_strx = sym.n_strx;
1393             sym32.n_value = cast(uint)sym.n_value;
1394             sym32.n_type = sym.n_type;
1395             sym32.n_desc = sym.n_desc;
1396             sym32.n_sect = sym.n_sect;
1397             fobjbuf.write(&sym32, sym32.sizeof);
1398         }
1399     }
1400     for (int i = 0; i < ncomdefs; i++)
1401     {   Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i;
1402         nlist_64 sym = void;
1403         sym.n_strx = elf_addmangled(c.sym);
1404         sym.n_value = c.size * c.count;
1405         sym.n_type = N_EXT | N_UNDF;
1406         int align_;
1407         if (c.size < 2)
1408             align_ = 0;          // align_ is expressed as power of 2
1409         else if (c.size < 4)
1410             align_ = 1;
1411         else if (c.size < 8)
1412             align_ = 2;
1413         else if (c.size < 16)
1414             align_ = 3;
1415         else
1416             align_ = 4;
1417         sym.n_desc = cast(ushort)(align_ << 8);
1418         sym.n_sect = 0;
1419         if (I64)
1420             fobjbuf.write(&sym, sym.sizeof);
1421         else
1422         {
1423             nlist sym32 = void;
1424             sym32.n_strx = sym.n_strx;
1425             sym32.n_value = cast(uint)sym.n_value;
1426             sym32.n_type = sym.n_type;
1427             sym32.n_desc = sym.n_desc;
1428             sym32.n_sect = sym.n_sect;
1429             fobjbuf.write(&sym32, sym32.sizeof);
1430         }
1431     }
1432     if (extdef)
1433     {
1434         nlist_64 sym = void;
1435         sym.n_strx = extdef;
1436         sym.n_value = 0;
1437         sym.n_type = N_EXT | N_UNDF;
1438         sym.n_desc = 0;
1439         sym.n_sect = 0;
1440         if (I64)
1441             fobjbuf.write(&sym, sym.sizeof);
1442         else
1443         {
1444             nlist sym32 = void;
1445             sym32.n_strx = sym.n_strx;
1446             sym32.n_value = cast(uint)sym.n_value;
1447             sym32.n_type = sym.n_type;
1448             sym32.n_desc = sym.n_desc;
1449             sym32.n_sect = sym.n_sect;
1450             fobjbuf.write(&sym32, sym32.sizeof);
1451         }
1452         symtab_cmd.nsyms++;
1453     }
1454     foffset += symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof);
1455 
1456     // Put out string table
1457     foffset = elf_align(I64 ? 8 : 4, foffset);
1458     symtab_cmd.stroff = foffset;
1459     symtab_cmd.strsize = cast(uint)symtab_strings.length();
1460     fobjbuf.write(symtab_strings.buf, symtab_cmd.strsize);
1461     foffset += symtab_cmd.strsize;
1462 
1463     // Put out indirectsym table, which is in two parts
1464     foffset = elf_align(I64 ? 8 : 4, foffset);
1465     dysymtab_cmd.indirectsymoff = foffset;
1466     if (indirectsymbuf1)
1467     {
1468         dysymtab_cmd.nindirectsyms += indirectsymbuf1.length() / (Symbol *).sizeof;
1469         for (int i = 0; i < dysymtab_cmd.nindirectsyms; i++)
1470         {   Symbol *s = (cast(Symbol **)indirectsymbuf1.buf)[i];
1471             fobjbuf.write32(s.Sxtrnnum);
1472         }
1473     }
1474     if (indirectsymbuf2)
1475     {
1476         int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof);
1477         dysymtab_cmd.nindirectsyms += n;
1478         for (int i = 0; i < n; i++)
1479         {   Symbol *s = (cast(Symbol **)indirectsymbuf2.buf)[i];
1480             fobjbuf.write32(s.Sxtrnnum);
1481         }
1482     }
1483     foffset += dysymtab_cmd.nindirectsyms * 4;
1484 
1485     /* The correct offsets are now determined, so
1486      * rewind and fix the header.
1487      */
1488     fobjbuf.position(headersize, sizeofcmds);
1489     if (I64)
1490     {
1491         fobjbuf.write(&segment_cmd64, segment_cmd64.sizeof);
1492         fobjbuf.write(SECbuf.buf + section_64.sizeof, cast(uint)((section_cnt - 1) * section_64.sizeof));
1493     }
1494     else
1495     {
1496         fobjbuf.write(&segment_cmd, segment_cmd.sizeof);
1497         fobjbuf.write(SECbuf.buf + section.sizeof, cast(uint)((section_cnt - 1) * section.sizeof));
1498     }
1499     fobjbuf.write(&symtab_cmd, symtab_cmd.sizeof);
1500     fobjbuf.write(&dysymtab_cmd, dysymtab_cmd.sizeof);
1501     fobjbuf.position(foffset, 0);
1502 }
1503 
1504 /*****************************
1505  * Line number support.
1506  */
1507 
1508 /***************************
1509  * Record file and line number at segment and offset.
1510  * The actual .debug_line segment is put out by dwarf_termfile().
1511  * Params:
1512  *      srcpos = source file position
1513  *      seg = segment it corresponds to
1514  *      offset = offset within seg
1515  */
1516 
1517 void Obj_linnum(Srcpos srcpos, int seg, targ_size_t offset)
1518 {
1519     if (srcpos.Slinnum == 0)
1520         return;
1521 
1522 static if (0)
1523 {
1524     printf("Obj_linnum(seg=%d, offset=x%lx) ", seg, offset);
1525     srcpos.print("");
1526 }
1527 
1528 version (MARS)
1529 {
1530     if (!srcpos.Sfilename)
1531         return;
1532 }
1533 version (SCPP)
1534 {
1535     if (!srcpos.Sfilptr)
1536         return;
1537     sfile_debug(&srcpos_sfile(srcpos));
1538     Sfile *sf = *srcpos.Sfilptr;
1539 }
1540 
1541     size_t i;
1542     seg_data *pseg = SegData[seg];
1543 
1544     // Find entry i in SDlinnum_data[] that corresponds to srcpos filename
1545     for (i = 0; 1; i++)
1546     {
1547         if (i == pseg.SDlinnum_data.length)
1548         {   // Create new entry
1549             version (MARS)
1550                 pseg.SDlinnum_data.push(linnum_data(srcpos.Sfilename));
1551             version (SCPP)
1552                 pseg.SDlinnum_data.push(linnum_data(sf));
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     ld.linoff.push(LinOff(srcpos.Slinnum, cast(uint)offset));
1570 }
1571 
1572 
1573 /*******************************
1574  * Set start address
1575  */
1576 
1577 void Obj_startaddress(Symbol *s)
1578 {
1579     //dbg_printf("Obj_startaddress(Symbol *%s)\n",s.Sident);
1580     //obj.startaddress = s;
1581 }
1582 
1583 /*******************************
1584  * Output library name.
1585  */
1586 
1587 bool Obj_includelib(const(char)* name)
1588 {
1589     //dbg_printf("Obj_includelib(name *%s)\n",name);
1590     return false;
1591 }
1592 
1593 /*******************************
1594 * Output linker directive.
1595 */
1596 
1597 bool Obj_linkerdirective(const(char)* name)
1598 {
1599     return false;
1600 }
1601 
1602 /**********************************
1603  * Do we allow zero sized objects?
1604  */
1605 
1606 bool Obj_allowZeroSize()
1607 {
1608     return true;
1609 }
1610 
1611 /**************************
1612  * Embed string in executable.
1613  */
1614 
1615 void Obj_exestr(const(char)* p)
1616 {
1617     //dbg_printf("Obj_exestr(char *%s)\n",p);
1618 }
1619 
1620 /**************************
1621  * Embed string in obj.
1622  */
1623 
1624 void Obj_user(const(char)* p)
1625 {
1626     //dbg_printf("Obj_user(char *%s)\n",p);
1627 }
1628 
1629 /*******************************
1630  * Output a weak extern record.
1631  */
1632 
1633 void Obj_wkext(Symbol *s1,Symbol *s2)
1634 {
1635     //dbg_printf("Obj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr);
1636 }
1637 
1638 /*******************************
1639  * Output file name record.
1640  *
1641  * Currently assumes that obj_filename will not be called
1642  *      twice for the same file.
1643  */
1644 
1645 void obj_filename(const(char)* modname)
1646 {
1647     //dbg_printf("obj_filename(char *%s)\n",modname);
1648     // Not supported by Mach-O
1649 }
1650 
1651 /*******************************
1652  * Embed compiler version in .obj file.
1653  */
1654 
1655 void Obj_compiler()
1656 {
1657     //dbg_printf("Obj_compiler\n");
1658 }
1659 
1660 
1661 /**************************************
1662  * Symbol is the function that calls the static constructors.
1663  * Put a pointer to it into a special segment that the startup code
1664  * looks at.
1665  * Input:
1666  *      s       static constructor function
1667  *      dtor    !=0 if leave space for static destructor
1668  *      seg     1:      user
1669  *              2:      lib
1670  *              3:      compiler
1671  */
1672 
1673 void Obj_staticctor(Symbol *s, int, int)
1674 {
1675     Obj_setModuleCtorDtor(s, true);
1676 }
1677 
1678 /**************************************
1679  * Symbol is the function that calls the static destructors.
1680  * Put a pointer to it into a special segment that the exit code
1681  * looks at.
1682  * Input:
1683  *      s       static destructor function
1684  */
1685 
1686 void Obj_staticdtor(Symbol *s)
1687 {
1688     Obj_setModuleCtorDtor(s, false);
1689 }
1690 
1691 
1692 /***************************************
1693  * Stuff pointer to function in its own segment.
1694  * Used for static ctor and dtor lists.
1695  */
1696 
1697 void Obj_setModuleCtorDtor(Symbol *sfunc, bool isCtor)
1698 {
1699     const align_ = I64 ? 3 : 2; // align to _tysize[TYnptr]
1700 
1701     IDXSEC seg = isCtor
1702                 ? getsegment2(seg_mod_init_func, "__mod_init_func", "__DATA", align_, S_MOD_INIT_FUNC_POINTERS)
1703                 : getsegment2(seg_mod_term_func, "__mod_term_func", "__DATA", align_, S_MOD_TERM_FUNC_POINTERS);
1704 
1705     const int relflags = I64 ? CFoff | CFoffset64 : CFoff;
1706     const int sz = Obj_reftoident(seg, SegData[seg].SDoffset, sfunc, 0, relflags);
1707     SegData[seg].SDoffset += sz;
1708 }
1709 
1710 
1711 /***************************************
1712  * Stuff the following data (instance of struct FuncTable) in a separate segment:
1713  *      pointer to function
1714  *      pointer to ehsym
1715  *      length of function
1716  */
1717 
1718 void Obj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym)
1719 {
1720     //dbg_printf("Obj_ehtables(%s) \n",sfunc.Sident.ptr);
1721 
1722     /* BUG: this should go into a COMDAT if sfunc is in a COMDAT
1723      * otherwise the duplicates aren't removed.
1724      */
1725 
1726     int align_ = I64 ? 3 : 2;            // align to _tysize[TYnptr]
1727     // The size is (FuncTable).sizeof in deh2.d
1728     int seg = getsegment2(seg_deh_eh, "__deh_eh", "__DATA", align_, S_REGULAR);
1729 
1730     Outbuffer *buf = SegData[seg].SDbuf;
1731     if (I64)
1732     {
1733         Obj_reftoident(seg, buf.length(), sfunc, 0, CFoff | CFoffset64);
1734         Obj_reftoident(seg, buf.length(), ehsym, 0, CFoff | CFoffset64);
1735         buf.write64(sfunc.Ssize);
1736     }
1737     else
1738     {
1739         Obj_reftoident(seg, buf.length(), sfunc, 0, CFoff);
1740         Obj_reftoident(seg, buf.length(), ehsym, 0, CFoff);
1741         buf.write32(cast(int)sfunc.Ssize);
1742     }
1743 }
1744 
1745 /*********************************************
1746  * Put out symbols that define the beginning/end of the .deh_eh section.
1747  * This gets called if this is the module with "main()" in it.
1748  */
1749 
1750 void Obj_ehsections()
1751 {
1752     //printf("Obj_ehsections()\n");
1753 }
1754 
1755 /*********************************
1756  * Setup for Symbol s to go into a COMDAT segment.
1757  * Output (if s is a function):
1758  *      cseg            segment index of new current code segment
1759  *      Offset(cseg)         starting offset in cseg
1760  * Returns:
1761  *      "segment index" of COMDAT
1762  */
1763 
1764 int Obj_comdatsize(Symbol *s, targ_size_t symsize)
1765 {
1766     return Obj_comdat(s);
1767 }
1768 
1769 int Obj_comdat(Symbol *s)
1770 {
1771     const(char)* sectname;
1772     const(char)* segname;
1773     int align_;
1774     int flags;
1775 
1776     //printf("Obj_comdat(Symbol* %s)\n",s.Sident.ptr);
1777     //symbol_print(s);
1778     symbol_debug(s);
1779 
1780     if (tyfunc(s.ty()))
1781     {
1782         sectname = "__textcoal_nt";
1783         segname = "__TEXT";
1784         align_ = 2;              // 4 byte alignment
1785         flags = S_COALESCED | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
1786         s.Sseg = getsegment2(seg_textcoal_nt, sectname, segname, align_, flags);
1787     }
1788     else if ((s.ty() & mTYLINK) == mTYthread)
1789     {
1790         s.Sfl = FLtlsdata;
1791         align_ = 4;
1792         if (I64)
1793             s.Sseg = objmod.tlsseg().SDseg;
1794         else
1795             s.Sseg = getsegment2(seg_tlscoal_nt, "__tlscoal_nt", "__DATA", align_, S_COALESCED);
1796         Obj_data_start(s, 1 << align_, s.Sseg);
1797     }
1798     else
1799     {
1800         s.Sfl = FLdata;
1801         sectname = "__datacoal_nt";
1802         segname = "__DATA";
1803         align_ = 4;              // 16 byte alignment
1804         s.Sseg = getsegment2(seg_datacoal_nt, sectname, segname, align_, S_COALESCED);
1805         Obj_data_start(s, 1 << align_, s.Sseg);
1806     }
1807                                 // find or create new segment
1808     if (s.Salignment > (1 << align_))
1809         SegData[s.Sseg].SDalignment = s.Salignment;
1810     s.Soffset = SegData[s.Sseg].SDoffset;
1811     if (s.Sfl == FLdata || s.Sfl == FLtlsdata)
1812     {   // Code symbols are 'published' by Obj_func_start()
1813 
1814         Obj_pubdef(s.Sseg,s,s.Soffset);
1815         searchfixlist(s);               // backpatch any refs to this symbol
1816     }
1817     return s.Sseg;
1818 }
1819 
1820 int Obj_readonly_comdat(Symbol *s)
1821 {
1822     assert(0);
1823 }
1824 
1825 /***********************************
1826  * Returns:
1827  *      jump table segment for function s
1828  */
1829 int Obj_jmpTableSegment(Symbol *s)
1830 {
1831     return (config.flags & CFGromable) ? cseg : CDATA;
1832 }
1833 
1834 /**********************************
1835  * Get segment.
1836  * Input:
1837  *      align_   segment alignment as power of 2
1838  * Returns:
1839  *      segment index of found or newly created segment
1840  */
1841 
1842 int Obj_getsegment(const(char)* sectname, const(char)* segname,
1843         int align_, int flags)
1844 {
1845     assert(strlen(sectname) <= 16);
1846     assert(strlen(segname)  <= 16);
1847     for (int seg = 1; seg < cast(int)SegData.length; seg++)
1848     {   seg_data *pseg = SegData[seg];
1849         if (I64)
1850         {
1851             if (strncmp(SecHdrTab64[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 &&
1852                 strncmp(SecHdrTab64[pseg.SDshtidx].segname.ptr, segname, 16) == 0)
1853                 return seg;         // return existing segment
1854         }
1855         else
1856         {
1857             if (strncmp(SecHdrTab[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 &&
1858                 strncmp(SecHdrTab[pseg.SDshtidx].segname.ptr, segname, 16) == 0)
1859                 return seg;         // return existing segment
1860         }
1861     }
1862 
1863     const int seg = cast(int)SegData.length;
1864     seg_data** ppseg = SegData.push();
1865 
1866     seg_data* pseg = *ppseg;
1867 
1868     if (pseg)
1869     {
1870         Outbuffer *b1 = pseg.SDbuf;
1871         Outbuffer *b2 = pseg.SDrel;
1872         memset(pseg, 0, seg_data.sizeof);
1873         if (b1)
1874             b1.reset();
1875         if (b2)
1876             b2.reset();
1877         pseg.SDbuf = b1;
1878         pseg.SDrel = b2;
1879     }
1880     else
1881     {
1882         pseg = cast(seg_data *)mem_calloc(seg_data.sizeof);
1883         SegData[seg] = pseg;
1884     }
1885 
1886     if (!pseg.SDbuf)
1887     {
1888         if (flags != S_ZEROFILL)
1889         {
1890             pseg.SDbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
1891             assert(pseg.SDbuf);
1892             pseg.SDbuf.reserve(4096);
1893         }
1894     }
1895 
1896     //printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf);
1897 
1898     pseg.SDseg = seg;
1899     pseg.SDoffset = 0;
1900 
1901     if (I64)
1902     {
1903         section_64 *sec = cast(section_64 *)
1904             SECbuf.writezeros(section_64.sizeof);
1905         strncpy(sec.sectname.ptr, sectname, 16);
1906         strncpy(sec.segname.ptr, segname, 16);
1907         sec._align = align_;
1908         sec.flags = flags;
1909     }
1910     else
1911     {
1912         section *sec = cast(section *)
1913             SECbuf.writezeros(section.sizeof);
1914         strncpy(sec.sectname.ptr, sectname, 16);
1915         strncpy(sec.segname.ptr, segname, 16);
1916         sec._align = align_;
1917         sec.flags = flags;
1918     }
1919 
1920     pseg.SDshtidx = section_cnt++;
1921     pseg.SDaranges_offset = 0;
1922     pseg.SDlinnum_data.reset();
1923 
1924     //printf("SegData.length = %d\n", SegData.length);
1925     return seg;
1926 }
1927 
1928 /********************************
1929  * Memoize seg index.
1930  * Params:
1931  *      seg = value to memoize if it is not already set
1932  *      sectname = section name
1933  *      segname = segment name
1934  *      align_ = section alignment
1935  *      flags = S_????
1936  * Returns:
1937  *      seg index
1938  */
1939 int getsegment2(ref int seg, const(char)* sectname, const(char)* segname,
1940         int align_, int flags)
1941 {
1942     if (seg == UNKNOWN)
1943         seg = Obj_getsegment(sectname, segname, align_, flags);
1944     return seg;
1945 }
1946 
1947 /**********************************
1948  * Reset code seg to existing seg.
1949  * Used after a COMDAT for a function is done.
1950  */
1951 
1952 void Obj_setcodeseg(int seg)
1953 {
1954     cseg = seg;
1955 }
1956 
1957 /********************************
1958  * Define a new code segment.
1959  * Input:
1960  *      name            name of segment, if null then revert to default
1961  *      suffix  0       use name as is
1962  *              1       append "_TEXT" to name
1963  * Output:
1964  *      cseg            segment index of new current code segment
1965  *      Offset(cseg)         starting offset in cseg
1966  * Returns:
1967  *      segment index of newly created code segment
1968  */
1969 
1970 int Obj_codeseg(const char *name,int suffix)
1971 {
1972     //dbg_printf("Obj_codeseg(%s,%x)\n",name,suffix);
1973 static if (0)
1974 {
1975     const(char)* sfx = (suffix) ? "_TEXT" : null;
1976 
1977     if (!name)                          // returning to default code segment
1978     {
1979         if (cseg != CODE)               // not the current default
1980         {
1981             SegData[cseg].SDoffset = Offset(cseg);
1982             Offset(cseg) = SegData[CODE].SDoffset;
1983             cseg = CODE;
1984         }
1985         return cseg;
1986     }
1987 
1988     int seg = ElfObj_getsegment(name, sfx, SHT_PROGDEF, SHF_ALLOC|SHF_EXECINSTR, 4);
1989                                     // find or create code segment
1990 
1991     cseg = seg;                         // new code segment index
1992     Offset(cseg) = 0;
1993     return seg;
1994 }
1995 else
1996 {
1997     return 0;
1998 }
1999 }
2000 
2001 /*********************************
2002  * Define segments for Thread Local Storage for 32bit.
2003  * Output:
2004  *      seg_tlsseg      set to segment number for TLS segment.
2005  * Returns:
2006  *      segment for TLS segment
2007  */
2008 
2009 seg_data *Obj_tlsseg()
2010 {
2011     //printf("Obj_tlsseg(\n");
2012     int seg = I32 ? getsegment2(seg_tlsseg, "__tls_data", "__DATA", 2, S_REGULAR)
2013                   : getsegment2(seg_tlsseg, "__thread_vars", "__DATA", 0, S_THREAD_LOCAL_VARIABLES);
2014     return SegData[seg];
2015 }
2016 
2017 
2018 /*********************************
2019  * Define segments for Thread Local Storage.
2020  * Output:
2021  *      seg_tlsseg_bss  set to segment number for TLS segment.
2022  * Returns:
2023  *      segment for TLS segment
2024  */
2025 
2026 seg_data *Obj_tlsseg_bss()
2027 {
2028 
2029     if (I32)
2030     {
2031         /* Because DMD does not support native tls for Mach-O 32bit,
2032          * it's easier to support if we have all the tls in one segment.
2033          */
2034         return Obj_tlsseg();
2035     }
2036     else
2037     {
2038         // The alignment should actually be alignment of the largest variable in
2039         // the section, but this seems to work anyway.
2040         int seg = getsegment2(seg_tlsseg_bss, "__thread_bss", "__DATA", 3, S_THREAD_LOCAL_ZEROFILL);
2041         return SegData[seg];
2042     }
2043 }
2044 
2045 /*********************************
2046  * Define segments for Thread Local Storage data.
2047  * Output:
2048  *      seg_tlsseg_data    set to segment number for TLS data segment.
2049  * Returns:
2050  *      segment for TLS data segment
2051  */
2052 
2053 seg_data *Obj_tlsseg_data()
2054 {
2055     //printf("Obj_tlsseg_data(\n");
2056     assert(I64);
2057 
2058     // The alignment should actually be alignment of the largest variable in
2059     // the section, but this seems to work anyway.
2060     int seg = getsegment2(seg_tlsseg_data, "__thread_data", "__DATA", 4, S_THREAD_LOCAL_REGULAR);
2061     return SegData[seg];
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 < SegData.length))
2475     {   printf("Obj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length);
2476         *cast(char*)0=0;
2477     }
2478 }
2479     assert(seg >= 0 && seg < SegData.length);
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 }