1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) ?-1998 by Symantec
6  *              Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/elfobj.d, backend/elfobj.d)
10  */
11 
12 module dmd.backend.elfobj;
13 
14 /****
15  * Output to ELF object files
16  * http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html
17  */
18 
19 version (SCPP)
20     version = COMPILE;
21 version (MARS)
22     version = COMPILE;
23 
24 version (COMPILE)
25 {
26 
27 import core.stdc.stdio;
28 import core.stdc.stdlib;
29 import core.stdc.string;
30 
31 import dmd.backend.barray;
32 import dmd.backend.cc;
33 import dmd.backend.cdef;
34 import dmd.backend.code;
35 import dmd.backend.code_x86;
36 import dmd.backend.mem;
37 import dmd.backend.aarray;
38 import dmd.backend.dlist;
39 import dmd.backend.el;
40 import dmd.backend.global;
41 import dmd.backend.obj;
42 import dmd.backend.oper;
43 import dmd.backend.outbuf;
44 import dmd.backend.symtab;
45 import dmd.backend.ty;
46 import dmd.backend.type;
47 
48 extern (C++):
49 
50 nothrow:
51 
52 static if (1)
53 {
54 
55 import dmd.backend.dwarf;
56 import dmd.backend.melf;
57 
58 extern bool symbol_iscomdat2(Symbol* s) @system;
59 
60 //#define DEBSYM 0x7E
61 
62 private __gshared Outbuffer *fobjbuf;
63 
64 enum MATCH_SECTION = 1;
65 
66 enum DEST_LEN = (IDMAX + IDOHD + 1);
67 
68 version (MARS)
69 {
70     // C++ name mangling is handled by front end
71     const(char)* cpp_mangle2(Symbol* s) { return &s.Sident[0]; }
72 }
73 else
74     const(char)* cpp_mangle2(Symbol* s) { return cpp_mangle(s); }
75 
76 void addSegmentToComdat(segidx_t seg, segidx_t comdatseg);
77 
78 /**
79  * If set the compiler requires full druntime support of the new
80  * section registration.
81  */
82 //version (DMDV2)
83 static if (1)
84     enum DMDV2 = true;
85 else
86     enum DMDV2 = false;
87 enum REQUIRE_DSO_REGISTRY = (DMDV2 && (TARGET_LINUX || TARGET_FREEBSD || TARGET_DRAGONFLYBSD));
88 
89 /**
90  * If set, produce .init_array/.fini_array instead of legacy .ctors/.dtors .
91  * OpenBSD added the support in Aug 2016. Other supported platforms has
92  * supported .init_array for years.
93  */
94 enum USE_INIT_ARRAY = !TARGET_OPENBSD;
95 
96 /******
97  * FreeBSD uses ELF, but the linker crashes with Elf comdats with the following message:
98  *  /usr/bin/ld: BFD 2.15 [FreeBSD] 2004-05-23 internal error, aborting at
99  *  /usr/src/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/elfcode.h
100  *  line 213 in bfd_elf32_swap_symbol_out
101  * For the time being, just stick with Linux.
102  */
103 
104 enum ELF_COMDAT = TARGET_LINUX;
105 
106 /***************************************************
107  * Correspondence of relocation types
108  *      386             32 bit in 64      64 in 64
109  *      R_386_32        R_X86_64_32       R_X86_64_64
110  *      R_386_GOTOFF    R_X86_64_PC32     R_X86_64_
111  *      R_386_GOTPC     R_X86_64_         R_X86_64_
112  *      R_386_GOT32     R_X86_64_         R_X86_64_
113  *      R_386_TLS_GD    R_X86_64_TLSGD    R_X86_64_
114  *      R_386_TLS_IE    R_X86_64_GOTTPOFF R_X86_64_
115  *      R_386_TLS_LE    R_X86_64_TPOFF32  R_X86_64_
116  *      R_386_PLT32     R_X86_64_PLT32    R_X86_64_
117  *      R_386_PC32      R_X86_64_PC32     R_X86_64_
118  */
119 
120 alias reltype_t = uint;
121 
122 /******************************************
123  */
124 
125 private __gshared Symbol *GOTsym; // global offset table reference
126 
127 private Symbol *ElfObj_getGOTsym()
128 {
129     if (!GOTsym)
130     {
131         GOTsym = symbol_name("_GLOBAL_OFFSET_TABLE_",SCglobal,tspvoid);
132     }
133     return GOTsym;
134 }
135 
136 void ElfObj_refGOTsym()
137 {
138     if (!GOTsym)
139     {
140         Symbol *s = ElfObj_getGOTsym();
141         ElfObj_external(s);
142     }
143 }
144 
145 //private void objfile_write(FILE *fd, void *buffer, uint len);
146 
147 // The object file is built is several separate pieces
148 
149 // Non-repeatable section types have single output buffers
150 //      Pre-allocated buffers are defined for:
151 //              Section Names string table
152 //              Section Headers table
153 //              Symbol table
154 //              String table
155 //              Notes section
156 //              Comment data
157 
158 // Section Names  - String table for section names only
159 private __gshared Outbuffer *section_names;
160 enum SEC_NAMES_INIT = 800;
161 enum SEC_NAMES_INC  = 400;
162 
163 // Hash table for section_names
164 __gshared AApair2 *section_names_hashtable;
165 
166 __gshared int jmpseg;
167 
168 /* ======================================================================== */
169 
170 // String Table  - String table for all other names
171 private __gshared Outbuffer *symtab_strings;
172 
173 
174 // Section Headers
175 __gshared Barray!(Elf32_Shdr) SecHdrTab;        // section header table
176 
177 const(char)* GET_SECTION_NAME(int secidx)
178 {
179     return cast(const(char)*)section_names.buf + SecHdrTab[secidx].sh_name;
180 }
181 
182 // The relocation for text and data seems to get lost.
183 // Try matching the order gcc output them
184 // This means defining the sections and then removing them if they are
185 // not used.
186 
187 enum
188 {
189     SHN_TEXT        = 1,
190     SHN_RELTEXT     = 2,
191     SHN_DATA        = 3,
192     SHN_RELDATA     = 4,
193     SHN_BSS         = 5,
194     SHN_RODAT       = 6,
195     SHN_STRINGS     = 7,
196     SHN_SYMTAB      = 8,
197     SHN_SECNAMES    = 9,
198     SHN_COM         = 10,
199     SHN_NOTE        = 11,
200     SHN_GNUSTACK    = 12,
201     SHN_CDATAREL    = 13,
202 }
203 
204 __gshared IDXSYM *mapsec2sym;
205 enum S2S_INC = 20;
206 
207 private __gshared int symbol_idx;          // Number of symbols in symbol table
208 private __gshared int local_cnt;           // Number of symbols with STB_LOCAL
209 
210 enum
211 {
212     STI_FILE     = 1,       // Where file symbol table entry is
213     STI_TEXT     = 2,
214     STI_DATA     = 3,
215     STI_BSS      = 4,
216     STI_GCC      = 5,       // Where "gcc2_compiled" symbol is */
217     STI_RODAT    = 6,       // Symbol for readonly data
218     STI_NOTE     = 7,       // Where note symbol table entry is
219     STI_COM      = 8,
220     STI_CDATAREL = 9,       // Symbol for readonly data with relocations
221 }
222 
223 // NOTE: There seems to be a requirement that the read-only data have the
224 // same symbol table index and section index. Use section NOTE as a place
225 // holder. When a read-only string section is required, swap to NOTE.
226 
227 __gshared
228 {
229 
230 struct ElfObj
231 {
232     // Symbol Table
233     Barray!Elf32_Sym SymbolTable;
234     Barray!Elf64_Sym SymbolTable64;
235 
236     Barray!(Symbol*) resetSyms; // Keep pointers to reset symbols
237 }
238 
239 private ElfObj elfobj;
240 
241 
242 // Extended section header indices
243 private Outbuffer *shndx_data;
244 private const IDXSEC secidx_shndx = SHN_HIRESERVE + 1;
245 
246 // Notes data (note currently used)
247 private Outbuffer *note_data;
248 private IDXSEC secidx_note;      // Final table index for note data
249 
250 // Comment data for compiler version
251 private Outbuffer *comment_data;
252 
253 // Each compiler segment is an elf section
254 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes
255 //      into SegData[]
256 //      An additionl index is reserved for comment data
257 //      New compiler segments are added to end.
258 //
259 // There doesn't seem to be any way to get reserved data space in the
260 //      same section as initialized data or code, so section offsets should
261 //      be continuous when adding data. Fix-ups anywhere withing existing data.
262 
263 enum COMD = CDATAREL+1;
264 
265 enum
266 {
267     OB_SEG_SIZ      = 10,           // initial number of segments supported
268     OB_SEG_INC      = 10,           // increment for additional segments
269 
270     OB_CODE_STR     = 100_000,      // initial size for code
271     OB_CODE_INC     = 100_000,      // increment for additional code
272     OB_DATA_STR     = 100_000,      // initial size for data
273     OB_DATA_INC     = 100_000,      // increment for additional data
274     OB_CDATA_STR    =    1024,      // initial size for data
275     OB_CDATA_INC    =    1024,      // increment for additional data
276     OB_COMD_STR     =     256,      // initial size for comments
277                                     // increment as needed
278     OB_XTRA_STR     =     250,      // initial size for extra segments
279     OB_XTRA_INC     =  10_000,      // increment size
280 }
281 
282 IDXSEC      MAP_SEG2SECIDX(int seg) { return SegData[seg].SDshtidx; }
283 extern (D)
284 IDXSYM      MAP_SEG2SYMIDX(int seg) { return SegData[seg].SDsymidx; }
285 Elf32_Shdr* MAP_SEG2SEC(int seg)    { return &SecHdrTab[MAP_SEG2SECIDX(seg)]; }
286 int         MAP_SEG2TYP(int seg)    { return MAP_SEG2SEC(seg).sh_flags & SHF_EXECINSTR ? CODE : DATA; }
287 
288 extern Rarray!(seg_data*) SegData;
289 
290 int seg_tlsseg = UNKNOWN;
291 int seg_tlsseg_bss = UNKNOWN;
292 
293 }
294 
295 
296 /*******************************
297  * Output a string into a string table
298  * Input:
299  *      strtab  =       string table for entry
300  *      str     =       string to add
301  *
302  * Returns index into the specified string table.
303  */
304 
305 IDXSTR ElfObj_addstr(Outbuffer *strtab, const(char)* str)
306 {
307     //dbg_printf("ElfObj_addstr(strtab = x%x str = '%s')\n",strtab,str);
308     IDXSTR idx = cast(IDXSTR)strtab.length();        // remember starting offset
309     strtab.writeString(str);
310     //dbg_printf("\tidx %d, new size %d\n",idx,strtab.length());
311     return idx;
312 }
313 
314 /*******************************
315  * Output a mangled string into the symbol string table
316  * Input:
317  *      str     =       string to add
318  *
319  * Returns index into the table.
320  */
321 
322 private IDXSTR elf_addmangled(Symbol *s)
323 {
324     //printf("elf_addmangled(%s)\n", s.Sident.ptr);
325     char[DEST_LEN] dest = void;
326 
327     IDXSTR namidx = cast(IDXSTR)symtab_strings.length();
328     size_t len;
329     char *destr = obj_mangle2(s, dest.ptr, &len);
330     const(char)* name = destr;
331     if (CPP && name[0] == '_' && name[1] == '_')
332     {
333         if (strncmp(name,"__ct__",6) == 0)
334         {
335             name += 4;
336             len -= 4;
337         }
338 static if (0)
339 {
340         switch(name[2])
341         {
342             case 'c':
343                 if (strncmp(name,"__ct__",6) == 0)
344                     name += 4;
345                 break;
346             case 'd':
347                 if (strcmp(name,"__dl__FvP") == 0)
348                     name = "__builtin_delete";
349                 break;
350             case 'v':
351                 //if (strcmp(name,"__vec_delete__FvPiUIPi") == 0)
352                     //name = "__builtin_vec_del";
353                 //else
354                 //if (strcmp(name,"__vn__FPUI") == 0)
355                     //name = "__builtin_vec_new";
356                 break;
357             case 'n':
358                 if (strcmp(name,"__nw__FPUI") == 0)
359                     name = "__builtin_new";
360                 break;
361 
362             default:
363                 break;
364         }
365 }
366     }
367     else if (tyfunc(s.ty()) && s.Sfunc && s.Sfunc.Fredirect)
368     {
369         name = s.Sfunc.Fredirect;
370         len = strlen(name);
371     }
372     symtab_strings.write(name, len + 1);
373     if (destr != dest.ptr)                  // if we resized result
374         mem_free(destr);
375     //dbg_printf("\telf_addmagled symtab_strings %s namidx %d len %d size %d\n",name, namidx,len,symtab_strings.length());
376     return namidx;
377 }
378 
379 /*******************************
380  * Output a symbol into the symbol table
381  * Input:
382  *      stridx  =       string table index for name
383  *      val     =       value associated with symbol
384  *      sz      =       symbol size
385  *      typ     =       symbol type
386  *      bind    =       symbol binding
387  *      sec     =       index of section where symbol is defined
388  *      visibility  =   visibility of symbol (STV_xxxx)
389  *
390  * Returns the symbol table index for the symbol
391  */
392 
393 private IDXSYM elf_addsym(IDXSTR nam, targ_size_t val, uint sz,
394                          uint typ, uint bind, IDXSEC sec,
395                          ubyte visibility = STV_DEFAULT)
396 {
397     //dbg_printf("elf_addsym(nam %d, val %d, sz %x, typ %x, bind %x, sec %d\n",
398             //nam,val,sz,typ,bind,sec);
399 
400     /* We want globally defined data symbols to have a size because
401      * zero sized symbols break copy relocations for shared libraries.
402      */
403     if(sz == 0 && (bind == STB_GLOBAL || bind == STB_WEAK) &&
404        (typ == STT_OBJECT || typ == STT_TLS) &&
405        sec != SHN_UNDEF)
406        sz = 1; // so fake it if it doesn't
407 
408     if (sec > SHN_HIRESERVE)
409     {   // If the section index is too big we need to store it as
410         // extended section header index.
411         if (!shndx_data)
412         {
413             shndx_data = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
414             assert(shndx_data);
415             shndx_data.reserve(50 * (Elf64_Word).sizeof);
416         }
417         // fill with zeros up to symbol_idx
418         const size_t shndx_idx = shndx_data.length() / Elf64_Word.sizeof;
419         shndx_data.writezeros(cast(uint)((symbol_idx - shndx_idx) * Elf64_Word.sizeof));
420 
421         shndx_data.write32(sec);
422         sec = SHN_XINDEX;
423     }
424 
425     if (I64)
426     {
427         Elf64_Sym* sym = elfobj.SymbolTable64.push();
428         sym.st_name = nam;
429         sym.st_value = val;
430         sym.st_size = sz;
431         sym.st_info = cast(ubyte)ELF64_ST_INFO(cast(ubyte)bind,cast(ubyte)typ);
432         sym.st_other = visibility;
433         sym.st_shndx = cast(ushort)sec;
434     }
435     else
436     {
437         Elf32_Sym* sym = elfobj.SymbolTable.push();
438         sym.st_name = nam;
439         sym.st_value = cast(uint)val;
440         sym.st_size = sz;
441         sym.st_info = ELF32_ST_INFO(cast(ubyte)bind,cast(ubyte)typ);
442         sym.st_other = visibility;
443         sym.st_shndx = cast(ushort)sec;
444     }
445 
446     if (bind == STB_LOCAL)
447         local_cnt++;
448     //dbg_printf("\treturning symbol table index %d\n",symbol_idx);
449     return symbol_idx++;
450 }
451 
452 /*******************************
453  * Create a new section header table entry.
454  *
455  * Input:
456  *      name    =       section name
457  *      suffix  =       suffix for name or null
458  *      type    =       type of data in section sh_type
459  *      flags   =       attribute flags sh_flags
460  * Output:
461  *      assigned number for this section
462  *      Note: Sections will be reordered on output
463  */
464 
465 private IDXSEC elf_newsection2(
466         Elf32_Word name,
467         Elf32_Word type,
468         Elf32_Word flags,
469         Elf32_Addr addr,
470         Elf32_Off offset,
471         Elf32_Word size,
472         Elf32_Word link,
473         Elf32_Word info,
474         Elf32_Word addralign,
475         Elf32_Word entsize)
476 {
477     Elf32_Shdr sec;
478 
479     sec.sh_name = name;
480     sec.sh_type = type;
481     sec.sh_flags = flags;
482     sec.sh_addr = addr;
483     sec.sh_offset = offset;
484     sec.sh_size = size;
485     sec.sh_link = link;
486     sec.sh_info = info;
487     sec.sh_addralign = addralign;
488     sec.sh_entsize = entsize;
489 
490     if (SecHdrTab.length == SHN_LORESERVE)
491     {   // insert dummy null sections to skip reserved section indices
492         foreach (i; SHN_LORESERVE .. SHN_HIRESERVE + 1)
493             SecHdrTab.push();
494         // shndx itself becomes the first section with an extended index
495         IDXSTR namidx = ElfObj_addstr(section_names, ".symtab_shndx");
496         elf_newsection2(namidx,SHT_SYMTAB_SHNDX,0,0,0,0,SHN_SYMTAB,0,4,4);
497     }
498     const si = SecHdrTab.length;
499     *SecHdrTab.push() = sec;
500     return cast(IDXSEC)si;
501 }
502 
503 /**
504 Add a new section name or get the string table index of an existing entry.
505 
506 Params:
507     name = name of section
508     suffix = append to name
509     padded = set to true when entry was newly added
510 Returns:
511     pointer to Pair, where the first field is the string index of the new or existing section name,
512     and the second field is its segment index
513  */
514 private Pair* elf_addsectionname(const(char)* name, const(char)* suffix = null, bool *padded = null)
515 {
516     IDXSTR namidx = cast(IDXSTR)section_names.length();
517     section_names.writeString(name);
518     if (suffix)
519     {   // Append suffix string
520         section_names.setsize(cast(uint)section_names.length() - 1);  // back up over terminating 0
521         section_names.writeString(suffix);
522     }
523     Pair* pidx = section_names_hashtable.get(namidx, cast(uint)section_names.length() - 1);
524     if (pidx.start)
525     {
526         // this section name already exists, remove addition
527         section_names.setsize(namidx);
528         return pidx;
529     }
530     if (padded)
531         *padded = true;
532     pidx.start = namidx;
533     return pidx;
534 }
535 
536 private IDXSEC elf_newsection(const(char)* name, const(char)* suffix,
537         Elf32_Word type, Elf32_Word flags)
538 {
539     // dbg_printf("elf_newsection(%s,%s,type %d, flags x%x)\n",
540     //        name?name:"",suffix?suffix:"",type,flags);
541     bool added = false;
542     Pair* pidx = elf_addsectionname(name, suffix, &added);
543     assert(added);
544 
545     return elf_newsection2(pidx.start,type,flags,0,0,0,0,0,0,0);
546 }
547 
548 /**************************
549  * Ouput read only data and generate a symbol for it.
550  *
551  */
552 
553 Symbol *ElfObj_sym_cdata(tym_t ty,char *p,int len)
554 {
555     Symbol *s;
556 
557 static if (0)
558 {
559     if (OPT_IS_SET(OPTfwritable_strings))
560     {
561         alignOffset(DATA, tysize(ty));
562         s = symboldata(Offset(DATA), ty);
563         SegData[DATA].SDbuf.write(p,len);
564         s.Sseg = DATA;
565         s.Soffset = Offset(DATA);   // Remember its offset into DATA section
566         Offset(DATA) += len;
567         s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
568         return s;
569     }
570 }
571 
572     //printf("ElfObj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA));
573     alignOffset(CDATA, tysize(ty));
574     s = symboldata(Offset(CDATA), ty);
575     ElfObj_bytes(CDATA, Offset(CDATA), len, p);
576     s.Sseg = CDATA;
577 
578     s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
579     return s;
580 }
581 
582 /**************************
583  * Ouput read only data for data.
584  * Output:
585  *      *pseg   segment of that data
586  * Returns:
587  *      offset of that data
588  */
589 
590 int ElfObj_data_readonly(char *p, int len, int *pseg)
591 {
592     int oldoff = cast(int)Offset(CDATA);
593     SegData[CDATA].SDbuf.reserve(len);
594     SegData[CDATA].SDbuf.writen(p,len);
595     Offset(CDATA) += len;
596     *pseg = CDATA;
597     return oldoff;
598 }
599 
600 int ElfObj_data_readonly(char *p, int len)
601 {
602     int pseg;
603 
604     return ElfObj_data_readonly(p, len, &pseg);
605 }
606 
607 /******************************
608  * Get segment for readonly string literals.
609  * The linker will pool strings in this section.
610  * Params:
611  *    sz = number of bytes per character (1, 2, or 4)
612  * Returns:
613  *    segment index
614  */
615 int ElfObj_string_literal_segment(uint sz)
616 {
617     /* Elf special sections:
618      * .rodata.strM.N - M is size of character
619      *                  N is alignment
620      * .rodata.cstN   - N fixed size readonly constants N bytes in size,
621      *              aligned to the same size
622      */
623     static immutable char[4][3] name = [ "1.1", "2.2", "4.4" ];
624     const int i = (sz == 4) ? 2 : sz - 1;
625     const IDXSEC seg =
626         ElfObj_getsegment(".rodata.str".ptr, name[i].ptr, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE | SHF_STRINGS, sz);
627     return seg;
628 }
629 
630 /******************************
631  * Perform initialization that applies to all .o output files.
632  *      Called before any other obj_xxx routines
633  */
634 
635 Obj ElfObj_init(Outbuffer *objbuf, const(char)* filename, const(char)* csegname)
636 {
637     //printf("ElfObj_init()\n");
638     Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj));
639 
640     cseg = CODE;
641     fobjbuf = objbuf;
642 
643     mapsec2sym = null;
644     note_data = null;
645     secidx_note = 0;
646     comment_data = null;
647     seg_tlsseg = UNKNOWN;
648     seg_tlsseg_bss = UNKNOWN;
649     GOTsym = null;
650 
651     // Initialize buffers
652 
653     if (symtab_strings)
654         symtab_strings.setsize(1);
655     else
656     {
657         symtab_strings = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
658         assert(symtab_strings);
659         symtab_strings.reserve(2048);
660         symtab_strings.writeByte(0);
661     }
662 
663     SecHdrTab.reset();
664 
665     enum NAMIDX : IDXSTR
666     {
667         NONE      =   0,
668         SYMTAB    =   1,    // .symtab
669         STRTAB    =   9,    // .strtab
670         SHSTRTAB  =  17,    // .shstrtab
671         TEXT      =  27,    // .text
672         DATA      =  33,    // .data
673         BSS       =  39,    // .bss
674         NOTE      =  44,    // .note
675         COMMENT   =  50,    // .comment
676         RODATA    =  59,    // .rodata
677         GNUSTACK  =  67,    // .note.GNU-stack
678         CDATAREL  =  83,    // .data.rel.ro
679         RELTEXT   =  96,    // .rel.text and .rela.text
680         RELDATA   = 106,    // .rel.data
681         RELDATA64 = 107,    // .rela.data
682     }
683 
684     if (I64)
685     {
686         static immutable char[107 + 12] section_names_init64 =
687           "\0.symtab\0.strtab\0.shstrtab\0.text\0.data\0.bss\0.note" ~
688           "\0.comment\0.rodata\0.note.GNU-stack\0.data.rel.ro\0.rela.text\0.rela.data";
689 
690         if (section_names)
691             section_names.setsize(section_names_init64.sizeof);
692         else
693         {
694             section_names = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
695             assert(section_names);
696             section_names.reserve(1024);
697             section_names.writen(section_names_init64.ptr, section_names_init64.sizeof);
698         }
699 
700         if (section_names_hashtable)
701             AApair2.destroy(section_names_hashtable);
702         section_names_hashtable = AApair2.create(&section_names.buf);
703 
704         // name,type,flags,addr,offset,size,link,info,addralign,entsize
705         elf_newsection2(0,               SHT_NULL,   0,                 0,0,0,0,0, 0,0);
706         elf_newsection2(NAMIDX.TEXT,SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,0,0,0,0,0, 4,0);
707         elf_newsection2(NAMIDX.RELTEXT,SHT_RELA, 0,0,0,0,SHN_SYMTAB,     SHN_TEXT, 8,0x18);
708         elf_newsection2(NAMIDX.DATA,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE,   0,0,0,0,0, 8,0);
709         elf_newsection2(NAMIDX.RELDATA64,SHT_RELA, 0,0,0,0,SHN_SYMTAB,   SHN_DATA, 8,0x18);
710         elf_newsection2(NAMIDX.BSS, SHT_NOBITS,SHF_ALLOC|SHF_WRITE,     0,0,0,0,0, 16,0);
711         elf_newsection2(NAMIDX.RODATA,SHT_PROGBITS,SHF_ALLOC,           0,0,0,0,0, 16,0);
712         elf_newsection2(NAMIDX.STRTAB,SHT_STRTAB, 0,                    0,0,0,0,0, 1,0);
713         elf_newsection2(NAMIDX.SYMTAB,SHT_SYMTAB, 0,                    0,0,0,0,0, 8,0);
714         elf_newsection2(NAMIDX.SHSTRTAB,SHT_STRTAB, 0,                  0,0,0,0,0, 1,0);
715         elf_newsection2(NAMIDX.COMMENT, SHT_PROGBITS,0,                 0,0,0,0,0, 1,0);
716         elf_newsection2(NAMIDX.NOTE,SHT_NOTE,   0,                      0,0,0,0,0, 1,0);
717         elf_newsection2(NAMIDX.GNUSTACK,SHT_PROGBITS,0,                 0,0,0,0,0, 1,0);
718         elf_newsection2(NAMIDX.CDATAREL,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE,0,0,0,0,0, 16,0);
719 
720         foreach (idxname; __traits(allMembers, NAMIDX)[1 .. $])
721         {
722             NAMIDX idx = mixin("NAMIDX." ~ idxname);
723             section_names_hashtable.get(idx, cast(uint)section_names_init64.sizeof).start = idx;
724         }
725     }
726     else
727     {
728         static immutable char[106 + 12] section_names_init =
729           "\0.symtab\0.strtab\0.shstrtab\0.text\0.data\0.bss\0.note" ~
730           "\0.comment\0.rodata\0.note.GNU-stack\0.data.rel.ro\0.rel.text\0.rel.data";
731 
732         if (section_names)
733             section_names.setsize(section_names_init.sizeof);
734         else
735         {
736             section_names = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
737             assert(section_names);
738             section_names.reserve(100*1024);
739             section_names.writen(section_names_init.ptr, section_names_init.sizeof);
740         }
741 
742         if (section_names_hashtable)
743             AApair2.destroy(section_names_hashtable);
744         section_names_hashtable = AApair2.create(&section_names.buf);
745 
746         // name,type,flags,addr,offset,size,link,info,addralign,entsize
747         elf_newsection2(0,               SHT_NULL,   0,                 0,0,0,0,0, 0,0);
748         elf_newsection2(NAMIDX.TEXT,SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,0,0,0,0,0, 16,0);
749         elf_newsection2(NAMIDX.RELTEXT,SHT_REL, 0,0,0,0,SHN_SYMTAB,      SHN_TEXT, 4,8);
750         elf_newsection2(NAMIDX.DATA,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE,   0,0,0,0,0, 4,0);
751         elf_newsection2(NAMIDX.RELDATA,SHT_REL, 0,0,0,0,SHN_SYMTAB,      SHN_DATA, 4,8);
752         elf_newsection2(NAMIDX.BSS, SHT_NOBITS,SHF_ALLOC|SHF_WRITE,     0,0,0,0,0, 32,0);
753         elf_newsection2(NAMIDX.RODATA,SHT_PROGBITS,SHF_ALLOC,           0,0,0,0,0, 4,0);
754         elf_newsection2(NAMIDX.STRTAB,SHT_STRTAB, 0,                    0,0,0,0,0, 1,0);
755         elf_newsection2(NAMIDX.SYMTAB,SHT_SYMTAB, 0,                    0,0,0,0,0, 4,0);
756         elf_newsection2(NAMIDX.SHSTRTAB,SHT_STRTAB, 0,                  0,0,0,0,0, 1,0);
757         elf_newsection2(NAMIDX.COMMENT, SHT_PROGBITS,0,                 0,0,0,0,0, 1,0);
758         elf_newsection2(NAMIDX.NOTE,SHT_NOTE,   0,                      0,0,0,0,0, 1,0);
759         elf_newsection2(NAMIDX.GNUSTACK,SHT_PROGBITS,0,                 0,0,0,0,0, 1,0);
760         elf_newsection2(NAMIDX.CDATAREL,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE,0,0,0,0,0, 1,0);
761 
762         foreach (idxname; __traits(allMembers, NAMIDX)[1 .. $])
763         {
764             NAMIDX idx = mixin("NAMIDX." ~ idxname);
765             section_names_hashtable.get(idx, cast(uint)section_names_init.sizeof).start = idx;
766         }
767     }
768 
769     elfobj.SymbolTable.reset();
770     elfobj.SymbolTable64.reset();
771 
772     foreach (s; elfobj.resetSyms)
773         symbol_reset(s);
774     elfobj.resetSyms.reset();
775 
776     if (shndx_data)
777         shndx_data.reset();
778     symbol_idx = 0;
779     local_cnt = 0;
780     // The symbols that every object file has
781     elf_addsym(0, 0, 0, STT_NOTYPE,  STB_LOCAL, 0);
782     elf_addsym(0, 0, 0, STT_FILE,    STB_LOCAL, SHN_ABS);       // STI_FILE
783     elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_TEXT);      // STI_TEXT
784     elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_DATA);      // STI_DATA
785     elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_BSS);       // STI_BSS
786     elf_addsym(0, 0, 0, STT_NOTYPE,  STB_LOCAL, SHN_TEXT);      // STI_GCC
787     elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_RODAT);     // STI_RODAT
788     elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_NOTE);      // STI_NOTE
789     elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_COM);       // STI_COM
790     elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_CDATAREL);  // STI_CDATAREL
791 
792     // Initialize output buffers for CODE, DATA and COMMENTS
793     //      (NOTE not supported, BSS not required)
794 
795     SegData.reset();   // recycle memory
796     SegData.push();    // element 0 is reserved
797 
798     elf_addsegment2(SHN_TEXT, STI_TEXT, SHN_RELTEXT);
799     assert(SegData[CODE].SDseg == CODE);
800 
801     elf_addsegment2(SHN_DATA, STI_DATA, SHN_RELDATA);
802     assert(SegData[DATA].SDseg == DATA);
803 
804     elf_addsegment2(SHN_RODAT, STI_RODAT, 0);
805     assert(SegData[CDATA].SDseg == CDATA);
806 
807     elf_addsegment2(SHN_BSS, STI_BSS, 0);
808     assert(SegData[UDATA].SDseg == UDATA);
809 
810     elf_addsegment2(SHN_CDATAREL, STI_CDATAREL, 0);
811     assert(SegData[CDATAREL].SDseg == CDATAREL);
812 
813     elf_addsegment2(SHN_COM, STI_COM, 0);
814     assert(SegData[COMD].SDseg == COMD);
815 
816     dwarf_initfile(filename);
817     return obj;
818 }
819 
820 /**************************
821  * Initialize the start of object output for this particular .o file.
822  *
823  * Input:
824  *      filename:       Name of source file
825  *      csegname:       User specified default code segment name
826  */
827 
828 void ElfObj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname)
829 {
830     //dbg_printf("ElfObj_initfile(filename = %s, modname = %s)\n",filename,modname);
831 
832     IDXSTR name = ElfObj_addstr(symtab_strings, filename);
833     if (I64)
834         elfobj.SymbolTable64[STI_FILE].st_name = name;
835     else
836         elfobj.SymbolTable[STI_FILE].st_name = name;
837 
838 static if (0)
839 {
840     // compiler flag for linker
841     if (I64)
842         elfobj.SymbolTable64[STI_GCC].st_name = ElfObj_addstr(symtab_strings,"gcc2_compiled.");
843     else
844         elfobj.SymbolTable[STI_GCC].st_name = ElfObj_addstr(symtab_strings,"gcc2_compiled.");
845 }
846 
847     if (csegname && *csegname && strcmp(csegname,".text"))
848     {   // Define new section and make it the default for cseg segment
849         // NOTE: cseg is initialized to CODE
850         const newsecidx = elf_newsection(csegname,null,SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR);
851         SecHdrTab[newsecidx].sh_addralign = 4;
852         SegData[cseg].SDshtidx = newsecidx;
853         SegData[cseg].SDsymidx = elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, newsecidx);
854     }
855     if (config.fulltypes)
856         dwarf_initmodule(filename, modname);
857 }
858 
859 /***************************
860  * Renumber symbols so they are
861  * ordered as locals, weak and then global
862  * Returns:
863  *      sorted symbol table, caller must free with util_free()
864  */
865 
866 void *elf_renumbersyms()
867 {   void *symtab;
868     int nextlocal = 0;
869     int nextglobal = local_cnt;
870 
871     SYMIDX *sym_map = cast(SYMIDX *)util_malloc(SYMIDX.sizeof,symbol_idx);
872 
873     if (I64)
874     {
875         Elf64_Sym *oldsymtab = &elfobj.SymbolTable64[0];
876         Elf64_Sym *symtabend = oldsymtab+symbol_idx;
877 
878         symtab = util_malloc(Elf64_Sym.sizeof,symbol_idx);
879 
880         Elf64_Sym *sl = cast(Elf64_Sym *)symtab;
881         Elf64_Sym *sg = sl + local_cnt;
882 
883         int old_idx = 0;
884         for(Elf64_Sym *s = oldsymtab; s != symtabend; s++)
885         {   // reorder symbol and map new #s to old
886             int bind = ELF64_ST_BIND(s.st_info);
887             if (bind == STB_LOCAL)
888             {
889                 *sl++ = *s;
890                 sym_map[old_idx] = nextlocal++;
891             }
892             else
893             {
894                 *sg++ = *s;
895                 sym_map[old_idx] = nextglobal++;
896             }
897             old_idx++;
898         }
899     }
900     else
901     {
902         Elf32_Sym *oldsymtab = &elfobj.SymbolTable[0];
903         Elf32_Sym *symtabend = oldsymtab+symbol_idx;
904 
905         symtab = util_malloc(Elf32_Sym.sizeof,symbol_idx);
906 
907         Elf32_Sym *sl = cast(Elf32_Sym *)symtab;
908         Elf32_Sym *sg = sl + local_cnt;
909 
910         int old_idx = 0;
911         for(Elf32_Sym *s = oldsymtab; s != symtabend; s++)
912         {   // reorder symbol and map new #s to old
913             int bind = ELF32_ST_BIND(s.st_info);
914             if (bind == STB_LOCAL)
915             {
916                 *sl++ = *s;
917                 sym_map[old_idx] = nextlocal++;
918             }
919             else
920             {
921                 *sg++ = *s;
922                 sym_map[old_idx] = nextglobal++;
923             }
924             old_idx++;
925         }
926     }
927 
928     // Reorder extended section header indices
929     if (shndx_data && shndx_data.length())
930     {
931         // fill with zeros up to symbol_idx
932         const size_t shndx_idx = shndx_data.length() / Elf64_Word.sizeof;
933         shndx_data.writezeros(cast(uint)((symbol_idx - shndx_idx) * Elf64_Word.sizeof));
934 
935         Elf64_Word *old_buf = cast(Elf64_Word *)shndx_data.buf;
936         Elf64_Word *tmp_buf = cast(Elf64_Word *)util_malloc(Elf64_Word.sizeof, symbol_idx);
937         for (SYMIDX old_idx = 0; old_idx < symbol_idx; ++old_idx)
938         {
939             const SYMIDX new_idx = sym_map[old_idx];
940             tmp_buf[new_idx] = old_buf[old_idx];
941         }
942         memcpy(old_buf, tmp_buf, Elf64_Word.sizeof * symbol_idx);
943         util_free(tmp_buf);
944     }
945 
946     // Renumber the relocations
947     for (int i = 1; i < SegData.length; i++)
948     {                           // Map indicies in the segment table
949         seg_data *pseg = SegData[i];
950         pseg.SDsymidx = cast(uint) sym_map[pseg.SDsymidx];
951 
952         if (SecHdrTab[pseg.SDshtidx].sh_type == SHT_GROUP)
953         {   // map symbol index of group section header
954             uint oidx = SecHdrTab[pseg.SDshtidx].sh_info;
955             assert(oidx < symbol_idx);
956             // we only have one symbol table
957             assert(SecHdrTab[pseg.SDshtidx].sh_link == SHN_SYMTAB);
958             SecHdrTab[pseg.SDshtidx].sh_info = cast(uint) sym_map[oidx];
959         }
960 
961         if (pseg.SDrel)
962         {
963             if (I64)
964             {
965                 Elf64_Rela *rel = cast(Elf64_Rela *) pseg.SDrel.buf;
966                 for (int r = 0; r < pseg.SDrelcnt; r++)
967                 {
968                     uint t = ELF64_R_TYPE(rel.r_info);
969                     uint si = ELF64_R_SYM(rel.r_info);
970                     assert(si < symbol_idx);
971                     rel.r_info = ELF64_R_INFO(sym_map[si],t);
972                     rel++;
973                 }
974             }
975             else
976             {
977                 Elf32_Rel *rel = cast(Elf32_Rel *) pseg.SDrel.buf;
978                 assert(pseg.SDrelcnt == pseg.SDrel.length() / Elf32_Rel.sizeof);
979                 for (int r = 0; r < pseg.SDrelcnt; r++)
980                 {
981                     uint t = ELF32_R_TYPE(rel.r_info);
982                     uint si = ELF32_R_SYM(rel.r_info);
983                     assert(si < symbol_idx);
984                     rel.r_info = ELF32_R_INFO(cast(uint) sym_map[si],t);
985                     rel++;
986                 }
987             }
988         }
989     }
990 
991     return symtab;
992 }
993 
994 
995 /***************************
996  * Fixup and terminate object file.
997  */
998 
999 void ElfObj_termfile()
1000 {
1001     //dbg_printf("ElfObj_termfile\n");
1002     if (configv.addlinenumbers)
1003     {
1004         dwarf_termmodule();
1005     }
1006 }
1007 
1008 /*********************************
1009  * Terminate package.
1010  */
1011 
1012 void ElfObj_term(const(char)* objfilename)
1013 {
1014     //printf("ElfObj_term()\n");
1015 version (SCPP)
1016 {
1017     if (!errcnt)
1018     {
1019         outfixlist();           // backpatches
1020     }
1021 }
1022 else
1023 {
1024     outfixlist();           // backpatches
1025 }
1026 
1027     if (configv.addlinenumbers)
1028     {
1029         dwarf_termfile();
1030     }
1031 
1032 version (MARS)
1033 {
1034     if (config.useModuleInfo)
1035         obj_rtinit();
1036 }
1037 
1038 version (SCPP)
1039 {
1040     if (errcnt)
1041         return;
1042 }
1043 
1044     int foffset;
1045     Elf32_Shdr *sechdr;
1046     seg_data *seg;
1047     void *symtab = elf_renumbersyms();
1048     FILE *fd = null;
1049 
1050     int hdrsize = (I64 ? Elf64_Ehdr.sizeof : Elf32_Ehdr.sizeof);
1051 
1052     ushort e_shnum;
1053     if (SecHdrTab.length < SHN_LORESERVE)
1054         e_shnum = cast(ushort)SecHdrTab.length;
1055     else
1056     {
1057         e_shnum = SHN_UNDEF;
1058         SecHdrTab[0].sh_size = cast(uint)SecHdrTab.length;
1059     }
1060     // uint16_t e_shstrndx = SHN_SECNAMES;
1061     fobjbuf.writezeros(hdrsize);
1062 
1063             // Walk through sections determining size and file offsets
1064             // Sections will be output in the following order
1065             //  Null segment
1066             //  For each Code/Data Segment
1067             //      code/data to load
1068             //      relocations without addens
1069             //  .bss
1070             //  notes
1071             //  comments
1072             //  section names table
1073             //  symbol table
1074             //  strings table
1075 
1076     foffset = hdrsize;      // start after header
1077                                     // section header table at end
1078 
1079     //
1080     // First output individual section data associate with program
1081     //  code and data
1082     //
1083     //printf("Setup offsets and sizes foffset %d\n\tSecHdrTab.length %d, SegData.length %d\n",foffset,cast(int)SecHdrTab.length,SegData.length);
1084     foreach (int i; 1 .. cast(int)SegData.length)
1085     {
1086         seg_data *pseg = SegData[i];
1087         Elf32_Shdr *sechdr2 = MAP_SEG2SEC(i);        // corresponding section
1088         if (sechdr2.sh_addralign < pseg.SDalignment)
1089             sechdr2.sh_addralign = pseg.SDalignment;
1090         foffset = elf_align(sechdr2.sh_addralign,foffset);
1091         if (i == UDATA) // 0, BSS never allocated
1092         {   // but foffset as if it has
1093             sechdr2.sh_offset = foffset;
1094             sechdr2.sh_size = cast(uint)pseg.SDoffset;
1095                                 // accumulated size
1096             continue;
1097         }
1098         else if (sechdr2.sh_type == SHT_NOBITS) // .tbss never allocated
1099         {
1100             sechdr2.sh_offset = foffset;
1101             sechdr2.sh_size = cast(uint)pseg.SDoffset;
1102                                 // accumulated size
1103             continue;
1104         }
1105         else if (!pseg.SDbuf)
1106             continue;           // For others leave sh_offset as 0
1107 
1108         sechdr2.sh_offset = foffset;
1109         //printf("\tsection name %d,",sechdr2.sh_name);
1110         if (pseg.SDbuf && pseg.SDbuf.length())
1111         {
1112             //printf(" - size %d\n",pseg.SDbuf.length());
1113             const size_t size = pseg.SDbuf.length();
1114             fobjbuf.write(pseg.SDbuf.buf, cast(uint)size);
1115             const int nfoffset = elf_align(sechdr2.sh_addralign, cast(uint)(foffset + size));
1116             sechdr2.sh_size = nfoffset - foffset;
1117             foffset = nfoffset;
1118         }
1119         //printf(" assigned offset %d, size %d\n",foffset,sechdr2.sh_size);
1120     }
1121 
1122     //
1123     // Next output any notes or comments
1124     //
1125     if (note_data)
1126     {
1127         sechdr = &SecHdrTab[secidx_note];               // Notes
1128         sechdr.sh_size = cast(uint)note_data.length();
1129         sechdr.sh_offset = foffset;
1130         fobjbuf.write(note_data.buf, sechdr.sh_size);
1131         foffset += sechdr.sh_size;
1132     }
1133 
1134     if (comment_data)
1135     {
1136         sechdr = &SecHdrTab[SHN_COM];           // Comments
1137         sechdr.sh_size = cast(uint)comment_data.length();
1138         sechdr.sh_offset = foffset;
1139         fobjbuf.write(comment_data.buf, sechdr.sh_size);
1140         foffset += sechdr.sh_size;
1141     }
1142 
1143     //
1144     // Then output string table for section names
1145     //
1146     sechdr = &SecHdrTab[SHN_SECNAMES];  // Section Names
1147     sechdr.sh_size = cast(uint)section_names.length();
1148     sechdr.sh_offset = foffset;
1149     //dbg_printf("section names offset %d\n",foffset);
1150     fobjbuf.write(section_names.buf, sechdr.sh_size);
1151     foffset += sechdr.sh_size;
1152 
1153     //
1154     // Symbol table and string table for symbols next
1155     //
1156     //dbg_printf("output symbol table size %d\n",SYMbuf.length());
1157     sechdr = &SecHdrTab[SHN_SYMTAB];    // Symbol Table
1158     sechdr.sh_size = I64 ? cast(uint)(elfobj.SymbolTable64.length * Elf64_Sym.sizeof)
1159                          : cast(uint)(elfobj.SymbolTable.length   * Elf32_Sym.sizeof);
1160     sechdr.sh_entsize = I64 ? (Elf64_Sym).sizeof : (Elf32_Sym).sizeof;
1161     sechdr.sh_link = SHN_STRINGS;
1162     sechdr.sh_info = local_cnt;
1163     foffset = elf_align(4,foffset);
1164     sechdr.sh_offset = foffset;
1165     fobjbuf.write(symtab, sechdr.sh_size);
1166     foffset += sechdr.sh_size;
1167     util_free(symtab);
1168 
1169     if (shndx_data && shndx_data.length())
1170     {
1171         assert(SecHdrTab.length >= secidx_shndx);
1172         sechdr = &SecHdrTab[secidx_shndx];
1173         sechdr.sh_size = cast(uint)shndx_data.length();
1174         sechdr.sh_offset = foffset;
1175         fobjbuf.write(shndx_data.buf, sechdr.sh_size);
1176         foffset += sechdr.sh_size;
1177     }
1178 
1179     //dbg_printf("output section strings size 0x%x,offset 0x%x\n",symtab_strings.length(),foffset);
1180     sechdr = &SecHdrTab[SHN_STRINGS];   // Symbol Strings
1181     sechdr.sh_size = cast(uint)symtab_strings.length();
1182     sechdr.sh_offset = foffset;
1183     fobjbuf.write(symtab_strings.buf, sechdr.sh_size);
1184     foffset += sechdr.sh_size;
1185 
1186     //
1187     // Now the relocation data for program code and data sections
1188     //
1189     foffset = elf_align(4,foffset);
1190     //dbg_printf("output relocations size 0x%x, foffset 0x%x\n",section_names.length(),foffset);
1191     for (int i=1; i < SegData.length; i++)
1192     {
1193         seg = SegData[i];
1194         if (!seg.SDbuf)
1195         {
1196 //            sechdr = &SecHdrTab[seg.SDrelidx];
1197 //          if (I64 && sechdr.sh_type == SHT_RELA)
1198 //              sechdr.sh_offset = foffset;
1199             continue;           // 0, BSS never allocated
1200         }
1201         if (seg.SDrel && seg.SDrel.length())
1202         {
1203             assert(seg.SDrelidx);
1204             sechdr = &SecHdrTab[seg.SDrelidx];
1205             sechdr.sh_size = cast(uint)seg.SDrel.length();
1206             sechdr.sh_offset = foffset;
1207             if (I64)
1208             {
1209                 assert(seg.SDrelcnt == seg.SDrel.length() / Elf64_Rela.sizeof);
1210 debug
1211 {
1212                 for (size_t j = 0; j < seg.SDrelcnt; ++j)
1213                 {   Elf64_Rela *p = (cast(Elf64_Rela *)seg.SDrel.buf) + j;
1214                     if (ELF64_R_TYPE(p.r_info) == R_X86_64_64)
1215                         assert(*cast(Elf64_Xword *)(seg.SDbuf.buf + p.r_offset) == 0);
1216                 }
1217 }
1218             }
1219             else
1220                 assert(seg.SDrelcnt == seg.SDrel.length() / Elf32_Rel.sizeof);
1221             fobjbuf.write(seg.SDrel.buf, sechdr.sh_size);
1222             foffset += sechdr.sh_size;
1223         }
1224     }
1225 
1226     //
1227     // Finish off with the section header table
1228     //
1229     ulong e_shoff = foffset;       // remember location in elf header
1230     //dbg_printf("output section header table\n");
1231 
1232     // Output the completed Section Header Table
1233     if (I64)
1234     {   // Translate section headers to 64 bits
1235         int sz = cast(int)(SecHdrTab.length * Elf64_Shdr.sizeof);
1236         fobjbuf.reserve(sz);
1237         foreach (ref sh; SecHdrTab)
1238         {
1239             Elf64_Shdr s;
1240             s.sh_name      = sh.sh_name;
1241             s.sh_type      = sh.sh_type;
1242             s.sh_flags     = sh.sh_flags;
1243             s.sh_addr      = sh.sh_addr;
1244             s.sh_offset    = sh.sh_offset;
1245             s.sh_size      = sh.sh_size;
1246             s.sh_link      = sh.sh_link;
1247             s.sh_info      = sh.sh_info;
1248             s.sh_addralign = sh.sh_addralign;
1249             s.sh_entsize   = sh.sh_entsize;
1250             fobjbuf.write((&s)[0 .. 1]);
1251         }
1252         foffset += sz;
1253     }
1254     else
1255     {
1256         fobjbuf.write(&SecHdrTab[0], cast(uint)(SecHdrTab.length * Elf32_Shdr.sizeof));
1257         foffset += SecHdrTab.length * Elf32_Shdr.sizeof;
1258     }
1259 
1260     //
1261     // Now that we have correct offset to section header table, e_shoff,
1262     //  go back and re-output the elf header
1263     //
1264     ubyte ELFOSABI;
1265     switch (config.exe)
1266     {
1267         case EX_LINUX:
1268         case EX_LINUX64:
1269             ELFOSABI = ELFOSABI_LINUX;
1270             break;
1271 
1272         case EX_FREEBSD:
1273         case EX_FREEBSD64:
1274             ELFOSABI = ELFOSABI_FREEBSD;
1275             break;
1276 
1277         case EX_OPENBSD:
1278         case EX_OPENBSD64:
1279             ELFOSABI = ELFOSABI_OPENBSD;
1280             break;
1281 
1282         case EX_SOLARIS:
1283         case EX_SOLARIS64:
1284         case EX_DRAGONFLYBSD64:
1285             ELFOSABI = ELFOSABI_SYSV;
1286             break;
1287 
1288         default:
1289             assert(0);
1290     }
1291 
1292     fobjbuf.position(0, hdrsize);
1293     if (I64)
1294     {
1295         __gshared Elf64_Ehdr h64 =
1296         {
1297             [
1298                 ELFMAG0,ELFMAG1,ELFMAG2,ELFMAG3,
1299                 ELFCLASS64,             // EI_CLASS
1300                 ELFDATA2LSB,            // EI_DATA
1301                 EV_CURRENT,             // EI_VERSION
1302                 0,0,                    // EI_OSABI,EI_ABIVERSION
1303                 0,0,0,0,0,0,0
1304             ],
1305             ET_REL,                         // e_type
1306             EM_X86_64,                      // e_machine
1307             EV_CURRENT,                     // e_version
1308             0,                              // e_entry
1309             0,                              // e_phoff
1310             0,                              // e_shoff
1311             0,                              // e_flags
1312             Elf64_Ehdr.sizeof,              // e_ehsize
1313             Elf64_Phdr.sizeof,              // e_phentsize
1314             0,                              // e_phnum
1315             Elf64_Shdr.sizeof,              // e_shentsize
1316             0,                              // e_shnum
1317             SHN_SECNAMES                    // e_shstrndx
1318         };
1319         h64.EHident[EI_OSABI] = ELFOSABI;
1320         h64.e_shoff     = e_shoff;
1321         h64.e_shnum     = e_shnum;
1322         fobjbuf.write(&h64, hdrsize);
1323     }
1324     else
1325     {
1326         __gshared Elf32_Ehdr h32 =
1327         {
1328             [
1329                 ELFMAG0,ELFMAG1,ELFMAG2,ELFMAG3,
1330                 ELFCLASS32,             // EI_CLASS
1331                 ELFDATA2LSB,            // EI_DATA
1332                 EV_CURRENT,             // EI_VERSION
1333                 0,0,                    // EI_OSABI,EI_ABIVERSION
1334                 0,0,0,0,0,0,0
1335             ],
1336             ET_REL,                         // e_type
1337             EM_386,                         // e_machine
1338             EV_CURRENT,                     // e_version
1339             0,                              // e_entry
1340             0,                              // e_phoff
1341             0,                              // e_shoff
1342             0,                              // e_flags
1343             Elf32_Ehdr.sizeof,              // e_ehsize
1344             Elf32_Phdr.sizeof,              // e_phentsize
1345             0,                              // e_phnum
1346             Elf32_Shdr.sizeof,              // e_shentsize
1347             0,                              // e_shnum
1348             SHN_SECNAMES                    // e_shstrndx
1349         };
1350         h32.EHident[EI_OSABI] = ELFOSABI;
1351         h32.e_shoff     = cast(uint)e_shoff;
1352         h32.e_shnum     = e_shnum;
1353         fobjbuf.write(&h32, hdrsize);
1354     }
1355     fobjbuf.position(foffset, 0);
1356 }
1357 
1358 /*****************************
1359  * Line number support.
1360  */
1361 
1362 /***************************
1363  * Record file and line number at segment and offset.
1364  * The actual .debug_line segment is put out by dwarf_termfile().
1365  * Params:
1366  *      srcpos = source file position
1367  *      seg = segment it corresponds to
1368  *      offset = offset within seg
1369  */
1370 
1371 void ElfObj_linnum(Srcpos srcpos, int seg, targ_size_t offset)
1372 {
1373     if (srcpos.Slinnum == 0)
1374         return;
1375 
1376 static if (0)
1377 {
1378     printf("ElfObj_linnum(seg=%d, offset=0x%lx) ", seg, offset);
1379     srcpos.print("");
1380 }
1381 
1382 version (MARS)
1383 {
1384     if (!srcpos.Sfilename)
1385         return;
1386 }
1387 version (SCPP)
1388 {
1389     if (!srcpos.Sfilptr)
1390         return;
1391     sfile_debug(&srcpos_sfile(srcpos));
1392     Sfile *sf = *srcpos.Sfilptr;
1393 }
1394 
1395     size_t i;
1396     seg_data *pseg = SegData[seg];
1397 
1398     // Find entry i in SDlinnum_data[] that corresponds to srcpos filename
1399     for (i = 0; 1; i++)
1400     {
1401         if (i == pseg.SDlinnum_data.length)
1402         {   // Create new entry
1403             version (MARS)
1404                 pseg.SDlinnum_data.push(linnum_data(srcpos.Sfilename));
1405             version (SCPP)
1406                 pseg.SDlinnum_data.push(linnum_data(sf));
1407             break;
1408         }
1409 version (MARS)
1410 {
1411         if (pseg.SDlinnum_data[i].filename == srcpos.Sfilename)
1412             break;
1413 }
1414 version (SCPP)
1415 {
1416         if (pseg.SDlinnum_data[i].filptr == sf)
1417             break;
1418 }
1419     }
1420 
1421     linnum_data *ld = &pseg.SDlinnum_data[i];
1422 //    printf("i = %d, ld = x%x\n", i, ld);
1423     ld.linoff.push(LinOff(srcpos.Slinnum, cast(uint)offset));
1424 }
1425 
1426 
1427 /*******************************
1428  * Set start address
1429  */
1430 
1431 void ElfObj_startaddress(Symbol *s)
1432 {
1433     //dbg_printf("ElfObj_startaddress(Symbol *%s)\n",s.Sident.ptr);
1434     //obj.startaddress = s;
1435 }
1436 
1437 /*******************************
1438  * Output library name.
1439  */
1440 
1441 bool ElfObj_includelib(const(char)* name)
1442 {
1443     //dbg_printf("ElfObj_includelib(name *%s)\n",name);
1444     return false;
1445 }
1446 
1447 /*******************************
1448 * Output linker directive.
1449 */
1450 
1451 bool ElfObj_linkerdirective(const(char)* name)
1452 {
1453     return false;
1454 }
1455 
1456 /**********************************
1457  * Do we allow zero sized objects?
1458  */
1459 
1460 bool ElfObj_allowZeroSize()
1461 {
1462     return true;
1463 }
1464 
1465 /**************************
1466  * Embed string in executable.
1467  */
1468 
1469 void ElfObj_exestr(const(char)* p)
1470 {
1471     //dbg_printf("ElfObj_exestr(char *%s)\n",p);
1472 }
1473 
1474 /**************************
1475  * Embed string in obj.
1476  */
1477 
1478 void ElfObj_user(const(char)* p)
1479 {
1480     //dbg_printf("ElfObj_user(char *%s)\n",p);
1481 }
1482 
1483 /*******************************
1484  * Output a weak extern record.
1485  */
1486 
1487 void ElfObj_wkext(Symbol *s1,Symbol *s2)
1488 {
1489     //dbg_printf("ElfObj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr);
1490 }
1491 
1492 /*******************************
1493  * Output file name record.
1494  *
1495  * Currently assumes that obj_filename will not be called
1496  *      twice for the same file.
1497  */
1498 
1499 void ElfObj_filename(const(char)* modname)
1500 {
1501     //dbg_printf("ElfObj_filename(char *%s)\n",modname);
1502     uint strtab_idx = ElfObj_addstr(symtab_strings,modname);
1503     elf_addsym(strtab_idx,0,0,STT_FILE,STB_LOCAL,SHN_ABS);
1504 }
1505 
1506 /*******************************
1507  * Embed compiler version in .obj file.
1508  */
1509 
1510 void ElfObj_compiler()
1511 {
1512     //dbg_printf("ElfObj_compiler\n");
1513     comment_data = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
1514     assert(comment_data);
1515 
1516     enum maxVersionLength = 40;  // hope enough to store `git describe --dirty`
1517     enum compilerHeader = "\0Digital Mars C/C++ ";
1518     enum n = compilerHeader.length;
1519     char[n + maxVersionLength] compiler = compilerHeader;
1520 
1521     assert(config._version.length + 1  < maxVersionLength);
1522     const newLength = n + config._version.length;
1523     compiler[n .. newLength] = config._version;
1524     compiler[newLength] = 0;
1525     comment_data.write(compiler[0 .. newLength + 1]);
1526     //dbg_printf("Comment data size %d\n",comment_data.length());
1527 }
1528 
1529 
1530 /**************************************
1531  * Symbol is the function that calls the static constructors.
1532  * Put a pointer to it into a special segment that the startup code
1533  * looks at.
1534  * Input:
1535  *      s       static constructor function
1536  *      dtor    !=0 if leave space for static destructor
1537  *      seg     1:      user
1538  *              2:      lib
1539  *              3:      compiler
1540  */
1541 
1542 void ElfObj_staticctor(Symbol *s, int, int)
1543 {
1544     ElfObj_setModuleCtorDtor(s, true);
1545 }
1546 
1547 /**************************************
1548  * Symbol is the function that calls the static destructors.
1549  * Put a pointer to it into a special segment that the exit code
1550  * looks at.
1551  * Input:
1552  *      s       static destructor function
1553  */
1554 
1555 void ElfObj_staticdtor(Symbol *s)
1556 {
1557     ElfObj_setModuleCtorDtor(s, false);
1558 }
1559 
1560 /***************************************
1561  * Stuff pointer to function in its own segment.
1562  * Used for static ctor and dtor lists.
1563  */
1564 
1565 void ElfObj_setModuleCtorDtor(Symbol *sfunc, bool isCtor)
1566 {
1567     IDXSEC seg;
1568     static if (USE_INIT_ARRAY)
1569         seg = isCtor ? ElfObj_getsegment(".init_array", null, SHT_INIT_ARRAY, SHF_ALLOC|SHF_WRITE, _tysize[TYnptr])
1570                      : ElfObj_getsegment(".fini_array", null, SHT_FINI_ARRAY, SHF_ALLOC|SHF_WRITE, _tysize[TYnptr]);
1571     else
1572         seg = ElfObj_getsegment(isCtor ? ".ctors" : ".dtors", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, _tysize[TYnptr]);
1573     const reltype_t reltype = I64 ? R_X86_64_64 : R_386_32;
1574     const size_t sz = ElfObj_writerel(seg, cast(uint)SegData[seg].SDoffset, reltype, sfunc.Sxtrnnum, 0);
1575     SegData[seg].SDoffset += sz;
1576 }
1577 
1578 
1579 /***************************************
1580  * Stuff the following data in a separate segment:
1581  *      pointer to function
1582  *      pointer to ehsym
1583  *      length of function
1584  */
1585 
1586 void ElfObj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym)
1587 {
1588     assert(0);                  // converted to Dwarf EH debug format
1589 }
1590 
1591 /*********************************************
1592  * Don't need to generate section brackets, use __start_SEC/__stop_SEC instead.
1593  */
1594 
1595 void ElfObj_ehsections()
1596 {
1597     obj_tlssections();
1598 }
1599 
1600 /*********************************************
1601  * Put out symbols that define the beginning/end of the thread local storage sections.
1602  */
1603 
1604 private void obj_tlssections()
1605 {
1606     const align_ = I64 ? 16 : 4;
1607 
1608     {
1609         const sec = ElfObj_getsegment(".tdata", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_);
1610         ElfObj_bytes(sec, 0, align_, null);
1611 
1612         const namidx = ElfObj_addstr(symtab_strings,"_tlsstart");
1613         elf_addsym(namidx, 0, align_, STT_TLS, STB_GLOBAL, MAP_SEG2SECIDX(sec));
1614     }
1615 
1616     ElfObj_getsegment(".tdata.", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_);
1617 
1618     {
1619         const sec = ElfObj_getsegment(".tcommon", null, SHT_NOBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_);
1620         const namidx = ElfObj_addstr(symtab_strings,"_tlsend");
1621         elf_addsym(namidx, 0, align_, STT_TLS, STB_GLOBAL, MAP_SEG2SECIDX(sec));
1622     }
1623 }
1624 
1625 /*********************************
1626  * Setup for Symbol s to go into a COMDAT segment.
1627  * Output (if s is a function):
1628  *      cseg            segment index of new current code segment
1629  *      Offset(cseg)         starting offset in cseg
1630  * Returns:
1631  *      "segment index" of COMDAT
1632  * References:
1633  *      Section Groups http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html#section_groups
1634  *      COMDAT section groups https://www.airs.com/blog/archives/52
1635  */
1636 
1637 private void setup_comdat(Symbol *s)
1638 {
1639     const(char)* prefix;
1640     int type;
1641     int flags;
1642     int align_ = 4;
1643 
1644     //printf("ElfObj_comdat(Symbol *%s\n",s.Sident.ptr);
1645     //symbol_print(s);
1646     symbol_debug(s);
1647     if (tyfunc(s.ty()))
1648     {
1649 static if (!ELF_COMDAT)
1650 {
1651         prefix = ".text.";              // undocumented, but works
1652         type = SHT_PROGBITS;
1653         flags = SHF_ALLOC|SHF_EXECINSTR;
1654 }
1655 else
1656 {
1657         elfobj.resetSyms.push(s);
1658 
1659         const(char)* p = cpp_mangle2(s);
1660 
1661         bool added = false;
1662         Pair* pidx = elf_addsectionname(".text.", p, &added);
1663         int groupseg;
1664         if (added)
1665         {
1666             // Create a new COMDAT section group
1667             Pair* pidx2 = elf_addsectionname(".group");
1668             groupseg = elf_addsegment(pidx2.start, SHT_GROUP, 0, (IDXSYM).sizeof);
1669             MAP_SEG2SEC(groupseg).sh_link = SHN_SYMTAB;
1670             MAP_SEG2SEC(groupseg).sh_entsize = (IDXSYM).sizeof;
1671             // Create a new TEXT section for the comdat symbol with the SHF_GROUP bit set
1672             s.Sseg = elf_addsegment(pidx.start, SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR|SHF_GROUP, align_);
1673             // add TEXT section to COMDAT section group
1674             SegData[groupseg].SDbuf.write32(GRP_COMDAT);
1675             SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(s.Sseg));
1676             SegData[s.Sseg].SDassocseg = groupseg;
1677         }
1678         else
1679         {
1680             /* If the section already existed, we've hit one of the few
1681              * occurences of different symbols with identical mangling. This should
1682              * not happen, but as a workaround we just use the existing sections.
1683              * Also see https://issues.dlang.org/show_bug.cgi?id=17352,
1684              * https://issues.dlang.org/show_bug.cgi?id=14831, and
1685              * https://issues.dlang.org/show_bug.cgi?id=17339.
1686              */
1687             if (!pidx.end)
1688                 pidx.end = elf_getsegment(pidx.start);
1689             s.Sseg = pidx.end;
1690             groupseg = SegData[s.Sseg].SDassocseg;
1691             assert(groupseg);
1692         }
1693 
1694         // Create a weak symbol for the comdat
1695         const namidxcd = ElfObj_addstr(symtab_strings, p);
1696         s.Sxtrnnum = elf_addsym(namidxcd, 0, 0, STT_FUNC, STB_WEAK, MAP_SEG2SECIDX(s.Sseg));
1697 
1698         if (added)
1699         {
1700             /* Set the weak symbol as comdat group symbol. This symbol determines
1701              * whether all or none of the sections in the group get linked. It's
1702              * also the only symbol in all group sections that might be referenced
1703              * from outside of the group.
1704              */
1705             MAP_SEG2SEC(groupseg).sh_info = s.Sxtrnnum;
1706             SegData[s.Sseg].SDsym = s;
1707         }
1708         else
1709         {
1710             // existing group symbol, and section symbol
1711             assert(MAP_SEG2SEC(groupseg).sh_info);
1712             assert(MAP_SEG2SEC(groupseg).sh_info == SegData[s.Sseg].SDsym.Sxtrnnum);
1713         }
1714         if (s.Salignment > align_)
1715             SegData[s.Sseg].SDalignment = s.Salignment;
1716         return;
1717 }
1718     }
1719     else if ((s.ty() & mTYLINK) == mTYthread)
1720     {
1721         /* Ensure that ".tdata" precedes any other .tdata. section, as the ld
1722          * linker script fails to work right.
1723          */
1724         if (I64)
1725             align_ = 16;
1726         ElfObj_getsegment(".tdata", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_);
1727 
1728         s.Sfl = FLtlsdata;
1729         prefix = ".tdata.";
1730         type = SHT_PROGBITS;
1731         flags = SHF_ALLOC|SHF_WRITE|SHF_TLS;
1732     }
1733     else
1734     {
1735         if (I64)
1736             align_ = 16;
1737         s.Sfl = FLdata;
1738         //prefix = ".gnu.linkonce.d.";
1739         prefix = ".data.";
1740         type = SHT_PROGBITS;
1741         flags = SHF_ALLOC|SHF_WRITE;
1742     }
1743 
1744     s.Sseg = ElfObj_getsegment(prefix, cpp_mangle2(s), type, flags, align_);
1745                                 // find or create new segment
1746     if (s.Salignment > align_)
1747         SegData[s.Sseg].SDalignment = s.Salignment;
1748     SegData[s.Sseg].SDsym = s;
1749 }
1750 
1751 int ElfObj_comdat(Symbol *s)
1752 {
1753     setup_comdat(s);
1754     if (s.Sfl == FLdata || s.Sfl == FLtlsdata)
1755     {
1756         ElfObj_pubdef(s.Sseg,s,0);
1757         searchfixlist(s);               // backpatch any refs to this symbol
1758     }
1759     return s.Sseg;
1760 }
1761 
1762 int ElfObj_comdatsize(Symbol *s, targ_size_t symsize)
1763 {
1764     setup_comdat(s);
1765     if (s.Sfl == FLdata || s.Sfl == FLtlsdata)
1766     {
1767         ElfObj_pubdefsize(s.Sseg,s,0,symsize);
1768         searchfixlist(s);               // backpatch any refs to this symbol
1769     }
1770     s.Soffset = 0;
1771     return s.Sseg;
1772 }
1773 
1774 int ElfObj_readonly_comdat(Symbol *s)
1775 {
1776     assert(0);
1777 }
1778 
1779 int ElfObj_jmpTableSegment(Symbol *s)
1780 {
1781     segidx_t seg = jmpseg;
1782     if (seg)                            // memoize the jmpseg on a per-function basis
1783         return seg;
1784 
1785     if (config.flags & CFGromable)
1786         seg = cseg;
1787     else
1788     {
1789         seg_data *pseg = SegData[s.Sseg];
1790         if (pseg.SDassocseg)
1791         {
1792             /* `s` is in a COMDAT, so the jmp table segment must also
1793              * go into its own segment in the same group.
1794              */
1795             seg = ElfObj_getsegment(".rodata.", s.Sident.ptr, SHT_PROGBITS, SHF_ALLOC|SHF_GROUP, _tysize[TYnptr]);
1796             addSegmentToComdat(seg, s.Sseg);
1797         }
1798         else
1799             seg = CDATA;
1800     }
1801     jmpseg = seg;
1802     return seg;
1803 }
1804 
1805 /****************************************
1806  * If `comdatseg` has a group, add `secidx` to the group.
1807  * Params:
1808  *      secidx = section to add to the group
1809  *      comdatseg = comdat that started the group
1810  */
1811 
1812 private void addSectionToComdat(IDXSEC secidx, segidx_t comdatseg)
1813 {
1814     seg_data *pseg = SegData[comdatseg];
1815     segidx_t groupseg = pseg.SDassocseg;
1816     if (groupseg)
1817     {
1818         seg_data *pgroupseg = SegData[groupseg];
1819 
1820         /* Don't write it if it is already there
1821          */
1822         Outbuffer *buf = pgroupseg.SDbuf;
1823         assert(int.sizeof == 4);               // loop depends on this
1824         for (size_t i = buf.length(); i > 4;)
1825         {
1826             /* A linear search, but shouldn't be more than 4 items
1827              * in it.
1828              */
1829             i -= 4;
1830             if (*cast(int*)(buf.buf + i) == secidx)
1831                 return;
1832         }
1833         buf.write32(secidx);
1834     }
1835 }
1836 
1837 /***********************************
1838  * Returns:
1839  *      jump table segment for function s
1840  */
1841 void addSegmentToComdat(segidx_t seg, segidx_t comdatseg)
1842 {
1843     addSectionToComdat(SegData[seg].SDshtidx, comdatseg);
1844 }
1845 
1846 private segidx_t elf_addsegment2(IDXSEC shtidx, IDXSYM symidx, IDXSEC relidx)
1847 {
1848     //printf("SegData = %p\n", SegData);
1849     const segidx_t seg = cast(segidx_t)SegData.length;
1850     seg_data** ppseg = SegData.push();
1851 
1852     seg_data* pseg = *ppseg;
1853     if (!pseg)
1854     {
1855         pseg = cast(seg_data *)mem_calloc(seg_data.sizeof);
1856         //printf("test2: SegData[%d] = %p\n", seg, SegData[seg]);
1857         SegData[seg] = pseg;
1858     }
1859     else
1860         memset(pseg, 0, seg_data.sizeof);
1861 
1862     pseg.SDseg = seg;
1863     pseg.SDshtidx = shtidx;
1864     pseg.SDoffset = 0;
1865     if (pseg.SDbuf)
1866         pseg.SDbuf.reset();
1867     else
1868     {   if (SecHdrTab[shtidx].sh_type != SHT_NOBITS)
1869         {
1870             pseg.SDbuf = cast(Outbuffer*) calloc(1, (Outbuffer).sizeof);
1871             assert(pseg.SDbuf);
1872             pseg.SDbuf.reserve(1024);
1873         }
1874     }
1875     if (pseg.SDrel)
1876         pseg.SDrel.reset();
1877     pseg.SDsymidx = symidx;
1878     pseg.SDrelidx = relidx;
1879     pseg.SDrelmaxoff = 0;
1880     pseg.SDrelindex = 0;
1881     pseg.SDrelcnt = 0;
1882     pseg.SDshtidxout = 0;
1883     pseg.SDsym = null;
1884     pseg.SDaranges_offset = 0;
1885     pseg.SDlinnum_data.reset();
1886     return seg;
1887 }
1888 
1889 /********************************
1890  * Add a new section and get corresponding seg_data entry.
1891  *
1892  * Input:
1893  *     nameidx = string index of section name
1894  *        type = section header type, e.g. SHT_PROGBITS
1895  *       flags = section header flags, e.g. SHF_ALLOC
1896  *       align_ = section alignment
1897  * Returns:
1898  *      SegData index of newly created section.
1899  */
1900 private segidx_t elf_addsegment(IDXSTR namidx, int type, int flags, int align_)
1901 {
1902     //dbg_printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf);
1903     IDXSEC shtidx = elf_newsection2(namidx,type,flags,0,0,0,0,0,0,0);
1904     SecHdrTab[shtidx].sh_addralign = align_;
1905     IDXSYM symidx = elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, shtidx);
1906     segidx_t seg = elf_addsegment2(shtidx, symidx, 0);
1907     //printf("-ElfObj_getsegment() = %d\n", seg);
1908     return seg;
1909 }
1910 
1911 /********************************
1912  * Find corresponding seg_data entry for existing section.
1913  *
1914  * Input:
1915  *     nameidx = string index of section name
1916  * Returns:
1917  *      SegData index of found section or 0 if none was found.
1918  */
1919 private int elf_getsegment(IDXSTR namidx)
1920 {
1921     // find existing section
1922     for (int seg = CODE; seg < SegData.length; seg++)
1923     {                               // should be in segment table
1924         if (MAP_SEG2SEC(seg).sh_name == namidx)
1925         {
1926             return seg;             // found section for segment
1927         }
1928     }
1929     return 0;
1930 }
1931 
1932 /********************************
1933  * Get corresponding seg_data entry for an existing or newly added section.
1934  *
1935  * Input:
1936  *        name = name of section
1937  *      suffix = append to name
1938  *        type = section header type, e.g. SHT_PROGBITS
1939  *       flags = section header flags, e.g. SHF_ALLOC
1940  *       align_ = section alignment
1941  * Returns:
1942  *      SegData index of found or newly created section.
1943  */
1944 segidx_t ElfObj_getsegment(const(char)* name, const(char)* suffix, int type, int flags,
1945         int align_)
1946 {
1947     //printf("ElfObj_getsegment(%s,%s,flags %x, align_ %d)\n",name,suffix,flags,align_);
1948     bool added = false;
1949     Pair* pidx = elf_addsectionname(name, suffix, &added);
1950     if (!added)
1951     {
1952         // Existing segment
1953         if (!pidx.end)
1954             pidx.end = elf_getsegment(pidx.start);
1955         return pidx.end;
1956     }
1957     else
1958         // New segment, cache the segment index in the hash table
1959         pidx.end = elf_addsegment(pidx.start, type, flags, align_);
1960     return pidx.end;
1961 }
1962 
1963 /**********************************
1964  * Reset code seg to existing seg.
1965  * Used after a COMDAT for a function is done.
1966  */
1967 
1968 void ElfObj_setcodeseg(int seg)
1969 {
1970     cseg = seg;
1971 }
1972 
1973 /********************************
1974  * Define a new code segment.
1975  * Input:
1976  *      name            name of segment, if null then revert to default
1977  *      suffix  0       use name as is
1978  *              1       append "_TEXT" to name
1979  * Output:
1980  *      cseg            segment index of new current code segment
1981  *      Offset(cseg)         starting offset in cseg
1982  * Returns:
1983  *      segment index of newly created code segment
1984  */
1985 
1986 int ElfObj_codeseg(const char *name,int suffix)
1987 {
1988     int seg;
1989     const(char)* sfx;
1990 
1991     //dbg_printf("ElfObj_codeseg(%s,%x)\n",name,suffix);
1992 
1993     sfx = (suffix) ? "_TEXT".ptr : null;
1994 
1995     if (!name)                          // returning to default code segment
1996     {
1997         if (cseg != CODE)               // not the current default
1998         {
1999             SegData[cseg].SDoffset = Offset(cseg);
2000             Offset(cseg) = SegData[CODE].SDoffset;
2001             cseg = CODE;
2002         }
2003         return cseg;
2004     }
2005 
2006     seg = ElfObj_getsegment(name, sfx, SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 4);
2007                                     // find or create code segment
2008 
2009     cseg = seg;                         // new code segment index
2010     Offset(cseg) = 0;
2011 
2012     return seg;
2013 }
2014 
2015 /*********************************
2016  * Define segments for Thread Local Storage.
2017  * Here's what the elf tls spec says:
2018  *      Field           .tbss                   .tdata
2019  *      sh_name         .tbss                   .tdata
2020  *      sh_type         SHT_NOBITS              SHT_PROGBITS
2021  *      sh_flags        SHF_ALLOC|SHF_WRITE|    SHF_ALLOC|SHF_WRITE|
2022  *                      SHF_TLS                 SHF_TLS
2023  *      sh_addr         virtual addr of section virtual addr of section
2024  *      sh_offset       0                       file offset of initialization image
2025  *      sh_size         size of section         size of section
2026  *      sh_link         SHN_UNDEF               SHN_UNDEF
2027  *      sh_info         0                       0
2028  *      sh_addralign    alignment of section    alignment of section
2029  *      sh_entsize      0                       0
2030  * We want _tlsstart and _tlsend to bracket all the D tls data.
2031  * The default linker script (ld -verbose) says:
2032  *  .tdata      : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
2033  *  .tbss       : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
2034  * so if we assign names:
2035  *      _tlsstart .tdata
2036  *      symbols   .tdata.
2037  *      symbols   .tbss
2038  *      _tlsend   .tbss.
2039  * this should work.
2040  * Don't care about sections emitted by other languages, as we presume they
2041  * won't be storing D gc roots in their tls.
2042  * Output:
2043  *      seg_tlsseg      set to segment number for TLS segment.
2044  * Returns:
2045  *      segment for TLS segment
2046  */
2047 
2048 seg_data *ElfObj_tlsseg()
2049 {
2050     /* Ensure that ".tdata" precedes any other .tdata. section, as the ld
2051      * linker script fails to work right.
2052      */
2053     ElfObj_getsegment(".tdata", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, 4);
2054 
2055     static immutable char[8] tlssegname = ".tdata.";
2056     //dbg_printf("ElfObj_tlsseg(\n");
2057 
2058     if (seg_tlsseg == UNKNOWN)
2059     {
2060         seg_tlsseg = ElfObj_getsegment(tlssegname.ptr, null, SHT_PROGBITS,
2061             SHF_ALLOC|SHF_WRITE|SHF_TLS, I64 ? 16 : 4);
2062     }
2063     return SegData[seg_tlsseg];
2064 }
2065 
2066 
2067 /*********************************
2068  * Define segments for Thread Local Storage.
2069  * Output:
2070  *      seg_tlsseg_bss  set to segment number for TLS segment.
2071  * Returns:
2072  *      segment for TLS segment
2073  */
2074 
2075 seg_data *ElfObj_tlsseg_bss()
2076 {
2077     static immutable char[6] tlssegname = ".tbss";
2078     //dbg_printf("ElfObj_tlsseg_bss(\n");
2079 
2080     if (seg_tlsseg_bss == UNKNOWN)
2081     {
2082         seg_tlsseg_bss = ElfObj_getsegment(tlssegname.ptr, null, SHT_NOBITS,
2083             SHF_ALLOC|SHF_WRITE|SHF_TLS, I64 ? 16 : 4);
2084     }
2085     return SegData[seg_tlsseg_bss];
2086 }
2087 
2088 seg_data *ElfObj_tlsseg_data()
2089 {
2090     // specific for Mach-O
2091     assert(0);
2092 }
2093 
2094 
2095 /*******************************
2096  * Output an alias definition record.
2097  */
2098 
2099 void ElfObj_alias(const(char)* n1,const(char)* n2)
2100 {
2101     //printf("ElfObj_alias(%s,%s)\n",n1,n2);
2102     assert(0);
2103 static if (0)
2104 {
2105     char *buffer = cast(char *) alloca(strlen(n1) + strlen(n2) + 2 * ONS_OHD);
2106     uint len = obj_namestring(buffer,n1);
2107     len += obj_namestring(buffer + len,n2);
2108     objrecord(ALIAS,buffer,len);
2109 }
2110 }
2111 
2112 private extern (D) char* unsstr(uint value)
2113 {
2114     __gshared char[64] buffer = void;
2115 
2116     sprintf(buffer.ptr, "%d", value);
2117     return buffer.ptr;
2118 }
2119 
2120 /*******************************
2121  * Mangle a name.
2122  * Returns:
2123  *      mangled name
2124  */
2125 
2126 private extern (D)
2127 char *obj_mangle2(Symbol *s,char *dest, size_t *destlen)
2128 {
2129     char *name;
2130 
2131     //dbg_printf("ElfObj_mangle('%s'), mangle = x%x\n",s.Sident.ptr,type_mangle(s.Stype));
2132     symbol_debug(s);
2133     assert(dest);
2134 
2135 version (SCPP)
2136     name = CPP ? cpp_mangle2(s) : s.Sident.ptr;
2137 else version (MARS)
2138     // C++ name mangling is handled by front end
2139     name = s.Sident.ptr;
2140 else
2141     name = s.Sident.ptr;
2142 
2143     size_t len = strlen(name);                 // # of bytes in name
2144     //dbg_printf("len %d\n",len);
2145     switch (type_mangle(s.Stype))
2146     {
2147         case mTYman_pas:                // if upper case
2148         case mTYman_for:
2149             if (len >= DEST_LEN)
2150                 dest = cast(char *)mem_malloc(len + 1);
2151             memcpy(dest,name,len + 1);  // copy in name and ending 0
2152             for (int i = 0; 1; i++)
2153             {   char c = dest[i];
2154                 if (!c)
2155                     break;
2156                 if (c >= 'a' && c <= 'z')
2157                     dest[i] = cast(char)(c + 'A' - 'a');
2158             }
2159             break;
2160         case mTYman_std:
2161         {
2162             bool cond = (tyfunc(s.ty()) && !variadic(s.Stype));
2163             if (cond)
2164             {
2165                 char *pstr = unsstr(type_paramsize(s.Stype));
2166                 size_t pstrlen = strlen(pstr);
2167                 size_t dlen = len + 1 + pstrlen;
2168 
2169                 if (dlen >= DEST_LEN)
2170                     dest = cast(char *)mem_malloc(dlen + 1);
2171                 memcpy(dest,name,len);
2172                 dest[len] = '@';
2173                 memcpy(dest + 1 + len, pstr, pstrlen + 1);
2174                 len = dlen;
2175                 break;
2176             }
2177         }
2178             goto case;
2179 
2180         case mTYman_cpp:
2181         case mTYman_c:
2182         case mTYman_d:
2183         case mTYman_sys:
2184         case 0:
2185             if (len >= DEST_LEN)
2186                 dest = cast(char *)mem_malloc(len + 1);
2187             memcpy(dest,name,len+1);// copy in name and trailing 0
2188             break;
2189 
2190         default:
2191 debug
2192 {
2193             printf("mangling %x\n",type_mangle(s.Stype));
2194             symbol_print(s);
2195 }
2196             printf("%d\n", type_mangle(s.Stype));
2197             assert(0);
2198     }
2199     //dbg_printf("\t %s\n",dest);
2200     *destlen = len;
2201     return dest;
2202 }
2203 
2204 /*******************************
2205  * Export a function name.
2206  */
2207 
2208 void ElfObj_export_symbol(Symbol *s,uint argsize)
2209 {
2210     //dbg_printf("ElfObj_export_symbol(%s,%d)\n",s.Sident.ptr,argsize);
2211 }
2212 
2213 /*******************************
2214  * Update data information about symbol
2215  *      align for output and assign segment
2216  *      if not already specified.
2217  *
2218  * Input:
2219  *      sdata           data symbol
2220  *      datasize        output size
2221  *      seg             default seg if not known
2222  * Returns:
2223  *      actual seg
2224  */
2225 
2226 int ElfObj_data_start(Symbol *sdata, targ_size_t datasize, int seg)
2227 {
2228     targ_size_t alignbytes;
2229     //printf("ElfObj_data_start(%s,size %llx,seg %d)\n",sdata.Sident.ptr,datasize,seg);
2230     //symbol_print(sdata);
2231 
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         ElfObj_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 ElfObj_func_start(Symbol *sfunc)
2258 {
2259     //dbg_printf("ElfObj_func_start(%s)\n",sfunc.Sident.ptr);
2260     symbol_debug(sfunc);
2261 
2262     if ((tybasic(sfunc.ty()) == TYmfunc) && (sfunc.Sclass == SCextern))
2263     {                                   // create a new code segment
2264         sfunc.Sseg =
2265             ElfObj_getsegment(".gnu.linkonce.t.", cpp_mangle2(sfunc), SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR,4);
2266 
2267     }
2268     else if (sfunc.Sseg == UNKNOWN)
2269         sfunc.Sseg = CODE;
2270     //dbg_printf("sfunc.Sseg %d CODE %d cseg %d Coffset %d\n",sfunc.Sseg,CODE,cseg,Offset(cseg));
2271     cseg = sfunc.Sseg;
2272     jmpseg = 0;                         // only 1 jmp seg per function
2273     assert(cseg == CODE || cseg > COMD);
2274 static if (ELF_COMDAT)
2275 {
2276     if (!symbol_iscomdat2(sfunc))
2277     {
2278         ElfObj_pubdef(cseg, sfunc, Offset(cseg));
2279     }
2280 }
2281 else
2282 {
2283     ElfObj_pubdef(cseg, sfunc, Offset(cseg));
2284 }
2285     sfunc.Soffset = Offset(cseg);
2286 
2287     dwarf_func_start(sfunc);
2288 }
2289 
2290 /*******************************
2291  * Update function info after codgen
2292  */
2293 
2294 void ElfObj_func_term(Symbol *sfunc)
2295 {
2296     //dbg_printf("ElfObj_func_term(%s) offset %x, Coffset %x symidx %d\n",
2297 //          sfunc.Sident.ptr, sfunc.Soffset,Offset(cseg),sfunc.Sxtrnnum);
2298 
2299     // fill in the function size
2300     if (I64)
2301         elfobj.SymbolTable64[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset;
2302     else
2303         elfobj.SymbolTable[sfunc.Sxtrnnum].st_size = cast(uint)(Offset(cseg) - sfunc.Soffset);
2304     dwarf_func_term(sfunc);
2305 }
2306 
2307 /********************************
2308  * Output a public definition.
2309  * Input:
2310  *      seg =           segment index that symbol is defined in
2311  *      s .            symbol
2312  *      offset =        offset of name within segment
2313  */
2314 
2315 void ElfObj_pubdef(int seg, Symbol *s, targ_size_t offset)
2316 {
2317     const targ_size_t symsize=
2318         tyfunc(s.ty()) ? Offset(s.Sseg) - offset : type_size(s.Stype);
2319     ElfObj_pubdefsize(seg, s, offset, symsize);
2320 }
2321 
2322 /********************************
2323  * Output a public definition.
2324  * Input:
2325  *      seg =           segment index that symbol is defined in
2326  *      s .            symbol
2327  *      offset =        offset of name within segment
2328  *      symsize         size of symbol
2329  */
2330 
2331 void ElfObj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize)
2332 {
2333     int bind;
2334     ubyte visibility = STV_DEFAULT;
2335     switch (s.Sclass)
2336     {
2337         case SCglobal:
2338         case SCinline:
2339             bind = STB_GLOBAL;
2340             break;
2341         case SCcomdat:
2342         case SCcomdef:
2343             bind = STB_WEAK;
2344             break;
2345         case SCstatic:
2346             if (s.Sflags & SFLhidden)
2347             {
2348                 visibility = STV_HIDDEN;
2349                 bind = STB_GLOBAL;
2350                 break;
2351             }
2352             goto default;
2353 
2354         default:
2355             bind = STB_LOCAL;
2356             break;
2357     }
2358 
2359     //printf("\nElfObj_pubdef(%d,%s,%d)\n",seg,s.Sident.ptr,offset);
2360     //symbol_print(s);
2361 
2362     symbol_debug(s);
2363     elfobj.resetSyms.push(s);
2364     const namidx = elf_addmangled(s);
2365     //printf("\tnamidx %d,section %d\n",namidx,MAP_SEG2SECIDX(seg));
2366     if (tyfunc(s.ty()))
2367     {
2368         s.Sxtrnnum = elf_addsym(namidx, offset, cast(uint)symsize,
2369             STT_FUNC, bind, MAP_SEG2SECIDX(seg), visibility);
2370     }
2371     else
2372     {
2373         const uint typ = (s.ty() & mTYthread) ? STT_TLS : STT_OBJECT;
2374         s.Sxtrnnum = elf_addsym(namidx, offset, cast(uint)symsize,
2375             typ, bind, MAP_SEG2SECIDX(seg), visibility);
2376     }
2377 }
2378 
2379 /*******************************
2380  * Output an external symbol for name.
2381  * Input:
2382  *      name    Name to do EXTDEF on
2383  *              (Not to be mangled)
2384  * Returns:
2385  *      Symbol table index of the definition
2386  *      NOTE: Numbers will not be linear.
2387  */
2388 
2389 int ElfObj_external_def(const(char)* name)
2390 {
2391     //dbg_printf("ElfObj_external_def('%s')\n",name);
2392     assert(name);
2393     const namidx = ElfObj_addstr(symtab_strings,name);
2394     const symidx = elf_addsym(namidx, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF);
2395     return symidx;
2396 }
2397 
2398 
2399 /*******************************
2400  * Output an external for existing symbol.
2401  * Input:
2402  *      s       Symbol to do EXTDEF on
2403  *              (Name is to be mangled)
2404  * Returns:
2405  *      Symbol table index of the definition
2406  *      NOTE: Numbers will not be linear.
2407  */
2408 
2409 int ElfObj_external(Symbol *s)
2410 {
2411     int symtype,sectype;
2412     uint size;
2413 
2414     //dbg_printf("ElfObj_external('%s') %x\n",s.Sident.ptr,s.Svalue);
2415     symbol_debug(s);
2416     elfobj.resetSyms.push(s);
2417     const namidx = elf_addmangled(s);
2418 
2419 version (SCPP)
2420 {
2421     if (s.Sscope && !tyfunc(s.ty()))
2422     {
2423         symtype = STT_OBJECT;
2424         sectype = SHN_COMMON;
2425         size = type_size(s.Stype);
2426     }
2427     else
2428     {
2429         symtype = STT_NOTYPE;
2430         sectype = SHN_UNDEF;
2431         size = 0;
2432     }
2433 }
2434 else
2435 {
2436     symtype = STT_NOTYPE;
2437     sectype = SHN_UNDEF;
2438     size = 0;
2439 }
2440     if (s.ty() & mTYthread)
2441     {
2442         //printf("ElfObj_external('%s') %x TLS\n",s.Sident.ptr,s.Svalue);
2443         symtype = STT_TLS;
2444     }
2445 
2446     s.Sxtrnnum = elf_addsym(namidx, size, size, symtype,
2447         /*(s.ty() & mTYweak) ? STB_WEAK : */STB_GLOBAL, sectype);
2448     return s.Sxtrnnum;
2449 
2450 }
2451 
2452 /*******************************
2453  * Output a common block definition.
2454  * Input:
2455  *      p .    external identifier
2456  *      size    size in bytes of each elem
2457  *      count   number of elems
2458  * Returns:
2459  *      Symbol table index for symbol
2460  */
2461 
2462 int ElfObj_common_block(Symbol *s,targ_size_t size,targ_size_t count)
2463 {
2464     //printf("ElfObj_common_block('%s',%d,%d)\n",s.Sident.ptr,size,count);
2465     symbol_debug(s);
2466 
2467     int align_ = I64 ? 16 : 4;
2468     if (s.ty() & mTYthread)
2469     {
2470         s.Sseg = ElfObj_getsegment(".tbss.", cpp_mangle2(s),
2471                 SHT_NOBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_);
2472         s.Sfl = FLtlsdata;
2473         SegData[s.Sseg].SDsym = s;
2474         SegData[s.Sseg].SDoffset += size * count;
2475         ElfObj_pubdefsize(s.Sseg, s, 0, size * count);
2476         searchfixlist(s);
2477         return s.Sseg;
2478     }
2479     else
2480     {
2481         s.Sseg = ElfObj_getsegment(".bss.", cpp_mangle2(s),
2482                 SHT_NOBITS, SHF_ALLOC|SHF_WRITE, align_);
2483         s.Sfl = FLudata;
2484         SegData[s.Sseg].SDsym = s;
2485         SegData[s.Sseg].SDoffset += size * count;
2486         ElfObj_pubdefsize(s.Sseg, s, 0, size * count);
2487         searchfixlist(s);
2488         return s.Sseg;
2489     }
2490 static if (0)
2491 {
2492     elfobj.resetSyms.push(s);
2493     const namidx = elf_addmangled(s);
2494     alignOffset(UDATA,size);
2495     const symidx = elf_addsym(namidx, SegData[UDATA].SDoffset, size*count,
2496                    (s.ty() & mTYthread) ? STT_TLS : STT_OBJECT,
2497                    STB_WEAK, SHN_BSS);
2498     //dbg_printf("\tElfObj_common_block returning symidx %d\n",symidx);
2499     s.Sseg = UDATA;
2500     s.Sfl = FLudata;
2501     SegData[UDATA].SDoffset += size * count;
2502     return symidx;
2503 }
2504 }
2505 
2506 int ElfObj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count)
2507 {
2508     return ElfObj_common_block(s, size, count);
2509 }
2510 
2511 /***************************************
2512  * Append an iterated data block of 0s.
2513  * (uninitialized data only)
2514  */
2515 
2516 void ElfObj_write_zeros(seg_data *pseg, targ_size_t count)
2517 {
2518     ElfObj_lidata(pseg.SDseg, pseg.SDoffset, count);
2519 }
2520 
2521 /***************************************
2522  * Output an iterated data block of 0s.
2523  *
2524  *      For boundary alignment and initialization
2525  */
2526 
2527 void ElfObj_lidata(int seg,targ_size_t offset,targ_size_t count)
2528 {
2529     //printf("ElfObj_lidata(%d,%x,%d)\n",seg,offset,count);
2530     if (seg == UDATA || seg == UNKNOWN)
2531     {   // Use SDoffset to record size of .BSS section
2532         SegData[UDATA].SDoffset += count;
2533     }
2534     else if (MAP_SEG2SEC(seg).sh_type == SHT_NOBITS)
2535     {   // Use SDoffset to record size of .TBSS section
2536         SegData[seg].SDoffset += count;
2537     }
2538     else
2539     {
2540         ElfObj_bytes(seg, offset, cast(uint)count, null);
2541     }
2542 }
2543 
2544 /***********************************
2545  * Append byte to segment.
2546  */
2547 
2548 void ElfObj_write_byte(seg_data *pseg, uint byte_)
2549 {
2550     ElfObj_byte(pseg.SDseg, pseg.SDoffset, byte_);
2551 }
2552 
2553 /************************************
2554  * Output byte to object file.
2555  */
2556 
2557 void ElfObj_byte(int seg,targ_size_t offset,uint byte_)
2558 {
2559     Outbuffer *buf = SegData[seg].SDbuf;
2560     int save = cast(int)buf.length();
2561     //dbg_printf("ElfObj_byte(seg=%d, offset=x%lx, byte_=x%x)\n",seg,offset,byte_);
2562     buf.setsize(cast(uint)offset);
2563     buf.writeByte(byte_);
2564     if (save > offset+1)
2565         buf.setsize(save);
2566     else
2567         SegData[seg].SDoffset = offset+1;
2568     //dbg_printf("\tsize now %d\n",buf.length());
2569 }
2570 
2571 /***********************************
2572  * Append bytes to segment.
2573  */
2574 
2575 void ElfObj_write_bytes(seg_data *pseg, uint nbytes, void *p)
2576 {
2577     ElfObj_bytes(pseg.SDseg, pseg.SDoffset, nbytes, p);
2578 }
2579 
2580 /************************************
2581  * Output bytes to object file.
2582  * Returns:
2583  *      nbytes
2584  */
2585 
2586 uint ElfObj_bytes(int seg, targ_size_t offset, uint nbytes, void *p)
2587 {
2588 static if (0)
2589 {
2590     if (!(seg >= 0 && seg < SegData.length))
2591     {   printf("ElfObj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length);
2592         *cast(char*)0=0;
2593     }
2594 }
2595     assert(seg >= 0 && seg < SegData.length);
2596     Outbuffer *buf = SegData[seg].SDbuf;
2597     if (buf == null)
2598     {
2599         //dbg_printf("ElfObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n", seg, offset, nbytes, p);
2600         //raise(SIGSEGV);
2601         assert(buf != null);
2602     }
2603     int save = cast(int)buf.length();
2604     //dbg_printf("ElfObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n",
2605             //seg,offset,nbytes,p);
2606     buf.position(cast(size_t)offset, nbytes);
2607     if (p)
2608         buf.writen(p, nbytes);
2609     else // Zero out the bytes
2610         buf.writezeros(nbytes);
2611 
2612     if (save > offset+nbytes)
2613         buf.setsize(save);
2614     else
2615         SegData[seg].SDoffset = offset+nbytes;
2616     return nbytes;
2617 }
2618 
2619 /*******************************
2620  * Output a relocation entry for a segment
2621  * Input:
2622  *      seg =           where the address is going
2623  *      offset =        offset within seg
2624  *      type =          ELF relocation type R_ARCH_XXXX
2625  *      index =         Related symbol table index
2626  *      val =           addend or displacement from address
2627  */
2628 
2629 __gshared int relcnt=0;
2630 
2631 void ElfObj_addrel(int seg, targ_size_t offset, uint type,
2632                     IDXSYM symidx, targ_size_t val)
2633 {
2634     seg_data *segdata;
2635     Outbuffer *buf;
2636     IDXSEC secidx;
2637 
2638     //assert(val == 0);
2639     relcnt++;
2640     //dbg_printf("%d-ElfObj_addrel(seg %d,offset x%x,type x%x,symidx %d,val %d)\n",
2641             //relcnt,seg, offset, type, symidx,val);
2642 
2643     assert(seg >= 0 && seg < SegData.length);
2644     segdata = SegData[seg];
2645     secidx = MAP_SEG2SECIDX(seg);
2646     assert(secidx != 0);
2647 
2648     if (segdata.SDrel == null)
2649     {
2650         segdata.SDrel = cast(Outbuffer*) calloc(1, (Outbuffer).sizeof);
2651         assert(segdata.SDrel);
2652     }
2653 
2654     if (segdata.SDrel.length() == 0)
2655     {   IDXSEC relidx;
2656 
2657         if (secidx == SHN_TEXT)
2658             relidx = SHN_RELTEXT;
2659         else if (secidx == SHN_DATA)
2660             relidx = SHN_RELDATA;
2661         else
2662         {
2663             // Get the section name, and make a copy because
2664             // elf_newsection() may reallocate the string buffer.
2665             char *section_name = cast(char *)GET_SECTION_NAME(secidx);
2666             size_t len = strlen(section_name) + 1;
2667             char[20] buf2 = void;
2668             char *p = len <= buf2.sizeof ? &buf2[0] : cast(char *)malloc(len);
2669             assert(p);
2670             memcpy(p, section_name, len);
2671 
2672             relidx = elf_newsection(I64 ? ".rela" : ".rel", p, I64 ? SHT_RELA : SHT_REL, 0);
2673             if (p != &buf2[0])
2674                 free(p);
2675             segdata.SDrelidx = relidx;
2676             addSectionToComdat(relidx,seg);
2677         }
2678 
2679         if (I64)
2680         {
2681             /* Note that we're using Elf32_Shdr here instead of Elf64_Shdr. This is to make
2682              * the code a bit simpler. In ElfObj_term(), we translate the Elf32_Shdr into the proper
2683              * Elf64_Shdr.
2684              */
2685             Elf32_Shdr *relsec = &SecHdrTab[relidx];
2686             relsec.sh_link = SHN_SYMTAB;
2687             relsec.sh_info = secidx;
2688             relsec.sh_entsize = Elf64_Rela.sizeof;
2689             relsec.sh_addralign = 8;
2690         }
2691         else
2692         {
2693             Elf32_Shdr *relsec = &SecHdrTab[relidx];
2694             relsec.sh_link = SHN_SYMTAB;
2695             relsec.sh_info = secidx;
2696             relsec.sh_entsize = Elf32_Rel.sizeof;
2697             relsec.sh_addralign = 4;
2698         }
2699     }
2700 
2701     if (I64)
2702     {
2703         Elf64_Rela rel;
2704         rel.r_offset = offset;          // build relocation information
2705         rel.r_info = ELF64_R_INFO(symidx,type);
2706         rel.r_addend = val;
2707         buf = segdata.SDrel;
2708         buf.write(&rel,(rel).sizeof);
2709         segdata.SDrelcnt++;
2710 
2711         if (offset >= segdata.SDrelmaxoff)
2712             segdata.SDrelmaxoff = offset;
2713         else
2714         {   // insert numerically
2715             Elf64_Rela *relbuf = cast(Elf64_Rela *)buf.buf;
2716             int i = relbuf[segdata.SDrelindex].r_offset > offset ? 0 : segdata.SDrelindex;
2717             while (i < segdata.SDrelcnt)
2718             {
2719                 if (relbuf[i].r_offset > offset)
2720                     break;
2721                 i++;
2722             }
2723             assert(i != segdata.SDrelcnt);     // slide greater offsets down
2724             memmove(relbuf+i+1,relbuf+i,Elf64_Rela.sizeof * (segdata.SDrelcnt - i - 1));
2725             *(relbuf+i) = rel;          // copy to correct location
2726             segdata.SDrelindex = i;    // next entry usually greater
2727         }
2728     }
2729     else
2730     {
2731         Elf32_Rel rel;
2732         rel.r_offset = cast(uint)offset;          // build relocation information
2733         rel.r_info = ELF32_R_INFO(symidx,type);
2734         buf = segdata.SDrel;
2735         buf.write(&rel,rel.sizeof);
2736         segdata.SDrelcnt++;
2737 
2738         if (offset >= segdata.SDrelmaxoff)
2739             segdata.SDrelmaxoff = offset;
2740         else
2741         {   // insert numerically
2742             Elf32_Rel *relbuf = cast(Elf32_Rel *)buf.buf;
2743             int i = relbuf[segdata.SDrelindex].r_offset > offset ? 0 : segdata.SDrelindex;
2744             while (i < segdata.SDrelcnt)
2745             {
2746                 if (relbuf[i].r_offset > offset)
2747                     break;
2748                 i++;
2749             }
2750             assert(i != segdata.SDrelcnt);     // slide greater offsets down
2751             memmove(relbuf+i+1,relbuf+i,Elf32_Rel.sizeof * (segdata.SDrelcnt - i - 1));
2752             *(relbuf+i) = rel;          // copy to correct location
2753             segdata.SDrelindex = i;    // next entry usually greater
2754         }
2755     }
2756 }
2757 
2758 private size_t relsize64(uint type)
2759 {
2760     assert(I64);
2761     switch (type)
2762     {
2763         case R_X86_64_NONE:      return 0;
2764         case R_X86_64_64:        return 8;
2765         case R_X86_64_PC32:      return 4;
2766         case R_X86_64_GOT32:     return 4;
2767         case R_X86_64_PLT32:     return 4;
2768         case R_X86_64_COPY:      return 0;
2769         case R_X86_64_GLOB_DAT:  return 8;
2770         case R_X86_64_JUMP_SLOT: return 8;
2771         case R_X86_64_RELATIVE:  return 8;
2772         case R_X86_64_GOTPCREL:  return 4;
2773         case R_X86_64_32:        return 4;
2774         case R_X86_64_32S:       return 4;
2775         case R_X86_64_16:        return 2;
2776         case R_X86_64_PC16:      return 2;
2777         case R_X86_64_8:         return 1;
2778         case R_X86_64_PC8:       return 1;
2779         case R_X86_64_DTPMOD64:  return 8;
2780         case R_X86_64_DTPOFF64:  return 8;
2781         case R_X86_64_TPOFF64:   return 8;
2782         case R_X86_64_TLSGD:     return 4;
2783         case R_X86_64_TLSLD:     return 4;
2784         case R_X86_64_DTPOFF32:  return 4;
2785         case R_X86_64_GOTTPOFF:  return 4;
2786         case R_X86_64_TPOFF32:   return 4;
2787         case R_X86_64_PC64:      return 8;
2788         case R_X86_64_GOTOFF64:  return 8;
2789         case R_X86_64_GOTPC32:   return 4;
2790 
2791         default:
2792             assert(0);
2793     }
2794 }
2795 
2796 private size_t relsize32(uint type)
2797 {
2798     assert(I32);
2799     switch (type)
2800     {
2801         case R_386_NONE:         return 0;
2802         case R_386_32:           return 4;
2803         case R_386_PC32:         return 4;
2804         case R_386_GOT32:        return 4;
2805         case R_386_PLT32:        return 4;
2806         case R_386_COPY:         return 0;
2807         case R_386_GLOB_DAT:     return 4;
2808         case R_386_JMP_SLOT:     return 4;
2809         case R_386_RELATIVE:     return 4;
2810         case R_386_GOTOFF:       return 4;
2811         case R_386_GOTPC:        return 4;
2812         case R_386_TLS_TPOFF:    return 4;
2813         case R_386_TLS_IE:       return 4;
2814         case R_386_TLS_GOTIE:    return 4;
2815         case R_386_TLS_LE:       return 4;
2816         case R_386_TLS_GD:       return 4;
2817         case R_386_TLS_LDM:      return 4;
2818         case R_386_TLS_GD_32:    return 4;
2819         case R_386_TLS_GD_PUSH:  return 4;
2820         case R_386_TLS_GD_CALL:  return 4;
2821         case R_386_TLS_GD_POP:   return 4;
2822         case R_386_TLS_LDM_32:   return 4;
2823         case R_386_TLS_LDM_PUSH: return 4;
2824         case R_386_TLS_LDM_CALL: return 4;
2825         case R_386_TLS_LDM_POP:  return 4;
2826         case R_386_TLS_LDO_32:   return 4;
2827         case R_386_TLS_IE_32:    return 4;
2828         case R_386_TLS_LE_32:    return 4;
2829         case R_386_TLS_DTPMOD32: return 4;
2830         case R_386_TLS_DTPOFF32: return 4;
2831         case R_386_TLS_TPOFF32:  return 4;
2832 
2833         default:
2834             assert(0);
2835     }
2836 }
2837 
2838 /*******************************
2839  * Write/Append a value to the given segment and offset.
2840  *      targseg =       the target segment for the relocation
2841  *      offset =        offset within target segment
2842  *      val =           addend or displacement from symbol
2843  *      size =          number of bytes to write
2844  */
2845 private size_t writeaddrval(int targseg, size_t offset, targ_size_t val, size_t size)
2846 {
2847     assert(targseg >= 0 && targseg < SegData.length);
2848 
2849     Outbuffer *buf = SegData[targseg].SDbuf;
2850     const save = buf.length();
2851     buf.setsize(cast(uint)offset);
2852     buf.write(&val, cast(uint)size);
2853     // restore Outbuffer position
2854     if (save > offset + size)
2855         buf.setsize(cast(uint)save);
2856     return size;
2857 }
2858 
2859 /*******************************
2860  * Write/Append a relocatable value to the given segment and offset.
2861  * Input:
2862  *      targseg =       the target segment for the relocation
2863  *      offset =        offset within target segment
2864  *      reltype =       ELF relocation type R_ARCH_XXXX
2865  *      symidx =        symbol base for relocation
2866  *      val =           addend or displacement from symbol
2867  */
2868 size_t ElfObj_writerel(int targseg, size_t offset, reltype_t reltype,
2869                         IDXSYM symidx, targ_size_t val)
2870 {
2871     assert(reltype != R_X86_64_NONE);
2872 
2873     size_t sz;
2874     if (I64)
2875     {
2876         // Elf64_Rela stores addend in Rela.r_addend field
2877         sz = relsize64(reltype);
2878         writeaddrval(targseg, offset, 0, sz);
2879         ElfObj_addrel(targseg, offset, reltype, symidx, val);
2880     }
2881     else
2882     {
2883         assert(I32);
2884         // Elf32_Rel stores addend in target location
2885         sz = relsize32(reltype);
2886         writeaddrval(targseg, offset, val, sz);
2887         ElfObj_addrel(targseg, offset, reltype, symidx, 0);
2888     }
2889     return sz;
2890 }
2891 
2892 /*******************************
2893  * Refer to address that is in the data segment.
2894  * Input:
2895  *      seg =           where the address is going
2896  *      offset =        offset within seg
2897  *      val =           displacement from address
2898  *      targetdatum =   DATA, CDATA or UDATA, depending where the address is
2899  *      flags =         CFoff, CFseg, CFoffset64, CFswitch
2900  * Example:
2901  *      int *abc = &def[3];
2902  *      to allocate storage:
2903  *              ElfObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA);
2904  * Note:
2905  *      For I64 && (flags & CFoffset64) && (flags & CFswitch)
2906  *      targetdatum is a symidx rather than a segment.
2907  */
2908 
2909 void ElfObj_reftodatseg(int seg,targ_size_t offset,targ_size_t val,
2910         uint targetdatum,int flags)
2911 {
2912 static if (0)
2913 {
2914     printf("ElfObj_reftodatseg(seg=%d, offset=x%llx, val=x%llx,data %x, flags %x)\n",
2915         seg,cast(ulong)offset,cast(ulong)val,targetdatum,flags);
2916 }
2917 
2918     reltype_t relinfo;
2919     IDXSYM targetsymidx = STI_RODAT;
2920     if (I64)
2921     {
2922 
2923         if (flags & CFoffset64)
2924         {
2925             relinfo = R_X86_64_64;
2926             if (flags & CFswitch) targetsymidx = targetdatum;
2927         }
2928         else if (flags & CFswitch)
2929         {
2930             relinfo = R_X86_64_PC32;
2931             targetsymidx = MAP_SEG2SYMIDX(targetdatum);
2932         }
2933         else if (MAP_SEG2TYP(seg) == CODE && config.flags3 & CFG3pic)
2934         {
2935             relinfo = R_X86_64_PC32;
2936             val -= 4;
2937             targetsymidx = MAP_SEG2SYMIDX(targetdatum);
2938         }
2939         else if (MAP_SEG2SEC(targetdatum).sh_flags & SHF_TLS)
2940         {
2941             if (config.flags3 & CFG3pie)
2942                 relinfo = R_X86_64_TPOFF32;
2943             else
2944                 relinfo = config.flags3 & CFG3pic ? R_X86_64_TLSGD : R_X86_64_TPOFF32;
2945         }
2946         else
2947         {
2948             relinfo = targetdatum == CDATA ? R_X86_64_32 : R_X86_64_32S;
2949             targetsymidx = MAP_SEG2SYMIDX(targetdatum);
2950         }
2951     }
2952     else
2953     {
2954         if (MAP_SEG2TYP(seg) == CODE && config.flags3 & CFG3pic)
2955             relinfo = R_386_GOTOFF;
2956         else if (MAP_SEG2SEC(targetdatum).sh_flags & SHF_TLS)
2957         {
2958             if (config.flags3 & CFG3pie)
2959                 relinfo = R_386_TLS_LE;
2960             else
2961                 relinfo = config.flags3 & CFG3pic ? R_386_TLS_GD : R_386_TLS_LE;
2962         }
2963         else
2964             relinfo = R_386_32;
2965         targetsymidx = MAP_SEG2SYMIDX(targetdatum);
2966     }
2967     ElfObj_writerel(seg, cast(uint)offset, relinfo, targetsymidx, val);
2968 }
2969 
2970 /*******************************
2971  * Refer to address that is in the code segment.
2972  * Only offsets are output, regardless of the memory model.
2973  * Used to put values in switch address tables.
2974  * Input:
2975  *      seg =           where the address is going (CODE or DATA)
2976  *      offset =        offset within seg
2977  *      val =           displacement from start of this module
2978  */
2979 
2980 void ElfObj_reftocodeseg(int seg,targ_size_t offset,targ_size_t val)
2981 {
2982     //printf("ElfObj_reftocodeseg(seg=%d, offset=x%llx, val=x%llx, off=x%llx )\n",seg,offset,val, val - funcsym_p.Soffset);
2983 
2984     reltype_t relinfo;
2985 static if (0)
2986 {
2987     if (MAP_SEG2TYP(seg) == CODE)
2988     {
2989         relinfo = RI_TYPE_PC32;
2990         ElfObj_writerel(seg, offset, relinfo, funcsym_p.Sxtrnnum, val - funcsym_p.Soffset);
2991         return;
2992     }
2993 }
2994 
2995     if (I64)
2996         relinfo = (config.flags3 & CFG3pic) ? R_X86_64_PC32 : R_X86_64_32;
2997     else
2998         relinfo = (config.flags3 & CFG3pic) ? R_386_GOTOFF : R_386_32;
2999     ElfObj_writerel(seg, cast(uint)offset, relinfo, funcsym_p.Sxtrnnum, val - funcsym_p.Soffset);
3000 }
3001 
3002 /*******************************
3003  * Refer to an identifier.
3004  * Input:
3005  *      segtyp =        where the address is going (CODE or DATA)
3006  *      offset =        offset within seg
3007  *      s =             Symbol table entry for identifier
3008  *      val =           displacement from identifier
3009  *      flags =         CFselfrel: self-relative
3010  *                      CFseg: get segment
3011  *                      CFoff: get offset
3012  *                      CFoffset64: 64 bit fixup
3013  *                      CFpc32: I64: PC relative 32 bit fixup
3014  * Returns:
3015  *      number of bytes in reference (4 or 8)
3016  */
3017 
3018 int ElfObj_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val,
3019         int flags)
3020 {
3021     bool external = true;
3022     Outbuffer *buf;
3023     reltype_t relinfo = R_X86_64_NONE;
3024     int refseg;
3025     const segtyp = MAP_SEG2TYP(seg);
3026     //assert(val == 0);
3027     int retsize = (flags & CFoffset64) ? 8 : 4;
3028 
3029 static if (0)
3030 {
3031     printf("\nElfObj_reftoident('%s' seg %d, offset x%llx, val x%llx, flags x%x)\n",
3032         s.Sident.ptr,seg,offset,val,flags);
3033     printf("Sseg = %d, Sxtrnnum = %d, retsize = %d\n",s.Sseg,s.Sxtrnnum,retsize);
3034     symbol_print(s);
3035 }
3036 
3037     const tym_t ty = s.ty();
3038     if (s.Sxtrnnum)
3039     {                           // identifier is defined somewhere else
3040         if (I64)
3041         {
3042             if (elfobj.SymbolTable64[s.Sxtrnnum].st_shndx != SHN_UNDEF)
3043                 external = false;
3044         }
3045         else
3046         {
3047             if (elfobj.SymbolTable[s.Sxtrnnum].st_shndx != SHN_UNDEF)
3048                 external = false;
3049         }
3050     }
3051 
3052     switch (s.Sclass)
3053     {
3054         case SClocstat:
3055             if (I64)
3056             {
3057                 if (s.Sfl == FLtlsdata)
3058                 {
3059                     if (config.flags3 & CFG3pie)
3060                         relinfo = R_X86_64_TPOFF32;
3061                     else
3062                         relinfo = config.flags3 & CFG3pic ? R_X86_64_TLSGD : R_X86_64_TPOFF32;
3063                 }
3064                 else
3065                 {   relinfo = config.flags3 & CFG3pic ? R_X86_64_PC32 : R_X86_64_32;
3066                     if (flags & CFpc32)
3067                         relinfo = R_X86_64_PC32;
3068                 }
3069             }
3070             else
3071             {
3072                 if (s.Sfl == FLtlsdata)
3073                 {
3074                     if (config.flags3 & CFG3pie)
3075                         relinfo = R_386_TLS_LE;
3076                     else
3077                         relinfo = config.flags3 & CFG3pic ? R_386_TLS_GD : R_386_TLS_LE;
3078                 }
3079                 else
3080                     relinfo = config.flags3 & CFG3pic ? R_386_GOTOFF : R_386_32;
3081             }
3082             if (flags & CFoffset64 && relinfo == R_X86_64_32)
3083             {
3084                 relinfo = R_X86_64_64;
3085                 retsize = 8;
3086             }
3087             refseg = STI_RODAT;
3088             val += s.Soffset;
3089             goto outrel;
3090 
3091         case SCcomdat:
3092         case_SCcomdat:
3093         case SCstatic:
3094 static if (0)
3095 {
3096             if ((s.Sflags & SFLthunk) && s.Soffset)
3097             {                   // A thunk symbol that has been defined
3098                 assert(s.Sseg == seg);
3099                 val = (s.Soffset+val) - (offset+4);
3100                 goto outaddrval;
3101             }
3102 }
3103             goto case;
3104 
3105         case SCextern:
3106         case SCcomdef:
3107         case_extern:
3108         case SCglobal:
3109             if (!s.Sxtrnnum)
3110             {   // not in symbol table yet - class might change
3111                 //printf("\tadding %s to fixlist\n",s.Sident.ptr);
3112                 size_t numbyteswritten = addtofixlist(s,offset,seg,val,flags);
3113                 assert(numbyteswritten == retsize);
3114                 return retsize;
3115             }
3116             else
3117             {
3118                 refseg = s.Sxtrnnum;       // default to name symbol table entry
3119 
3120                 if (flags & CFselfrel)
3121                 {               // only for function references within code segments
3122                     if (!external &&            // local definition found
3123                          s.Sseg == seg &&      // within same code segment
3124                           (!(config.flags3 & CFG3pic) ||        // not position indp code
3125                            s.Sclass == SCstatic)) // or is pic, but declared static
3126                     {                   // Can use PC relative
3127                         //dbg_printf("\tdoing PC relative\n");
3128                         val = (s.Soffset+val) - (offset+4);
3129                     }
3130                     else
3131                     {
3132                         //dbg_printf("\tadding relocation\n");
3133                         if (s.Sclass == SCglobal && config.flags3 & CFG3pie && tyfunc(s.ty()))
3134                             relinfo = I64 ? R_X86_64_PC32 : R_386_PC32;
3135                         else if (I64)
3136                             relinfo = config.flags3 & CFG3pic ?  R_X86_64_PLT32 : R_X86_64_PC32;
3137                         else
3138                             relinfo = config.flags3 & CFG3pic ?  R_386_PLT32 : R_386_PC32;
3139                         val = -cast(targ_size_t)4;
3140                     }
3141                 }
3142                 else
3143                 {       // code to code code to data, data to code, data to data refs
3144                     if (s.Sclass == SCstatic)
3145                     {                           // offset into .data or .bss seg
3146                         refseg = MAP_SEG2SYMIDX(s.Sseg);
3147                                                 // use segment symbol table entry
3148                         val += s.Soffset;
3149                         if (!(config.flags3 & CFG3pic) ||       // all static refs from normal code
3150                              segtyp == DATA)    // or refs from data from posi indp
3151                         {
3152                             if (I64)
3153                                 relinfo = (flags & CFpc32) ? R_X86_64_PC32 : R_X86_64_32;
3154                             else
3155                                 relinfo = R_386_32;
3156                         }
3157                         else
3158                         {
3159                             relinfo = I64 ? R_X86_64_PC32 : R_386_GOTOFF;
3160                         }
3161                     }
3162                     else if (config.flags3 & CFG3pic && s == GOTsym)
3163                     {                   // relocation for Gbl Offset Tab
3164                         relinfo =  I64 ? R_X86_64_NONE : R_386_GOTPC;
3165                     }
3166                     else if (segtyp == DATA)
3167                     {                   // relocation from within DATA seg
3168                         relinfo = I64 ? R_X86_64_32 : R_386_32;
3169                         if (I64 && flags & CFpc32)
3170                             relinfo = R_X86_64_PC32;
3171                     }
3172                     else
3173                     {                   // relocation from within CODE seg
3174                         if (I64)
3175                         {
3176                             if (config.flags3 & CFG3pie && s.Sclass == SCglobal)
3177                                 relinfo = R_X86_64_PC32;
3178                             else if (config.flags3 & CFG3pic)
3179                                 relinfo = R_X86_64_GOTPCREL;
3180                             else
3181                                 relinfo = (flags & CFpc32) ? R_X86_64_PC32 : R_X86_64_32;
3182                         }
3183                         else
3184                         {
3185                             if (config.flags3 & CFG3pie && s.Sclass == SCglobal)
3186                                 relinfo = R_386_GOTOFF;
3187                             else
3188                                 relinfo = config.flags3 & CFG3pic ? R_386_GOT32 : R_386_32;
3189                         }
3190                     }
3191                     if ((s.ty() & mTYLINK) & mTYthread)
3192                     {
3193                         if (I64)
3194                         {
3195                             if (config.flags3 & CFG3pie)
3196                             {
3197                                 if (s.Sclass == SCstatic || s.Sclass == SCglobal)
3198                                     relinfo = R_X86_64_TPOFF32;
3199                                 else
3200                                     relinfo = R_X86_64_GOTTPOFF;
3201                             }
3202                             else if (config.flags3 & CFG3pic)
3203                             {
3204                                 /+if (s.Sclass == SCstatic || s.Sclass == SClocstat)
3205                                     // Could use 'local dynamic (LD)' to optimize multiple local TLS reads
3206                                     relinfo = R_X86_64_TLSGD;
3207                                 else+/
3208                                     relinfo = R_X86_64_TLSGD;
3209                             }
3210                             else
3211                             {
3212                                 if (s.Sclass == SCstatic || s.Sclass == SClocstat)
3213                                     relinfo = R_X86_64_TPOFF32;
3214                                 else
3215                                     relinfo = R_X86_64_GOTTPOFF;
3216                             }
3217                         }
3218                         else
3219                         {
3220                             if (config.flags3 & CFG3pie)
3221                             {
3222                                 if (s.Sclass == SCstatic || s.Sclass == SCglobal)
3223                                     relinfo = R_386_TLS_LE;
3224                                 else
3225                                     relinfo = R_386_TLS_GOTIE;
3226                             }
3227                             else if (config.flags3 & CFG3pic)
3228                             {
3229                                 /+if (s.Sclass == SCstatic)
3230                                     // Could use 'local dynamic (LD)' to optimize multiple local TLS reads
3231                                     relinfo = R_386_TLS_GD;
3232                                 else+/
3233                                     relinfo = R_386_TLS_GD;
3234                             }
3235                             else
3236                             {
3237                                 if (s.Sclass == SCstatic)
3238                                     relinfo = R_386_TLS_LE;
3239                                 else
3240                                     relinfo = R_386_TLS_IE;
3241                             }
3242                         }
3243                     }
3244                     if (flags & CFoffset64 && relinfo == R_X86_64_32)
3245                     {
3246                         relinfo = R_X86_64_64;
3247                     }
3248                 }
3249                 if (relinfo == R_X86_64_NONE)
3250                 {
3251                 outaddrval:
3252                     writeaddrval(seg, cast(uint)offset, val, retsize);
3253                 }
3254                 else
3255                 {
3256                 outrel:
3257                     //printf("\t\t************* adding relocation\n");
3258                     const size_t nbytes = ElfObj_writerel(seg, cast(uint)offset, relinfo, refseg, val);
3259                     assert(nbytes == retsize);
3260                 }
3261             }
3262             break;
3263 
3264         case SCsinline:
3265         case SCeinline:
3266             printf ("Undefined inline value <<fixme>>\n");
3267             //warerr(WM_undefined_inline,s.Sident.ptr);
3268             goto  case;
3269 
3270         case SCinline:
3271             if (tyfunc(ty))
3272             {
3273                 s.Sclass = SCextern;
3274                 goto case_extern;
3275             }
3276             else if (config.flags2 & CFG2comdat)
3277                 goto case_SCcomdat;     // treat as initialized common block
3278             goto default;
3279 
3280         default:
3281             //symbol_print(s);
3282             assert(0);
3283     }
3284     return retsize;
3285 }
3286 
3287 /*****************************************
3288  * Generate far16 thunk.
3289  * Input:
3290  *      s       Symbol to generate a thunk for
3291  */
3292 
3293 void ElfObj_far16thunk(Symbol *s)
3294 {
3295     //dbg_printf("ElfObj_far16thunk('%s')\n", s.Sident.ptr);
3296     assert(0);
3297 }
3298 
3299 /**************************************
3300  * Mark object file as using floating point.
3301  */
3302 
3303 void ElfObj_fltused()
3304 {
3305     //dbg_printf("ElfObj_fltused()\n");
3306 }
3307 
3308 /************************************
3309  * Close and delete .OBJ file.
3310  */
3311 
3312 void elfobjfile_delete()
3313 {
3314     //remove(fobjname); // delete corrupt output file
3315 }
3316 
3317 /**********************************
3318  * Terminate.
3319  */
3320 
3321 void elfobjfile_term()
3322 {
3323 static if (TERMCODE)
3324 {
3325     mem_free(fobjname);
3326     fobjname = null;
3327 }
3328 }
3329 
3330 /**********************************
3331   * Write to the object file
3332   */
3333 /+void objfile_write(FILE *fd, void *buffer, uint len)
3334 {
3335     fobjbuf.write(buffer, len);
3336 }
3337 +/
3338 
3339 private extern (D)
3340 int elf_align(targ_size_t size,int foffset)
3341 {
3342     if (size <= 1)
3343         return foffset;
3344     int offset = cast(int)((foffset + size - 1) & ~(size - 1));
3345     if (offset > foffset)
3346         fobjbuf.writezeros(offset - foffset);
3347     return offset;
3348 }
3349 
3350 /***************************************
3351  * Stuff pointer to ModuleInfo into its own section (minfo).
3352  */
3353 
3354 version (MARS)
3355 {
3356 
3357 void ElfObj_moduleinfo(Symbol *scc)
3358 {
3359     const CFflags = I64 ? (CFoffset64 | CFoff) : CFoff;
3360 
3361     // needs to be writeable for PIC code, see Bugzilla 13117
3362     const shf_flags = SHF_ALLOC | SHF_WRITE;
3363     const seg = ElfObj_getsegment("minfo", null, SHT_PROGBITS, shf_flags, _tysize[TYnptr]);
3364     SegData[seg].SDoffset +=
3365         ElfObj_reftoident(seg, SegData[seg].SDoffset, scc, 0, CFflags);
3366 }
3367 
3368 /***************************************
3369  * Create startup/shutdown code to register an executable/shared
3370  * library (DSO) with druntime. Create one for each object file and
3371  * put the sections into a COMDAT group. This will ensure that each
3372  * DSO gets registered only once.
3373  */
3374 
3375 private void obj_rtinit()
3376 {
3377     // section start/stop symbols are defined by the linker (http://www.airs.com/blog/archives/56)
3378     // make the symbols hidden so that each DSO gets its own brackets
3379     IDXSYM minfo_beg, minfo_end, dso_rec;
3380 
3381     {
3382     // needs to be writeable for PIC code, see Bugzilla 13117
3383     const shf_flags = SHF_ALLOC | SHF_WRITE;
3384 
3385     const namidx = ElfObj_addstr(symtab_strings,"__start_minfo");
3386     minfo_beg = elf_addsym(namidx, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN);
3387 
3388     ElfObj_getsegment("minfo", null, SHT_PROGBITS, shf_flags, _tysize[TYnptr]);
3389 
3390     const namidx2 = ElfObj_addstr(symtab_strings,"__stop_minfo");
3391     minfo_end = elf_addsym(namidx2, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN);
3392     }
3393 
3394     // Create a COMDAT section group
3395     const groupseg = ElfObj_getsegment(".group.d_dso", null, SHT_GROUP, 0, 0);
3396     SegData[groupseg].SDbuf.write32(GRP_COMDAT);
3397 
3398     {
3399         /*
3400          * Create an instance of DSORec as global static data in the section .data.d_dso_rec
3401          * It is writeable and allows the runtime to store information.
3402          * Make it a COMDAT so there's only one per DSO.
3403          *
3404          * typedef union
3405          * {
3406          *     size_t        id;
3407          *     void       *data;
3408          * } DSORec;
3409          */
3410         const seg = ElfObj_getsegment(".data.d_dso_rec", null, SHT_PROGBITS,
3411                          SHF_ALLOC|SHF_WRITE|SHF_GROUP, _tysize[TYnptr]);
3412         dso_rec = MAP_SEG2SYMIDX(seg);
3413         ElfObj_bytes(seg, 0, _tysize[TYnptr], null);
3414         // add to section group
3415         SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(seg));
3416 
3417         /*
3418          * Create an instance of DSO on the stack:
3419          *
3420          * typedef struct
3421          * {
3422          *     size_t                version;
3423          *     DSORec               *dso_rec;
3424          *     void   *minfo_beg, *minfo_end;
3425          * } DSO;
3426          *
3427          * Generate the following function as a COMDAT so there's only one per DSO:
3428          *  .text.d_dso_init    segment
3429          *      push    EBP
3430          *      mov     EBP,ESP
3431          *      sub     ESP,align
3432          *      lea     RAX,minfo_end[RIP]
3433          *      push    RAX
3434          *      lea     RAX,minfo_beg[RIP]
3435          *      push    RAX
3436          *      lea     RAX,.data.d_dso_rec[RIP]
3437          *      push    RAX
3438          *      push    1       // version
3439          *      mov     RDI,RSP
3440          *      call      _d_dso_registry@PLT32
3441          *      leave
3442          *      ret
3443          * and then put a pointer to that function in .init_array and in .fini_array so it'll
3444          * get executed once upon loading and once upon unloading the DSO.
3445          */
3446         const codseg = ElfObj_getsegment(".text.d_dso_init", null, SHT_PROGBITS,
3447                                 SHF_ALLOC|SHF_EXECINSTR|SHF_GROUP, _tysize[TYnptr]);
3448         // add to section group
3449         SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(codseg));
3450 
3451         debug
3452         {
3453             // adds a local symbol (name) to the code, useful to set a breakpoint
3454             const namidx = ElfObj_addstr(symtab_strings, "__d_dso_init");
3455             elf_addsym(namidx, 0, 0, STT_FUNC, STB_LOCAL, MAP_SEG2SECIDX(codseg));
3456         }
3457 
3458         Outbuffer *buf = SegData[codseg].SDbuf;
3459         assert(!buf.length());
3460         size_t off = 0;
3461 
3462         // 16-byte align for call
3463         const size_t sizeof_dso = 6 * _tysize[TYnptr];
3464         const size_t align_ = I64 ?
3465             // return address, RBP, DSO
3466             (-(2 * _tysize[TYnptr] + sizeof_dso) & 0xF) :
3467             // return address, EBP, EBX, DSO, arg
3468             (-(3 * _tysize[TYnptr] + sizeof_dso + _tysize[TYnptr]) & 0xF);
3469 
3470         // push EBP
3471         buf.writeByte(0x50 + BP);
3472         off += 1;
3473         // mov EBP, ESP
3474         if (I64)
3475         {
3476             buf.writeByte(REX | REX_W);
3477             off += 1;
3478         }
3479         buf.writeByte(0x8B);
3480         buf.writeByte(modregrm(3,BP,SP));
3481         off += 2;
3482         // sub ESP, align_
3483         if (align_)
3484         {
3485             if (I64)
3486             {
3487                 buf.writeByte(REX | REX_W);
3488                 off += 1;
3489             }
3490             buf.writeByte(0x81);
3491             buf.writeByte(modregrm(3,5,SP));
3492             buf.writeByte(align_ & 0xFF);
3493             buf.writeByte(align_ >> 8 & 0xFF);
3494             buf.writeByte(0);
3495             buf.writeByte(0);
3496             off += 6;
3497         }
3498 
3499         if (config.flags3 & CFG3pic && I32)
3500         {   // see cod3_load_got() for reference
3501             // push EBX
3502             buf.writeByte(0x50 + BX);
3503             off += 1;
3504             // call L1
3505             buf.writeByte(0xE8);
3506             buf.write32(0);
3507             // L1: pop EBX (now contains EIP)
3508             buf.writeByte(0x58 + BX);
3509             off += 6;
3510             // add EBX,_GLOBAL_OFFSET_TABLE_+3
3511             buf.writeByte(0x81);
3512             buf.writeByte(modregrm(3,0,BX));
3513             off += 2;
3514             off += ElfObj_writerel(codseg, off, R_386_GOTPC, ElfObj_external(ElfObj_getGOTsym()), 3);
3515         }
3516 
3517         reltype_t reltype;
3518         opcode_t op;
3519         if (0 && config.flags3 & CFG3pie)
3520         {
3521             op = LOD;
3522             reltype = I64 ? R_X86_64_GOTPCREL : R_386_GOT32;
3523         }
3524         else if (config.flags3 & CFG3pic)
3525         {
3526             op = LEA;
3527             reltype = I64 ? R_X86_64_PC32 : R_386_GOTOFF;
3528         }
3529         else
3530         {
3531             op = LEA;
3532             reltype = I64 ? R_X86_64_32 : R_386_32;
3533         }
3534 
3535         const IDXSYM[3] syms = [dso_rec, minfo_beg, minfo_end];
3536 
3537         for (size_t i = (syms).sizeof / (syms[0]).sizeof; i--; )
3538         {
3539             const IDXSYM sym = syms[i];
3540 
3541             if (config.flags3 & CFG3pic)
3542             {
3543                 if (I64)
3544                 {
3545                     // lea RAX, sym[RIP]
3546                     buf.writeByte(REX | REX_W);
3547                     buf.writeByte(op);
3548                     buf.writeByte(modregrm(0,AX,5));
3549                     off += 3;
3550                     off += ElfObj_writerel(codseg, off, reltype, syms[i], -4);
3551                 }
3552                 else
3553                 {
3554                     // lea EAX, sym[EBX]
3555                     buf.writeByte(op);
3556                     buf.writeByte(modregrm(2,AX,BX));
3557                     off += 2;
3558                     off += ElfObj_writerel(codseg, off, reltype, syms[i], 0);
3559                 }
3560             }
3561             else
3562             {
3563                 // mov EAX, sym
3564                 buf.writeByte(0xB8 + AX);
3565                 off += 1;
3566                 off += ElfObj_writerel(codseg, off, reltype, syms[i], 0);
3567             }
3568             // push RAX
3569             buf.writeByte(0x50 + AX);
3570             off += 1;
3571         }
3572         buf.writeByte(0x6A);            // PUSH 1
3573         buf.writeByte(1);               // version flag to simplify future extensions
3574         off += 2;
3575 
3576         if (I64)
3577         {   // mov RDI, DSO*
3578             buf.writeByte(REX | REX_W);
3579             buf.writeByte(0x8B);
3580             buf.writeByte(modregrm(3,DI,SP));
3581             off += 3;
3582         }
3583         else
3584         {   // push DSO*
3585             buf.writeByte(0x50 + SP);
3586             off += 1;
3587         }
3588 
3589 static if (REQUIRE_DSO_REGISTRY)
3590 {
3591 
3592         const IDXSYM symidx = ElfObj_external_def("_d_dso_registry");
3593 
3594         // call _d_dso_registry@PLT
3595         buf.writeByte(0xE8);
3596         off += 1;
3597         off += ElfObj_writerel(codseg, off, I64 ? R_X86_64_PLT32 : R_386_PLT32, symidx, -4);
3598 
3599 }
3600 else
3601 {
3602 
3603         // use a weak reference for _d_dso_registry
3604         const namidx2 = ElfObj_addstr(symtab_strings, "_d_dso_registry");
3605         const IDXSYM symidx = elf_addsym(namidx2, 0, 0, STT_NOTYPE, STB_WEAK, SHN_UNDEF);
3606 
3607         if (config.flags3 & CFG3pic)
3608         {
3609             if (I64)
3610             {
3611                 // cmp foo@GOT[RIP], 0
3612                 buf.writeByte(REX | REX_W);
3613                 buf.writeByte(0x83);
3614                 buf.writeByte(modregrm(0,7,5));
3615                 off += 3;
3616                 const reltype2 = /*config.flags3 & CFG3pie ? R_X86_64_PC32 :*/ R_X86_64_GOTPCREL;
3617                 off += ElfObj_writerel(codseg, off, reltype2, symidx, -5);
3618                 buf.writeByte(0);
3619                 off += 1;
3620             }
3621             else
3622             {
3623                 // cmp foo[GOT], 0
3624                 buf.writeByte(0x81);
3625                 buf.writeByte(modregrm(2,7,BX));
3626                 off += 2;
3627                 const reltype2 = /*config.flags3 & CFG3pie ? R_386_GOTOFF :*/ R_386_GOT32;
3628                 off += ElfObj_writerel(codseg, off, reltype2, symidx, 0);
3629                 buf.write32(0);
3630                 off += 4;
3631             }
3632             // jz +5
3633             buf.writeByte(0x74);
3634             buf.writeByte(0x05);
3635             off += 2;
3636 
3637             // call foo@PLT[RIP]
3638             buf.writeByte(0xE8);
3639             off += 1;
3640             off += ElfObj_writerel(codseg, off, I64 ? R_X86_64_PLT32 : R_386_PLT32, symidx, -4);
3641         }
3642         else
3643         {
3644             // mov ECX, offset foo
3645             buf.writeByte(0xB8 + CX);
3646             off += 1;
3647             const reltype2 = I64 ? R_X86_64_32 : R_386_32;
3648             off += ElfObj_writerel(codseg, off, reltype2, symidx, 0);
3649 
3650             // test ECX, ECX
3651             buf.writeByte(0x85);
3652             buf.writeByte(modregrm(3,CX,CX));
3653 
3654             // jz +5 (skip call)
3655             buf.writeByte(0x74);
3656             buf.writeByte(0x05);
3657             off += 4;
3658 
3659             // call _d_dso_registry[RIP]
3660             buf.writeByte(0xE8);
3661             off += 1;
3662             off += ElfObj_writerel(codseg, off, I64 ? R_X86_64_PC32 : R_386_PC32, symidx, -4);
3663         }
3664 
3665 }
3666 
3667         if (config.flags3 & CFG3pic && I32)
3668         {   // mov EBX,[EBP-4-align_]
3669             buf.writeByte(0x8B);
3670             buf.writeByte(modregrm(1,BX,BP));
3671             buf.writeByte(cast(int)(-4-align_));
3672             off += 3;
3673         }
3674         // leave
3675         buf.writeByte(0xC9);
3676         // ret
3677         buf.writeByte(0xC3);
3678         off += 2;
3679         Offset(codseg) = off;
3680 
3681         // put a reference into .init_array/.fini_array each
3682         // needs to be writeable for PIC code, see Bugzilla 13117
3683         const int flags = SHF_ALLOC | SHF_WRITE | SHF_GROUP;
3684         {
3685             enum fini_name = USE_INIT_ARRAY ? ".fini_array.d_dso_dtor" : ".dtors.d_dso_dtor";
3686             enum fini_type = USE_INIT_ARRAY ? SHT_FINI_ARRAY : SHT_PROGBITS;
3687             const cdseg = ElfObj_getsegment(fini_name.ptr, null, fini_type, flags, _tysize[TYnptr]);
3688             assert(!SegData[cdseg].SDbuf.length());
3689             // add to section group
3690             SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(cdseg));
3691             // relocation
3692             const reltype2 = I64 ? R_X86_64_64 : R_386_32;
3693             SegData[cdseg].SDoffset += ElfObj_writerel(cdseg, 0, reltype2, MAP_SEG2SYMIDX(codseg), 0);
3694         }
3695         {
3696             enum init_name = USE_INIT_ARRAY ? ".init_array.d_dso_ctor" : ".ctors.d_dso_ctor";
3697             enum init_type = USE_INIT_ARRAY ? SHT_INIT_ARRAY : SHT_PROGBITS;
3698             const cdseg = ElfObj_getsegment(init_name.ptr, null, init_type, flags, _tysize[TYnptr]);
3699             assert(!SegData[cdseg].SDbuf.length());
3700             // add to section group
3701             SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(cdseg));
3702             // relocation
3703             const reltype2 = I64 ? R_X86_64_64 : R_386_32;
3704             SegData[cdseg].SDoffset += ElfObj_writerel(cdseg, 0, reltype2, MAP_SEG2SYMIDX(codseg), 0);
3705         }
3706     }
3707     // set group section infos
3708     Offset(groupseg) = SegData[groupseg].SDbuf.length();
3709     Elf32_Shdr *p = MAP_SEG2SEC(groupseg);
3710     p.sh_link    = SHN_SYMTAB;
3711     p.sh_info    = dso_rec; // set the dso_rec as group symbol
3712     p.sh_entsize = IDXSYM.sizeof;
3713     p.sh_size    = cast(uint)Offset(groupseg);
3714 }
3715 
3716 }
3717 
3718 /*************************************
3719  */
3720 
3721 void ElfObj_gotref(Symbol *s)
3722 {
3723     //printf("ElfObj_gotref(%x '%s', %d)\n",s,s.Sident.ptr, s.Sclass);
3724     switch(s.Sclass)
3725     {
3726         case SCstatic:
3727         case SClocstat:
3728             s.Sfl = FLgotoff;
3729             break;
3730 
3731         case SCextern:
3732         case SCglobal:
3733         case SCcomdat:
3734         case SCcomdef:
3735             s.Sfl = FLgot;
3736             break;
3737 
3738         default:
3739             break;
3740     }
3741 }
3742 
3743 Symbol *ElfObj_tlv_bootstrap()
3744 {
3745     // specific for Mach-O
3746     assert(0);
3747 }
3748 
3749 void ElfObj_write_pointerRef(Symbol* s, uint off)
3750 {
3751 }
3752 
3753 /******************************************
3754  * Generate fixup specific to .eh_frame and .gcc_except_table sections.
3755  * Params:
3756  *      seg = segment of where to write fixup
3757  *      offset = offset of where to write fixup
3758  *      s = fixup is a reference to this Symbol
3759  *      val = displacement from s
3760  * Returns:
3761  *      number of bytes written at seg:offset
3762  */
3763 int elf_dwarf_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val)
3764 {
3765     if (config.flags3 & CFG3pic)
3766     {
3767         /* fixup: R_X86_64_PC32 sym="DW.ref.name"
3768          * symtab: .weak DW.ref.name,@OBJECT,VALUE=.data.DW.ref.name+0x00,SIZE=8
3769          * Section 13  .data.DW.ref.name  PROGBITS,ALLOC,WRITE,SIZE=0x0008(8),OFFSET=0x0138,ALIGN=8
3770          *  0138:   0  0  0  0  0  0  0  0                           ........
3771          * Section 14  .rela.data.DW.ref.name  RELA,ENTRIES=1,OFFSET=0x0E18,ALIGN=8,LINK=22,INFO=13
3772          *   0 offset=00000000 addend=0000000000000000 type=R_X86_64_64 sym="name"
3773          */
3774         if (!s.Sdw_ref_idx)
3775         {
3776             const dataDWref_seg = ElfObj_getsegment(".data.DW.ref.", s.Sident.ptr, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, I64 ? 8 : 4);
3777             Outbuffer *buf = SegData[dataDWref_seg].SDbuf;
3778             assert(buf.length() == 0);
3779             ElfObj_reftoident(dataDWref_seg, 0, s, 0, I64 ? CFoffset64 : CFoff);
3780 
3781             // Add "DW.ref." ~ name to the symtab_strings table
3782             const namidx = cast(IDXSTR)symtab_strings.length();
3783             symtab_strings.writeString("DW.ref.");
3784             symtab_strings.setsize(cast(uint)(symtab_strings.length() - 1));  // back up over terminating 0
3785             symtab_strings.writeString(s.Sident.ptr);
3786 
3787             s.Sdw_ref_idx = elf_addsym(namidx, val, 8, STT_OBJECT, STB_WEAK, MAP_SEG2SECIDX(dataDWref_seg), STV_HIDDEN);
3788         }
3789         ElfObj_writerel(seg, cast(uint)offset, I64 ? R_X86_64_PC32 : R_386_PC32, s.Sdw_ref_idx, 0);
3790     }
3791     else
3792     {
3793         ElfObj_reftoident(seg, offset, s, val, CFoff);
3794         //dwarf_addrel(seg, offset, s.Sseg, s.Soffset);
3795         //et.write32(s.Soffset);
3796     }
3797     return 4;
3798 }
3799 
3800 }
3801 
3802 }