1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1994-1998 by Symantec
6  *              Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/obj.d, backend/obj.d)
10  */
11 
12 module dmd.backend.obj;
13 
14 // Online documentation: https://dlang.org/phobos/dmd_backend_obj.html
15 
16 /* Interface to object file format
17  */
18 
19 import dmd.backend.cdef;
20 import dmd.backend.cc;
21 import dmd.backend.code;
22 import dmd.backend.el;
23 import dmd.backend.outbuf;
24 
25 extern (C++):
26 
27 nothrow:
28 
29 version (SPP)
30     version = STUB;
31 else version (HTOD)
32     version = STUB;
33 else version (Windows)
34 {
35 }
36 else version (Posix)
37 {
38 }
39 else
40     static assert(0, "unsupported version");
41 
42 /******************************************************************/
43 
44 /* Functions common to all object formats
45  */
46 mixin(ObjMemDecl("Obj $Obj_init(Outbuffer *, const(char)* filename, const(char)* csegname)"));
47 mixin(ObjMemDecl("void $Obj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname)"));
48 mixin(ObjMemDecl("void $Obj_termfile()"));
49 mixin(ObjMemDecl("void $Obj_term(const(char)* objfilename)"));
50 mixin(ObjMemDecl("void $Obj_linnum(Srcpos srcpos, int seg, targ_size_t offset)"));
51 mixin(ObjMemDecl("int  $Obj_codeseg(const char *name,int suffix)"));
52 mixin(ObjMemDecl("void $Obj_startaddress(Symbol *)"));
53 mixin(ObjMemDecl("bool $Obj_includelib(const(char)* )"));
54 mixin(ObjMemDecl("bool $Obj_linkerdirective(const(char)* )"));
55 mixin(ObjMemDecl("bool $Obj_allowZeroSize()"));
56 mixin(ObjMemDecl("void $Obj_exestr(const(char)* p)"));
57 mixin(ObjMemDecl("void $Obj_user(const(char)* p)"));
58 mixin(ObjMemDecl("void $Obj_compiler()"));
59 mixin(ObjMemDecl("void $Obj_wkext(Symbol *,Symbol *)"));
60 mixin(ObjMemDecl("void $Obj_alias(const(char)* n1,const(char)* n2)"));
61 mixin(ObjMemDecl("void $Obj_staticctor(Symbol *s,int dtor,int seg)"));
62 mixin(ObjMemDecl("void $Obj_staticdtor(Symbol *s)"));
63 mixin(ObjMemDecl("void $Obj_setModuleCtorDtor(Symbol *s, bool isCtor)"));
64 mixin(ObjMemDecl("void $Obj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym)"));
65 mixin(ObjMemDecl("void $Obj_ehsections()"));
66 mixin(ObjMemDecl("void $Obj_moduleinfo(Symbol *scc)"));
67 mixin(ObjMemDecl("int  $Obj_comdat(Symbol *)"));
68 mixin(ObjMemDecl("int  $Obj_comdatsize(Symbol *, targ_size_t symsize)"));
69 mixin(ObjMemDecl("int  $Obj_readonly_comdat(Symbol *s)"));
70 mixin(ObjMemDecl("void $Obj_setcodeseg(int seg)"));
71 mixin(ObjMemDecl("seg_data* $Obj_tlsseg()"));
72 mixin(ObjMemDecl("seg_data* $Obj_tlsseg_bss()"));
73 mixin(ObjMemDecl("seg_data* $Obj_tlsseg_data()"));
74 mixin(ObjMemDecl("void $Obj_export_symbol(Symbol *s, uint argsize)"));
75 mixin(ObjMemDecl("void $Obj_pubdef(int seg, Symbol *s, targ_size_t offset)"));
76 mixin(ObjMemDecl("void $Obj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize)"));
77 mixin(ObjMemDecl("int  $Obj_external_def(const(char)*)"));
78 mixin(ObjMemDecl("int  $Obj_data_start(Symbol *sdata, targ_size_t datasize, int seg)"));
79 mixin(ObjMemDecl("int  $Obj_external(Symbol *)"));
80 mixin(ObjMemDecl("int  $Obj_common_block(Symbol *s, targ_size_t size, targ_size_t count)"));
81 mixin(ObjMemDecl("int  $Obj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count)"));
82 mixin(ObjMemDecl("void $Obj_lidata(int seg, targ_size_t offset, targ_size_t count)"));
83 mixin(ObjMemDecl("void $Obj_write_zeros(seg_data *pseg, targ_size_t count)"));
84 mixin(ObjMemDecl("void $Obj_write_byte(seg_data *pseg, uint _byte)"));
85 mixin(ObjMemDecl("void $Obj_write_bytes(seg_data *pseg, uint nbytes, void *p)"));
86 mixin(ObjMemDecl("void $Obj_byte(int seg, targ_size_t offset, uint _byte)"));
87 mixin(ObjMemDecl("uint $Obj_bytes(int seg, targ_size_t offset, uint nbytes, void *p)"));
88 mixin(ObjMemDecl("void $Obj_reftodatseg(int seg, targ_size_t offset, targ_size_t val, uint targetdatum, int flags)"));
89 mixin(ObjMemDecl("void $Obj_reftocodeseg(int seg, targ_size_t offset, targ_size_t val)"));
90 mixin(ObjMemDecl("int  $Obj_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags)"));
91 mixin(ObjMemDecl("void $Obj_far16thunk(Symbol *s)"));
92 mixin(ObjMemDecl("void $Obj_fltused()"));
93 mixin(ObjMemDecl("int  $Obj_data_readonly(char *p, int len, int *pseg)"));
94 mixin(ObjMemDecl("int  $Obj_data_readonly(char *p, int len)"));
95 mixin(ObjMemDecl("int  $Obj_string_literal_segment(uint sz)"));
96 mixin(ObjMemDecl("Symbol* $Obj_sym_cdata(tym_t, char *, int)"));
97 mixin(ObjMemDecl("void $Obj_func_start(Symbol *sfunc)"));
98 mixin(ObjMemDecl("void $Obj_func_term(Symbol *sfunc)"));
99 mixin(ObjMemDecl("void $Obj_write_pointerRef(Symbol* s, uint off)"));
100 mixin(ObjMemDecl("int  $Obj_jmpTableSegment(Symbol* s)"));
101 mixin(ObjMemDecl("Symbol* $Obj_tlv_bootstrap()"));
102 
103 /******************************************************************/
104 
105 size_t OmfObj_mangle(Symbol *s,char *dest);
106 void OmfObj_import(elem *e);
107 void OmfObj_dosseg();
108 void OmfObj_lzext(Symbol *,Symbol *);
109 void OmfObj_theadr(const(char)* modname);
110 void OmfObj_segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
111 int  OmfObj_fardata(char *name, targ_size_t size, targ_size_t *poffset);
112 void OmfObj_ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2);
113 void OmfObj_write_long(int seg, targ_size_t offset, uint data, uint lcfd, uint idx1, uint idx2);
114 void OmfObj_reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
115 int  OmfObj_seg_debugT();           // where the symbolic debug type data goes
116 
117 /******************************************************************/
118 
119 int  MsCoffObj_getsegment(const(char)* sectname, uint flags);
120 int  MsCoffObj_getsegment2(uint shtidx);
121 uint MsCoffObj_addScnhdr(const(char)* scnhdr_name, uint flags);
122 void MsCoffObj_addrel(int seg, targ_size_t offset, Symbol *targsym, uint targseg, int rtype, int val);
123 int  MsCoffObj_seg_drectve();
124 int  MsCoffObj_seg_pdata();
125 int  MsCoffObj_seg_xdata();
126 int  MsCoffObj_seg_pdata_comdat(Symbol *sfunc);
127 int  MsCoffObj_seg_xdata_comdat(Symbol *sfunc);
128 int  MsCoffObj_seg_debugS();
129 int  MsCoffObj_seg_debugS_comdat(Symbol *sfunc);
130 int  MsCoffObj_seg_debugT();           // where the symbolic debug type data goes
131 
132 /******************************************************************/
133 
134 void ElfObj_dosseg();
135 size_t ElfObj_mangle(Symbol* s, char* dest);
136 void ElfObj_import(elem* e);
137 void ElfObj_lzext(Symbol*, Symbol*);
138 void ElfObj_theadr(const(char)* modname);
139 void ElfObj_segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
140 int ElfObj_fardata(char *name, targ_size_t size, targ_size_t* poffset);
141 void ElfObj_ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2);
142 void ElfObj_reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
143 void ElfObj_gotref(Symbol* s);
144 uint ElfObj_addstr(Outbuffer* strtab, const(char)*);
145 Symbol* ElfObj_getGOTsym();
146 void ElfObj_refGOTsym();
147 int ElfObj_getsegment(const(char)* sectname, const(char)* suffix, int type, int flags, int align_);
148 void ElfObj_addrel(int seg, targ_size_t offset, uint type, uint symidx, targ_size_t val);
149 size_t ElfObj_writerel(int targseg, size_t offset, uint type, uint symidx, targ_size_t val);
150 
151 /******************************************************************/
152 
153 void MachObj_dosseg();
154 size_t MachObj_mangle(Symbol *s,char *dest);
155 void MachObj_import(elem *e);
156 void MachObj_lzext(Symbol *,Symbol *);
157 void MachObj_theadr(const(char)* modname);
158 void MachObj_segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
159 int MachObj_fardata(char *name, targ_size_t size, targ_size_t *poffset);
160 void MachObj_ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2);
161 void MachObj_reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
162 void MachObj_gotref(Symbol *s);
163 uint MachObj_addstr(Outbuffer *strtab, const(char)* );
164 Symbol* MachObj_getGOTsym();
165 void MachObj_refGOTsym();
166 int MachObj_getsegment(const(char)* sectname, const(char)* segname, int align_, int flags);
167 void MachObj_addrel(int seg, targ_size_t offset, Symbol* targsym, uint targseg, int rtype, int val);
168 
169 /******************************************************************/
170 
171 version (STUB)
172 {
173     public import stubobj;
174 }
175 else
176 {
177     /*******************************************
178      * Generic interface to the four object module file formats supported.
179      * Instead of using virtual functions (i.e. virtual dispatch) it uses
180      * static dispatch. Since config.objfmt never changes after initialization
181      * of the compiler, static branch prediction should make it faster than
182      * virtual dispatch.
183      *
184      * Making static dispatch work requires tediously repetitive boilerplate,
185      * which we accomplish via string mixins.
186      */
187     class Obj
188     {
189       static
190       {
191         nothrow:
192 
193         Obj init(Outbuffer* objbuf, const(char)* filename, const(char)* csegname)
194         {
195             mixin(genRetVal("init(objbuf, filename, csegname)"));
196         }
197 
198         void initfile(const(char)* filename, const(char)* csegname, const(char)* modname)
199         {
200             mixin(genRetVoid("initfile(filename, csegname, modname)"));
201         }
202 
203         void termfile()
204         {
205             mixin(genRetVoid("termfile()"));
206         }
207 
208         void term(const(char)* objfilename)
209         {
210             mixin(genRetVoid("term(objfilename)"));
211         }
212 
213         size_t mangle(Symbol *s,char *dest)
214         {
215             assert(config.objfmt == OBJ_OMF);
216             return OmfObj_mangle(s, dest);
217         }
218 
219         void _import(elem *e)
220         {
221             assert(config.objfmt == OBJ_OMF);
222             return OmfObj_import(e);
223         }
224 
225         void linnum(Srcpos srcpos, int seg, targ_size_t offset)
226         {
227             mixin(genRetVoid("linnum(srcpos, seg, offset)"));
228         }
229 
230         int codeseg(const char *name,int suffix)
231         {
232             mixin(genRetVal("codeseg(name, suffix)"));
233         }
234 
235         void dosseg()
236         {
237             assert(config.objfmt == OBJ_OMF);
238             return OmfObj_dosseg();
239         }
240 
241         void startaddress(Symbol *s)
242         {
243             mixin(genRetVoid("startaddress(s)"));
244         }
245 
246         bool includelib(const(char)* name)
247         {
248             mixin(genRetVal("includelib(name)"));
249         }
250 
251         bool linkerdirective(const(char)* p)
252         {
253             mixin(genRetVal("linkerdirective(p)"));
254         }
255 
256         bool allowZeroSize()
257         {
258             mixin(genRetVal("allowZeroSize()"));
259         }
260 
261         void exestr(const(char)* p)
262         {
263             mixin(genRetVoid("exestr(p)"));
264         }
265 
266         void user(const(char)* p)
267         {
268             mixin(genRetVoid("user(p)"));
269         }
270 
271         void compiler()
272         {
273             mixin(genRetVoid("compiler()"));
274         }
275 
276         void wkext(Symbol* s1, Symbol* s2)
277         {
278             mixin(genRetVoid("wkext(s1, s2)"));
279         }
280 
281         void lzext(Symbol* s1, Symbol* s2)
282         {
283             assert(config.objfmt == OBJ_OMF);
284             OmfObj_lzext(s1, s2);
285         }
286 
287         void _alias(const(char)* n1,const(char)* n2)
288         {
289             mixin(genRetVoid("alias(n1, n2)"));
290         }
291 
292         void theadr(const(char)* modname)
293         {
294             assert(config.objfmt == OBJ_OMF);
295             OmfObj_theadr(modname);
296         }
297 
298         void segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize)
299         {
300             assert(config.objfmt == OBJ_OMF);
301             OmfObj_segment_group(codesize, datasize, cdatasize, udatasize);
302         }
303 
304         void staticctor(Symbol *s,int dtor,int seg)
305         {
306             mixin(genRetVoid("staticctor(s, dtor, seg)"));
307         }
308 
309         void staticdtor(Symbol *s)
310         {
311             mixin(genRetVoid("staticdtor(s)"));
312         }
313 
314         void setModuleCtorDtor(Symbol *s, bool isCtor)
315         {
316             mixin(genRetVoid("setModuleCtorDtor(s, isCtor)"));
317         }
318 
319         void ehtables(Symbol *sfunc,uint size,Symbol *ehsym)
320         {
321             mixin(genRetVoid("ehtables(sfunc, size, ehsym)"));
322         }
323 
324         void ehsections()
325         {
326             mixin(genRetVoid("ehsections()"));
327         }
328 
329         void moduleinfo(Symbol *scc)
330         {
331             mixin(genRetVoid("moduleinfo(scc)"));
332         }
333 
334         int comdat(Symbol *s)
335         {
336             mixin(genRetVal("comdat(s)"));
337         }
338 
339         int comdatsize(Symbol *s, targ_size_t symsize)
340         {
341             mixin(genRetVal("comdatsize(s, symsize)"));
342         }
343 
344         int readonly_comdat(Symbol *s)
345         {
346             mixin(genRetVal("comdat(s)"));
347         }
348 
349         void setcodeseg(int seg)
350         {
351             mixin(genRetVoid("setcodeseg(seg)"));
352         }
353 
354         seg_data *tlsseg()
355         {
356             mixin(genRetVal("tlsseg()"));
357         }
358 
359         seg_data *tlsseg_bss()
360         {
361             mixin(genRetVal("tlsseg_bss()"));
362         }
363 
364         seg_data *tlsseg_data()
365         {
366             mixin(genRetVal("tlsseg_data()"));
367         }
368 
369         int  fardata(char *name, targ_size_t size, targ_size_t *poffset)
370         {
371             assert(config.objfmt == OBJ_OMF);
372             return OmfObj_fardata(name, size, poffset);
373         }
374 
375         void export_symbol(Symbol *s, uint argsize)
376         {
377             mixin(genRetVoid("export_symbol(s, argsize)"));
378         }
379 
380         void pubdef(int seg, Symbol *s, targ_size_t offset)
381         {
382             mixin(genRetVoid("pubdef(seg, s, offset)"));
383         }
384 
385         void pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize)
386         {
387             mixin(genRetVoid("pubdefsize(seg, s, offset, symsize)"));
388         }
389 
390         int external_def(const(char)* name)
391         {
392             mixin(genRetVal("external_def(name)"));
393         }
394 
395         int data_start(Symbol *sdata, targ_size_t datasize, int seg)
396         {
397             mixin(genRetVal("data_start(sdata, datasize, seg)"));
398         }
399 
400         int external(Symbol *s)
401         {
402             mixin(genRetVal("external(s)"));
403         }
404 
405         int common_block(Symbol *s, targ_size_t size, targ_size_t count)
406         {
407             mixin(genRetVal("common_block(s, size, count)"));
408         }
409 
410         int common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count)
411         {
412             mixin(genRetVal("common_block(s, flag, size, count)"));
413         }
414 
415         void lidata(int seg, targ_size_t offset, targ_size_t count)
416         {
417             mixin(genRetVoid("lidata(seg, offset, count)"));
418         }
419 
420         void write_zeros(seg_data *pseg, targ_size_t count)
421         {
422             mixin(genRetVoid("write_zeros(pseg, count)"));
423         }
424 
425         void write_byte(seg_data *pseg, uint _byte)
426         {
427             mixin(genRetVoid("write_byte(pseg, _byte)"));
428         }
429 
430         void write_bytes(seg_data *pseg, uint nbytes, void *p)
431         {
432             mixin(genRetVoid("write_bytes(pseg, nbytes, p)"));
433         }
434 
435         void _byte(int seg, targ_size_t offset, uint _byte)
436         {
437             mixin(genRetVoid("byte(seg, offset, _byte)"));
438         }
439 
440         uint bytes(int seg, targ_size_t offset, uint nbytes, void *p)
441         {
442             mixin(genRetVal("bytes(seg, offset, nbytes, p)"));
443         }
444 
445         void ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2)
446         {
447             assert(config.objfmt == OBJ_OMF);
448             OmfObj_ledata(seg, offset, data, lcfd, idx1, idx2);
449         }
450 
451         void reftodatseg(int seg, targ_size_t offset, targ_size_t val, uint targetdatum, int flags)
452         {
453             mixin(genRetVoid("reftodatseg(seg, offset, val, targetdatum, flags)"));
454         }
455 
456         void reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags)
457         {
458             assert(config.objfmt == OBJ_OMF);
459             OmfObj_reftofarseg(seg, offset, val, farseg, flags);
460         }
461 
462         void reftocodeseg(int seg, targ_size_t offset, targ_size_t val)
463         {
464             mixin(genRetVoid("reftocodeseg(seg, offset, val)"));
465         }
466 
467         int reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags)
468         {
469             mixin(genRetVal("reftoident(seg, offset, s, val, flags)"));
470         }
471 
472         void far16thunk(Symbol *s)
473         {
474             mixin(genRetVoid("far16thunk(s)"));
475         }
476 
477         void fltused()
478         {
479             mixin(genRetVoid("fltused()"));
480         }
481 
482         int data_readonly(char *p, int len, int *pseg)
483         {
484             mixin(genRetVal("data_readonly(p, len, pseg)"));
485         }
486 
487         int data_readonly(char *p, int len)
488         {
489             mixin(genRetVal("data_readonly(p, len)"));
490         }
491 
492         int string_literal_segment(uint sz)
493         {
494             mixin(genRetVal("string_literal_segment(sz)"));
495         }
496 
497         Symbol *sym_cdata(tym_t ty, char *p, int len)
498         {
499             mixin(genRetVal("sym_cdata(ty, p, len)"));
500         }
501 
502         void func_start(Symbol *sfunc)
503         {
504             mixin(genRetVoid("func_start(sfunc)"));
505         }
506 
507         void func_term(Symbol *sfunc)
508         {
509             mixin(genRetVoid("func_term(sfunc)"));
510         }
511 
512         void write_pointerRef(Symbol* s, uint off)
513         {
514             mixin(genRetVoid("write_pointerRef(s, off)"));
515         }
516 
517         int jmpTableSegment(Symbol* s)
518         {
519             mixin(genRetVal("jmpTableSegment(s)"));
520         }
521 
522         Symbol *tlv_bootstrap()
523         {
524             mixin(genRetVal("tlv_bootstrap()"));
525         }
526 
527         void gotref(Symbol *s)
528         {
529             switch (config.objfmt)
530             {
531                 case OBJ_ELF:     ElfObj_gotref(s); break;
532                 case OBJ_MACH:   MachObj_gotref(s); break;
533                 default:         assert(0);
534             }
535         }
536 
537         Symbol *getGOTsym()
538         {
539             switch (config.objfmt)
540             {
541                 case OBJ_ELF:    return  ElfObj_getGOTsym();
542                 case OBJ_MACH:   return MachObj_getGOTsym();
543                 default:         assert(0);
544             }
545         }
546 
547         void refGOTsym()
548         {
549             switch (config.objfmt)
550             {
551                 case OBJ_ELF:     ElfObj_refGOTsym(); break;
552                 case OBJ_MACH:   MachObj_refGOTsym(); break;
553                 default:         assert(0);
554             }
555         }
556 
557         int seg_debugT()           // where the symbolic debug type data goes
558         {
559             switch (config.objfmt)
560             {
561                 case OBJ_MSCOFF: return MsCoffObj_seg_debugT();
562                 case OBJ_OMF:    return    OmfObj_seg_debugT();
563                 default:         assert(0);
564             }
565         }
566 
567         void write_long(int seg, targ_size_t offset, uint data, uint lcfd, uint idx1, uint idx2)
568         {
569             assert(config.objfmt == OBJ_OMF);
570             return OmfObj_write_long(seg, offset, data, lcfd, idx1, idx2);
571         }
572 
573         uint addstr(Outbuffer *strtab, const(char)* p)
574         {
575             switch (config.objfmt)
576             {
577                 case OBJ_ELF:    return    ElfObj_addstr(strtab, p);
578                 case OBJ_MACH:   return   MachObj_addstr(strtab, p);
579                 default:         assert(0);
580             }
581         }
582 
583         int getsegment(const(char)* sectname, const(char)* segname, int align_, int flags)
584         {
585             assert(config.objfmt == OBJ_MACH);
586             return MachObj_getsegment(sectname, segname, align_, flags);
587         }
588 
589         int getsegment(const(char)* name, const(char)* suffix, int type, int flags, int  align_)
590         {
591             assert(config.objfmt == OBJ_ELF);
592             return ElfObj_getsegment(name, suffix, type, flags, align_);
593         }
594 
595         int getsegment(const(char)* sectname, uint flags)
596         {
597             assert(config.objfmt == OBJ_MSCOFF);
598             return MsCoffObj_getsegment(sectname, flags);
599         }
600 
601         void addrel(int seg, targ_size_t offset, Symbol *targsym, uint targseg, int rtype, int val = 0)
602         {
603             switch (config.objfmt)
604             {
605                 case OBJ_MSCOFF: return MsCoffObj_addrel(seg, offset, targsym, targseg, rtype, val);
606                 case OBJ_MACH:   return   MachObj_addrel(seg, offset, targsym, targseg, rtype, val);
607                 default:         assert(0);
608             }
609         }
610 
611         void addrel(int seg, targ_size_t offset, uint type, uint symidx, targ_size_t val)
612         {
613             assert(config.objfmt == OBJ_ELF);
614             return ElfObj_addrel(seg, offset, type, symidx, val);
615         }
616 
617         size_t writerel(int targseg, size_t offset, uint type, uint symidx, targ_size_t val)
618         {
619             assert(config.objfmt == OBJ_ELF);
620             return ElfObj_writerel(targseg, offset, type, symidx, val);
621         }
622 
623         int  getsegment2(uint shtidx)
624         {
625             assert(config.objfmt == OBJ_MSCOFF);
626             return MsCoffObj_getsegment2(shtidx);
627         }
628 
629         uint addScnhdr(const(char)* scnhdr_name, uint flags)
630         {
631             assert(config.objfmt == OBJ_MSCOFF);
632             return MsCoffObj_addScnhdr(scnhdr_name, flags);
633         }
634 
635         int  seg_drectve()
636         {
637             assert(config.objfmt == OBJ_MSCOFF);
638             return MsCoffObj_seg_drectve();
639         }
640 
641         int  seg_pdata()
642         {
643             assert(config.objfmt == OBJ_MSCOFF);
644             return MsCoffObj_seg_pdata();
645         }
646 
647         int  seg_xdata()
648         {
649             assert(config.objfmt == OBJ_MSCOFF);
650             return MsCoffObj_seg_xdata();
651         }
652 
653         int  seg_pdata_comdat(Symbol *sfunc)
654         {
655             assert(config.objfmt == OBJ_MSCOFF);
656             return MsCoffObj_seg_pdata_comdat(sfunc);
657         }
658 
659         int  seg_xdata_comdat(Symbol *sfunc)
660         {
661             assert(config.objfmt == OBJ_MSCOFF);
662             return MsCoffObj_seg_xdata_comdat(sfunc);
663         }
664 
665         int  seg_debugS()
666         {
667             assert(config.objfmt == OBJ_MSCOFF);
668             return MsCoffObj_seg_debugS();
669         }
670 
671         int  seg_debugS_comdat(Symbol *sfunc)
672         {
673             assert(config.objfmt == OBJ_MSCOFF);
674             return MsCoffObj_seg_debugS_comdat(sfunc);
675         }
676       }
677     }
678 }
679 
680 
681 extern __gshared Obj objmod;
682 
683 /*****************************************
684  * Use to generate 4 function declarations, one for
685  * each object file format supported.
686  * Params:
687  *      pattern = function declaration
688  * Returns:
689  *      declarations as a string suitable for mixin
690  */
691 private extern (D)
692 string ObjMemDecl(string pattern)
693 {
694     string r =
695         gen(pattern,    "Omf") ~ ";\n" ~
696         gen(pattern, "MsCoff") ~ ";\n" ~
697         gen(pattern,    "Elf") ~ ";\n" ~
698         gen(pattern,   "Mach") ~ ";\n";
699     return r;
700 }
701 
702 /****************************************
703  * Generate boilerplate for static dispatch that
704  * returns a void.
705  * Params:
706  *      arg = string to insert where ever there's a '$'
707  * Returns:
708  *      mixin string with static dispatch
709  */
710 private extern (D)
711 string genRetVoid(string arg)
712 {
713     string pattern =
714     "
715         switch (config.objfmt)
716         {
717             case OBJ_ELF:       ElfObj_$; break;
718             case OBJ_MSCOFF: MsCoffObj_$; break;
719             case OBJ_OMF:       OmfObj_$; break;
720             case OBJ_MACH:     MachObj_$; break;
721             default:     assert(0);
722         }
723     ";
724     return gen(pattern, arg);
725 }
726 
727 /****************************************
728  * Generate boilerplate for static dispatch that
729  * returns a value. Don't care about type of the value.
730  * Params:
731  *      arg = string to insert where ever there's a '$'
732  * Returns:
733  *      mixin string with static dispatch
734  */
735 private extern (D)
736 string genRetVal(string arg)
737 {
738     string pattern =
739     "
740         switch (config.objfmt)
741         {
742             case OBJ_ELF:    return    ElfObj_$;
743             case OBJ_MSCOFF: return MsCoffObj_$;
744             case OBJ_OMF:    return    OmfObj_$;
745             case OBJ_MACH:   return   MachObj_$;
746             default:     assert(0);
747         }
748     ";
749     return gen(pattern, arg);
750 }
751 
752 /****************************************
753  * Generate boilerplate that replaces '$' in pattern with `arg`
754  * Params:
755  *      pattern = pattern to scan for '$'
756  *      arg = string to insert where ever '$' is found
757  * Returns:
758  *      boilerplate string
759  */
760 private extern (D)
761 string gen(string pattern, string arg)
762 {
763     size_t count;               // number of '$' in pattern
764     foreach (c; pattern)
765         count += (c == '$');
766 
767     // length of result
768     const length = pattern.length - count + arg.length * count;
769 
770     char[] result = new char[length];
771     size_t i;
772     foreach (c; pattern)
773     {
774         if (c == '$')
775         {
776             result[i .. i + arg.length] = arg[]; // substitution
777             i += arg.length;
778         }
779         else
780         {
781             result[i] = c;
782             ++i;
783         }
784     }
785     assert(i == length);
786     return cast(string)result;
787 }
788 
789