1 /**
2  * Compiler implementation of the
3  * $(LINK2 https://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1994-1998 by Symantec
6  *              Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 https://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 
24 import dmd.common.outbuffer;
25 
26 nothrow:
27 
28 version (Windows)
29 {
30 }
31 else version (Posix)
32 {
33 }
34 else
35     static assert(0, "unsupported version");
36 
37 /******************************************************************/
38 
39 import dmd.backend.cgobj;
40 import dmd.backend.mscoffobj;
41 import dmd.backend.elfobj;
42 import dmd.backend.machobj;
43 
44 /******************************************************************/
45 
46 version (STUB)
47 {
48     public import stubobj;
49 }
50 else
51 {
52     /*******************************************
53      * Generic interface to the four object module file formats supported.
54      * Instead of using virtual functions (i.e. virtual dispatch) it uses
55      * static dispatch. Since config.objfmt never changes after initialization
56      * of the compiler, static branch prediction should make it faster than
57      * virtual dispatch.
58      *
59      * Making static dispatch work requires tediously repetitive boilerplate,
60      * which we accomplish via string mixins.
61      */
62     class Obj
63     {
64       static
65       {
66         nothrow:
67 
68         Obj initialize(OutBuffer* objbuf, const(char)* filename, const(char)* csegname)
69         {
70             mixin(genRetVal("init(objbuf, filename, csegname)"));
71         }
72 
73         void initfile(const(char)* filename, const(char)* csegname, const(char)* modname)
74         {
75             mixin(genRetVal("initfile(filename, csegname, modname)"));
76         }
77 
78         void termfile()
79         {
80             mixin(genRetVal("termfile()"));
81         }
82 
83         void term(const(char)* objfilename)
84         {
85             mixin(genRetVal("term(objfilename)"));
86         }
87 
88         size_t mangle(Symbol *s,char *dest)
89         {
90             assert(config.objfmt == OBJ_OMF);
91             return OmfObj_mangle(s, dest);
92         }
93 
94         void _import(elem *e)
95         {
96             assert(config.objfmt == OBJ_OMF);
97             return OmfObj_import(e);
98         }
99 
100         void linnum(Srcpos srcpos, int seg, targ_size_t offset)
101         {
102             mixin(genRetVal("linnum(srcpos, seg, offset)"));
103         }
104 
105         int codeseg(const char *name,int suffix)
106         {
107             mixin(genRetVal("codeseg(name, suffix)"));
108         }
109 
110         void dosseg()
111         {
112             assert(config.objfmt == OBJ_OMF);
113             return OmfObj_dosseg();
114         }
115 
116         void startaddress(Symbol *s)
117         {
118             mixin(genRetVal("startaddress(s)"));
119         }
120 
121         bool includelib(scope const(char)[] name)
122         {
123             mixin(genRetVal("includelib(name)"));
124         }
125 
126         bool linkerdirective(const(char)* p)
127         {
128             mixin(genRetVal("linkerdirective(p)"));
129         }
130 
131         bool allowZeroSize()
132         {
133             mixin(genRetVal("allowZeroSize()"));
134         }
135 
136         void exestr(const(char)* p)
137         {
138             mixin(genRetVal("exestr(p)"));
139         }
140 
141         void user(const(char)* p)
142         {
143             mixin(genRetVal("user(p)"));
144         }
145 
146         void compiler(const(char)* p)
147         {
148             mixin(genRetVal("compiler(p)"));
149         }
150 
151         void wkext(Symbol* s1, Symbol* s2)
152         {
153             mixin(genRetVal("wkext(s1, s2)"));
154         }
155 
156         void lzext(Symbol* s1, Symbol* s2)
157         {
158             assert(config.objfmt == OBJ_OMF);
159             OmfObj_lzext(s1, s2);
160         }
161 
162         void _alias(const(char)* n1,const(char)* n2)
163         {
164             mixin(genRetVal("alias(n1, n2)"));
165         }
166 
167         void theadr(const(char)* modname)
168         {
169             assert(config.objfmt == OBJ_OMF);
170             OmfObj_theadr(modname);
171         }
172 
173         void segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize)
174         {
175             assert(config.objfmt == OBJ_OMF);
176             OmfObj_segment_group(codesize, datasize, cdatasize, udatasize);
177         }
178 
179         void staticctor(Symbol *s,int dtor,int seg)
180         {
181             mixin(genRetVal("staticctor(s, dtor, seg)"));
182         }
183 
184         void staticdtor(Symbol *s)
185         {
186             mixin(genRetVal("staticdtor(s)"));
187         }
188 
189         void setModuleCtorDtor(Symbol *s, bool isCtor)
190         {
191             mixin(genRetVal("setModuleCtorDtor(s, isCtor)"));
192         }
193 
194         void ehtables(Symbol *sfunc,uint size,Symbol *ehsym)
195         {
196             mixin(genRetVal("ehtables(sfunc, size, ehsym)"));
197         }
198 
199         void ehsections()
200         {
201             mixin(genRetVal("ehsections()"));
202         }
203 
204         void moduleinfo(Symbol *scc)
205         {
206             mixin(genRetVal("moduleinfo(scc)"));
207         }
208 
209         int comdat(Symbol *s)
210         {
211             mixin(genRetVal("comdat(s)"));
212         }
213 
214         int comdatsize(Symbol *s, targ_size_t symsize)
215         {
216             mixin(genRetVal("comdatsize(s, symsize)"));
217         }
218 
219         int readonly_comdat(Symbol *s)
220         {
221             mixin(genRetVal("comdat(s)"));
222         }
223 
224         void setcodeseg(int seg)
225         {
226             mixin(genRetVal("setcodeseg(seg)"));
227         }
228 
229         seg_data *tlsseg()
230         {
231             mixin(genRetVal("tlsseg()"));
232         }
233 
234         seg_data *tlsseg_bss()
235         {
236             mixin(genRetVal("tlsseg_bss()"));
237         }
238 
239         seg_data *tlsseg_data()
240         {
241             mixin(genRetVal("tlsseg_data()"));
242         }
243 
244         int  fardata(char *name, targ_size_t size, targ_size_t *poffset)
245         {
246             assert(config.objfmt == OBJ_OMF);
247             return OmfObj_fardata(name, size, poffset);
248         }
249 
250         void export_symbol(Symbol *s, uint argsize)
251         {
252             mixin(genRetVal("export_symbol(s, argsize)"));
253         }
254 
255         void pubdef(int seg, Symbol *s, targ_size_t offset)
256         {
257             mixin(genRetVal("pubdef(seg, s, offset)"));
258         }
259 
260         void pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize)
261         {
262             mixin(genRetVal("pubdefsize(seg, s, offset, symsize)"));
263         }
264 
265         int external_def(const(char)* name)
266         {
267             mixin(genRetVal("external_def(name)"));
268         }
269 
270         int data_start(Symbol *sdata, targ_size_t datasize, int seg)
271         {
272             mixin(genRetVal("data_start(sdata, datasize, seg)"));
273         }
274 
275         int external(Symbol *s)
276         {
277             mixin(genRetVal("external(s)"));
278         }
279 
280         int common_block(Symbol *s, targ_size_t size, targ_size_t count)
281         {
282             mixin(genRetVal("common_block(s, size, count)"));
283         }
284 
285         int common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count)
286         {
287             mixin(genRetVal("common_block(s, flag, size, count)"));
288         }
289 
290         void lidata(int seg, targ_size_t offset, targ_size_t count)
291         {
292             mixin(genRetVal("lidata(seg, offset, count)"));
293         }
294 
295         void write_zeros(seg_data *pseg, targ_size_t count)
296         {
297             mixin(genRetVal("write_zeros(pseg, count)"));
298         }
299 
300         void write_byte(seg_data *pseg, uint _byte)
301         {
302             mixin(genRetVal("write_byte(pseg, _byte)"));
303         }
304 
305         void write_bytes(seg_data *pseg, const(void[]) a)
306         {
307             mixin(genRetVal("write_bytes(pseg, a)"));
308         }
309 
310         void _byte(int seg, targ_size_t offset, uint _byte)
311         {
312             mixin(genRetVal("byte(seg, offset, _byte)"));
313         }
314 
315         size_t bytes(int seg, targ_size_t offset, size_t nbytes, const(void)* p)
316         {
317             mixin(genRetVal("bytes(seg, offset, nbytes, p)"));
318         }
319 
320         void ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2)
321         {
322             assert(config.objfmt == OBJ_OMF);
323             OmfObj_ledata(seg, offset, data, lcfd, idx1, idx2);
324         }
325 
326         void reftodatseg(int seg, targ_size_t offset, targ_size_t val, uint targetdatum, int flags)
327         {
328             mixin(genRetVal("reftodatseg(seg, offset, val, targetdatum, flags)"));
329         }
330 
331         void reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags)
332         {
333             assert(config.objfmt == OBJ_OMF);
334             OmfObj_reftofarseg(seg, offset, val, farseg, flags);
335         }
336 
337         void reftocodeseg(int seg, targ_size_t offset, targ_size_t val)
338         {
339             mixin(genRetVal("reftocodeseg(seg, offset, val)"));
340         }
341 
342         int reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags)
343         {
344             mixin(genRetVal("reftoident(seg, offset, s, val, flags)"));
345         }
346 
347         void far16thunk(Symbol *s)
348         {
349             mixin(genRetVal("far16thunk(s)"));
350         }
351 
352         void fltused()
353         {
354             mixin(genRetVal("fltused()"));
355         }
356 
357         int data_readonly(char *p, int len, int *pseg)
358         {
359             mixin(genRetVal("data_readonly(p, len, pseg)"));
360         }
361 
362         int data_readonly(char *p, int len)
363         {
364             mixin(genRetVal("data_readonly(p, len)"));
365         }
366 
367         int string_literal_segment(uint sz)
368         {
369             mixin(genRetVal("string_literal_segment(sz)"));
370         }
371 
372         Symbol *sym_cdata(tym_t ty, char *p, int len)
373         {
374             mixin(genRetVal("sym_cdata(ty, p, len)"));
375         }
376 
377         void func_start(Symbol *sfunc)
378         {
379             mixin(genRetVal("func_start(sfunc)"));
380         }
381 
382         void func_term(Symbol *sfunc)
383         {
384             mixin(genRetVal("func_term(sfunc)"));
385         }
386 
387         void write_pointerRef(Symbol* s, uint off)
388         {
389             mixin(genRetVal("write_pointerRef(s, off)"));
390         }
391 
392         int jmpTableSegment(Symbol* s)
393         {
394             mixin(genRetVal("jmpTableSegment(s)"));
395         }
396 
397         Symbol *tlv_bootstrap()
398         {
399             mixin(genRetVal("tlv_bootstrap()"));
400         }
401 
402         void gotref(Symbol *s)
403         {
404             switch (config.objfmt)
405             {
406                 case OBJ_ELF:     ElfObj_gotref(s); break;
407                 case OBJ_MACH:   MachObj_gotref(s); break;
408                 default:         assert(0);
409             }
410         }
411 
412         Symbol *getGOTsym()
413         {
414             switch (config.objfmt)
415             {
416                 case OBJ_ELF:    return  ElfObj_getGOTsym();
417                 case OBJ_MACH:   return MachObj_getGOTsym();
418                 default:         assert(0);
419             }
420         }
421 
422         void refGOTsym()
423         {
424             switch (config.objfmt)
425             {
426                 case OBJ_ELF:     ElfObj_refGOTsym(); break;
427                 case OBJ_MACH:   MachObj_refGOTsym(); break;
428                 default:         assert(0);
429             }
430         }
431 
432         int seg_debugT()           // where the symbolic debug type data goes
433         {
434             switch (config.objfmt)
435             {
436                 case OBJ_MSCOFF: return MsCoffObj_seg_debugT();
437                 case OBJ_OMF:    return    OmfObj_seg_debugT();
438                 default:         assert(0);
439             }
440         }
441 
442         void write_long(int seg, targ_size_t offset, uint data, uint lcfd, uint idx1, uint idx2)
443         {
444             assert(config.objfmt == OBJ_OMF);
445             return OmfObj_write_long(seg, offset, data, lcfd, idx1, idx2);
446         }
447 
448         uint addstr(OutBuffer *strtab, const(char)* p)
449         {
450             switch (config.objfmt)
451             {
452                 case OBJ_ELF:    return    ElfObj_addstr(strtab, p);
453                 case OBJ_MACH:   return   MachObj_addstr(strtab, p);
454                 default:         assert(0);
455             }
456         }
457 
458         int getsegment(const(char)* sectname, const(char)* segname, int align_, int flags)
459         {
460             assert(config.objfmt == OBJ_MACH);
461             return MachObj_getsegment(sectname, segname, align_, flags);
462         }
463 
464         int getsegment(const(char)* name, const(char)* suffix, int type, int flags, int  align_)
465         {
466             assert(config.objfmt == OBJ_ELF);
467             return ElfObj_getsegment(name, suffix, type, flags, align_);
468         }
469 
470         int getsegment(const(char)* sectname, uint flags)
471         {
472             assert(config.objfmt == OBJ_MSCOFF);
473             return MsCoffObj_getsegment(sectname, flags);
474         }
475 
476         void addrel(int seg, targ_size_t offset, Symbol *targsym, uint targseg, int rtype, int val = 0)
477         {
478             switch (config.objfmt)
479             {
480                 case OBJ_MSCOFF: return MsCoffObj_addrel(seg, offset, targsym, targseg, rtype, val);
481                 case OBJ_MACH:   return   MachObj_addrel(seg, offset, targsym, targseg, rtype, val);
482                 default:         assert(0);
483             }
484         }
485 
486         void addrel(int seg, targ_size_t offset, uint type, uint symidx, targ_size_t val)
487         {
488             assert(config.objfmt == OBJ_ELF);
489             return ElfObj_addrel(seg, offset, type, symidx, val);
490         }
491 
492         size_t writerel(int targseg, size_t offset, uint type, uint symidx, targ_size_t val)
493         {
494             assert(config.objfmt == OBJ_ELF);
495             return ElfObj_writerel(targseg, offset, type, symidx, val);
496         }
497 
498         int  getsegment2(uint shtidx)
499         {
500             assert(config.objfmt == OBJ_MSCOFF);
501             return MsCoffObj_getsegment2(shtidx);
502         }
503 
504         uint addScnhdr(const(char)* scnhdr_name, uint flags)
505         {
506             assert(config.objfmt == OBJ_MSCOFF);
507             return MsCoffObj_addScnhdr(scnhdr_name, flags);
508         }
509 
510         int  seg_drectve()
511         {
512             assert(config.objfmt == OBJ_MSCOFF);
513             return MsCoffObj_seg_drectve();
514         }
515 
516         int  seg_pdata()
517         {
518             assert(config.objfmt == OBJ_MSCOFF);
519             return MsCoffObj_seg_pdata();
520         }
521 
522         int  seg_xdata()
523         {
524             assert(config.objfmt == OBJ_MSCOFF);
525             return MsCoffObj_seg_xdata();
526         }
527 
528         int  seg_pdata_comdat(Symbol *sfunc)
529         {
530             assert(config.objfmt == OBJ_MSCOFF);
531             return MsCoffObj_seg_pdata_comdat(sfunc);
532         }
533 
534         int  seg_xdata_comdat(Symbol *sfunc)
535         {
536             assert(config.objfmt == OBJ_MSCOFF);
537             return MsCoffObj_seg_xdata_comdat(sfunc);
538         }
539 
540         int  seg_debugS()
541         {
542             assert(config.objfmt == OBJ_MSCOFF);
543             return MsCoffObj_seg_debugS();
544         }
545 
546         int  seg_debugS_comdat(Symbol *sfunc)
547         {
548             assert(config.objfmt == OBJ_MSCOFF);
549             return MsCoffObj_seg_debugS_comdat(sfunc);
550         }
551       }
552     }
553 }
554 
555 public import dmd.backend.var : objmod;
556 
557 /*****************************************
558  * Use to generate 4 function declarations, one for
559  * each object file format supported.
560  * Params:
561  *      pattern = function declaration
562  * Returns:
563  *      declarations as a string suitable for mixin
564  */
565 private extern (D)
566 string ObjMemDecl(string pattern)
567 {
568     string r =
569         gen(pattern,    "Omf") ~ ";\n" ~
570         gen(pattern, "MsCoff") ~ ";\n" ~
571         gen(pattern,    "Elf") ~ ";\n" ~
572         gen(pattern,   "Mach") ~ ";\n";
573     return r;
574 }
575 
576 /****************************************
577  * Generate boilerplate for static dispatch that
578  * returns a value. Don't care about type of the value.
579  * Params:
580  *      arg = function name to be dispatched based on `objfmt`
581  * Returns:
582  *      mixin string with static dispatch
583  */
584 private extern (D)
585 string genRetVal(string arg)
586 {
587     return
588     "
589         switch (config.objfmt)
590         {
591             case OBJ_ELF:    return    ElfObj_"~arg~";
592             case OBJ_MSCOFF: return MsCoffObj_"~arg~";
593             case OBJ_OMF:    return    OmfObj_"~arg~";
594             case OBJ_MACH:   return   MachObj_"~arg~";
595             default:     assert(0);
596         }
597     ";
598 }
599 
600 /****************************************
601  * Generate boilerplate that replaces the single '$' in `pattern` with `arg`
602  * Params:
603  *      pattern = pattern to scan for '$'
604  *      arg = string to insert where '$' is found
605  * Returns:
606  *      boilerplate string
607  */
608 private extern (D)
609 string gen(string pattern, string arg)
610 {
611     foreach (i; 0 .. pattern.length)
612         if (pattern[i] == '$')
613             return pattern[0 .. i] ~ arg ~ pattern[i + 1 .. $];
614     assert(0);
615 }