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