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