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