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