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