1 /**
2  * Convert an AST that went through all semantic phases into an object file.
3  *
4  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/tocsym.d, _toobj.d)
8  * Documentation:  https://dlang.org/phobos/dmd_toobj.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/toobj.d
10  */
11 
12 module dmd.toobj;
13 
14 import core.stdc.stdio;
15 import core.stdc.stddef;
16 import core.stdc..string;
17 import core.stdc.time;
18 
19 import dmd.root.array;
20 import dmd.root.outbuffer;
21 import dmd.root.rmem;
22 import dmd.root.rootobject;
23 
24 import dmd.aggregate;
25 import dmd.arraytypes;
26 import dmd.attrib;
27 import dmd.dclass;
28 import dmd.declaration;
29 import dmd.denum;
30 import dmd.dmodule;
31 import dmd.dscope;
32 import dmd.dstruct;
33 import dmd.dsymbol;
34 import dmd.dtemplate;
35 import dmd.errors;
36 import dmd.expression;
37 import dmd.func;
38 import dmd.globals;
39 import dmd.glue;
40 import dmd.hdrgen;
41 import dmd.id;
42 import dmd.init;
43 import dmd.mtype;
44 import dmd.nspace;
45 import dmd.objc_glue;
46 import dmd.statement;
47 import dmd.staticassert;
48 import dmd.target;
49 import dmd.tocsym;
50 import dmd.toctype;
51 import dmd.tocvdebug;
52 import dmd.todt;
53 import dmd.tokens;
54 import dmd.traits;
55 import dmd.typinf;
56 import dmd.visitor;
57 
58 import dmd.backend.cc;
59 import dmd.backend.cdef;
60 import dmd.backend.cgcv;
61 import dmd.backend.code;
62 import dmd.backend.code_x86;
63 import dmd.backend.cv4;
64 import dmd.backend.dt;
65 import dmd.backend.el;
66 import dmd.backend.global;
67 import dmd.backend.obj;
68 import dmd.backend.oper;
69 import dmd.backend.ty;
70 import dmd.backend.type;
71 
72 extern (C++):
73 
74 alias toSymbol = dmd.tocsym.toSymbol;
75 alias toSymbol = dmd.glue.toSymbol;
76 
77 
78 /* ================================================================== */
79 
80 // Put out instance of ModuleInfo for this Module
81 
82 void genModuleInfo(Module m)
83 {
84     //printf("Module.genmoduleinfo() %s\n", m.toChars());
85 
86     if (!Module.moduleinfo)
87     {
88         ObjectNotFound(Id.ModuleInfo);
89     }
90 
91     Symbol *msym = toSymbol(m);
92 
93     //////////////////////////////////////////////
94 
95     m.csym.Sclass = SCglobal;
96     m.csym.Sfl = FLdata;
97 
98     auto dtb = DtBuilder(0);
99     ClassDeclarations aclasses;
100 
101     //printf("members.dim = %d\n", members.dim);
102     foreach (i; 0 .. m.members.dim)
103     {
104         Dsymbol member = (*m.members)[i];
105 
106         //printf("\tmember '%s'\n", member.toChars());
107         member.addLocalClass(&aclasses);
108     }
109 
110     // importedModules[]
111     size_t aimports_dim = m.aimports.dim;
112     for (size_t i = 0; i < m.aimports.dim; i++)
113     {
114         Module mod = m.aimports[i];
115         if (!mod.needmoduleinfo)
116             aimports_dim--;
117     }
118 
119     FuncDeclaration sgetmembers = m.findGetMembers();
120 
121     // These must match the values in druntime/src/object_.d
122     enum
123     {
124         MIstandalone      = 0x4,
125         MItlsctor         = 0x8,
126         MItlsdtor         = 0x10,
127         MIctor            = 0x20,
128         MIdtor            = 0x40,
129         MIxgetMembers     = 0x80,
130         MIictor           = 0x100,
131         MIunitTest        = 0x200,
132         MIimportedModules = 0x400,
133         MIlocalClasses    = 0x800,
134         MIname            = 0x1000,
135     }
136 
137     uint flags = 0;
138     if (!m.needmoduleinfo)
139         flags |= MIstandalone;
140     if (m.sctor)
141         flags |= MItlsctor;
142     if (m.sdtor)
143         flags |= MItlsdtor;
144     if (m.ssharedctor)
145         flags |= MIctor;
146     if (m.sshareddtor)
147         flags |= MIdtor;
148     if (sgetmembers)
149         flags |= MIxgetMembers;
150     if (m.sictor)
151         flags |= MIictor;
152     if (m.stest)
153         flags |= MIunitTest;
154     if (aimports_dim)
155         flags |= MIimportedModules;
156     if (aclasses.dim)
157         flags |= MIlocalClasses;
158     flags |= MIname;
159 
160     dtb.dword(flags);        // _flags
161     dtb.dword(0);            // _index
162 
163     if (flags & MItlsctor)
164         dtb.xoff(m.sctor, 0, TYnptr);
165     if (flags & MItlsdtor)
166         dtb.xoff(m.sdtor, 0, TYnptr);
167     if (flags & MIctor)
168         dtb.xoff(m.ssharedctor, 0, TYnptr);
169     if (flags & MIdtor)
170         dtb.xoff(m.sshareddtor, 0, TYnptr);
171     if (flags & MIxgetMembers)
172         dtb.xoff(toSymbol(sgetmembers), 0, TYnptr);
173     if (flags & MIictor)
174         dtb.xoff(m.sictor, 0, TYnptr);
175     if (flags & MIunitTest)
176         dtb.xoff(m.stest, 0, TYnptr);
177     if (flags & MIimportedModules)
178     {
179         dtb.size(aimports_dim);
180         foreach (i; 0 .. m.aimports.dim)
181         {
182             Module mod = m.aimports[i];
183 
184             if (!mod.needmoduleinfo)
185                 continue;
186 
187             Symbol *s = toSymbol(mod);
188 
189             /* Weak references don't pull objects in from the library,
190              * they resolve to 0 if not pulled in by something else.
191              * Don't pull in a module just because it was imported.
192              */
193             s.Sflags |= SFLweak;
194             dtb.xoff(s, 0, TYnptr);
195         }
196     }
197     if (flags & MIlocalClasses)
198     {
199         dtb.size(aclasses.dim);
200         foreach (i; 0 .. aclasses.dim)
201         {
202             ClassDeclaration cd = aclasses[i];
203             dtb.xoff(toSymbol(cd), 0, TYnptr);
204         }
205     }
206     if (flags & MIname)
207     {
208         // Put out module name as a 0-terminated string, to save bytes
209         m.nameoffset = dtb.length();
210         const(char) *name = m.toPrettyChars();
211         m.namelen = strlen(name);
212         dtb.nbytes(cast(uint)m.namelen + 1, name);
213         //printf("nameoffset = x%x\n", nameoffset);
214     }
215 
216     objc.generateModuleInfo(m);
217     m.csym.Sdt = dtb.finish();
218     out_readonly(m.csym);
219     outdata(m.csym);
220 
221     //////////////////////////////////////////////
222 
223     objmod.moduleinfo(msym);
224 }
225 
226 /*****************************************
227  * write pointer references for typed data to the object file
228  * a class type is considered to mean a reference to a class instance
229  * Params:
230  *      type   = type of the data to check for pointers
231  *      s      = symbol that contains the data
232  *      offset = offset of the data inside the Symbol's memory
233  */
234 void write_pointers(Type type, Symbol *s, uint offset)
235 {
236     uint ty = type.toBasetype().ty;
237     if (ty == Tclass)
238         return objmod.write_pointerRef(s, offset);
239 
240     write_instance_pointers(type, s, offset);
241 }
242 
243 /*****************************************
244 * write pointer references for typed data to the object file
245 * a class type is considered to mean the instance, not a reference
246 * Params:
247 *      type   = type of the data to check for pointers
248 *      s      = symbol that contains the data
249 *      offset = offset of the data inside the Symbol's memory
250 */
251 void write_instance_pointers(Type type, Symbol *s, uint offset)
252 {
253     if (!type.hasPointers())
254         return;
255 
256     Array!(d_uns64) data;
257     d_uns64 sz = getTypePointerBitmap(Loc.initial, type, &data);
258     if (sz == d_uns64.max)
259         return;
260 
261     const bytes_size_t = cast(size_t)Type.tsize_t.size(Loc.initial);
262     const bits_size_t = bytes_size_t * 8;
263     auto words = cast(size_t)(sz / bytes_size_t);
264     for (size_t i = 0; i < data.dim; i++)
265     {
266         size_t bits = words < bits_size_t ? words : bits_size_t;
267         for (size_t b = 0; b < bits; b++)
268             if (data[i] & (1L << b))
269             {
270                 auto off = cast(uint) ((i * bits_size_t + b) * bytes_size_t);
271                 objmod.write_pointerRef(s, off + offset);
272             }
273         words -= bits;
274     }
275 }
276 
277 /* ================================================================== */
278 
279 void toObjFile(Dsymbol ds, bool multiobj)
280 {
281     //printf("toObjFile(%s)\n", ds.toChars());
282     extern (C++) final class ToObjFile : Visitor
283     {
284         alias visit = Visitor.visit;
285     public:
286         bool multiobj;
287 
288         this(bool multiobj)
289         {
290             this.multiobj = multiobj;
291         }
292 
293         void visitNoMultiObj(Dsymbol ds)
294         {
295             bool multiobjsave = multiobj;
296             multiobj = false;
297             ds.accept(this);
298             multiobj = multiobjsave;
299         }
300 
301         override void visit(Dsymbol ds)
302         {
303             //printf("Dsymbol.toObjFile('%s')\n", ds.toChars());
304             // ignore
305         }
306 
307         override void visit(FuncDeclaration fd)
308         {
309             // in glue.c
310             FuncDeclaration_toObjFile(fd, multiobj);
311         }
312 
313         override void visit(ClassDeclaration cd)
314         {
315             //printf("ClassDeclaration.toObjFile('%s')\n", cd.toChars());
316 
317             if (cd.type.ty == Terror)
318             {
319                 cd.error("had semantic errors when compiling");
320                 return;
321             }
322 
323             if (!cd.members)
324                 return;
325 
326             if (multiobj && !cd.hasStaticCtorOrDtor())
327             {
328                 obj_append(cd);
329                 return;
330             }
331 
332             if (global.params.symdebugref)
333                 Type_toCtype(cd.type); // calls toDebug() only once
334             else if (global.params.symdebug)
335                 toDebug(cd);
336 
337             assert(cd.semanticRun >= PASS.semantic3done);     // semantic() should have been run to completion
338 
339             enum_SC scclass = SCcomdat;
340 
341             // Put out the members
342             /* There might be static ctors in the members, and they cannot
343              * be put in separate obj files.
344              */
345             cd.members.foreachDsymbol( (s) { s.accept(this); } );
346 
347             if (cd.classKind == ClassKind.objc)
348             {
349                 objc.toObjFile(cd);
350                 return;
351             }
352 
353             // If something goes wrong during this pass don't bother with the
354             // rest as we may have incomplete info
355             // https://issues.dlang.org/show_bug.cgi?id=17918
356             if (!finishVtbl(cd))
357             {
358                 return;
359             }
360 
361             const bool gentypeinfo = global.params.useTypeInfo && Type.dtypeinfo;
362             const bool genclassinfo = gentypeinfo || !(cd.isCPPclass || cd.isCOMclass);
363 
364             // Generate C symbols
365             if (genclassinfo)
366                 toSymbol(cd);                           // __ClassZ symbol
367             toVtblSymbol(cd);                           // __vtblZ symbol
368             Symbol *sinit = toInitializer(cd);          // __initZ symbol
369 
370             //////////////////////////////////////////////
371 
372             // Generate static initializer
373             {
374                 sinit.Sclass = scclass;
375                 sinit.Sfl = FLdata;
376                 auto dtb = DtBuilder(0);
377                 ClassDeclaration_toDt(cd, dtb);
378                 sinit.Sdt = dtb.finish();
379                 out_readonly(sinit);
380                 outdata(sinit);
381             }
382 
383             //////////////////////////////////////////////
384 
385             // Put out the TypeInfo
386             if (gentypeinfo)
387                 genTypeInfo(cd.loc, cd.type, null);
388             //toObjFile(cd.type.vtinfo, multiobj);
389 
390             if (genclassinfo)
391             {
392                 genClassInfoForClass(cd, sinit);
393             }
394 
395             //////////////////////////////////////////////
396 
397             // Put out the vtbl[]
398             //printf("putting out %s.vtbl[]\n", toChars());
399             auto dtbv = DtBuilder(0);
400             if (cd.vtblOffset())
401                 dtbv.xoff(cd.csym, 0, TYnptr);           // first entry is ClassInfo reference
402             foreach (i; cd.vtblOffset() .. cd.vtbl.dim)
403             {
404                 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
405 
406                 //printf("\tvtbl[%d] = %p\n", i, fd);
407                 if (fd && (fd.fbody || !cd.isAbstract()))
408                 {
409                     dtbv.xoff(toSymbol(fd), 0, TYnptr);
410                 }
411                 else
412                     dtbv.size(0);
413             }
414             if (dtbv.isZeroLength())
415             {
416                 /* Someone made an 'extern (C++) class C { }' with no virtual functions.
417                  * But making an empty vtbl[] causes linking problems, so make a dummy
418                  * entry.
419                  */
420                 dtbv.size(0);
421             }
422             cd.vtblsym.csym.Sdt = dtbv.finish();
423             cd.vtblsym.csym.Sclass = scclass;
424             cd.vtblsym.csym.Sfl = FLdata;
425             out_readonly(cd.vtblsym.csym);
426             outdata(cd.vtblsym.csym);
427             if (cd.isExport())
428                 objmod.export_symbol(cd.vtblsym.csym,0);
429         }
430 
431         override void visit(InterfaceDeclaration id)
432         {
433             //printf("InterfaceDeclaration.toObjFile('%s')\n", id.toChars());
434 
435             if (id.type.ty == Terror)
436             {
437                 id.error("had semantic errors when compiling");
438                 return;
439             }
440 
441             if (!id.members)
442                 return;
443 
444             if (global.params.symdebugref)
445                 Type_toCtype(id.type); // calls toDebug() only once
446             else if (global.params.symdebug)
447                 toDebug(id);
448 
449             // Put out the members
450             id.members.foreachDsymbol( (s) { visitNoMultiObj(s); } );
451 
452             // Generate C symbols
453             toSymbol(id);
454 
455             //////////////////////////////////////////////
456 
457             // Put out the TypeInfo
458             if (global.params.useTypeInfo && Type.dtypeinfo)
459             {
460                 genTypeInfo(id.loc, id.type, null);
461                 id.type.vtinfo.accept(this);
462             }
463 
464             //////////////////////////////////////////////
465 
466             genClassInfoForInterface(id);
467         }
468 
469         override void visit(StructDeclaration sd)
470         {
471             //printf("StructDeclaration.toObjFile('%s')\n", sd.toChars());
472 
473             if (sd.type.ty == Terror)
474             {
475                 sd.error("had semantic errors when compiling");
476                 return;
477             }
478 
479             if (multiobj && !sd.hasStaticCtorOrDtor())
480             {
481                 obj_append(sd);
482                 return;
483             }
484 
485             // Anonymous structs/unions only exist as part of others,
486             // do not output forward referenced structs's
487             if (!sd.isAnonymous() && sd.members)
488             {
489                 if (global.params.symdebugref)
490                     Type_toCtype(sd.type); // calls toDebug() only once
491                 else if (global.params.symdebug)
492                     toDebug(sd);
493 
494                 if (global.params.useTypeInfo && Type.dtypeinfo)
495                     genTypeInfo(sd.loc, sd.type, null);
496 
497                 // Generate static initializer
498                 auto sinit = toInitializer(sd);
499                 if (sinit.Sclass == SCextern)
500                 {
501                     if (sinit == bzeroSymbol) assert(0);
502                     sinit.Sclass = sd.isInstantiated() ? SCcomdat : SCglobal;
503                     sinit.Sfl = FLdata;
504                     auto dtb = DtBuilder(0);
505                     StructDeclaration_toDt(sd, dtb);
506                     sinit.Sdt = dtb.finish();
507 
508                     /* fails to link on OBJ_MACH 64 with:
509                      *  ld: in generated/osx/release/64/libphobos2.a(dwarfeh_8dc_56a.o),
510                      *  in section __TEXT,__textcoal_nt reloc 6:
511                      *  symbol index out of range for architecture x86_64
512                      */
513                     if (config.objfmt != OBJ_MACH &&
514                         dtallzeros(sinit.Sdt))
515                     {
516                         sinit.Sclass = SCglobal;
517                         dt2common(&sinit.Sdt);
518                     }
519                     else
520                         out_readonly(sinit);    // put in read-only segment
521                     outdata(sinit);
522                 }
523 
524                 // Put out the members
525                 /* There might be static ctors in the members, and they cannot
526                  * be put in separate obj files.
527                  */
528                 sd.members.foreachDsymbol( (s) { s.accept(this); } );
529 
530                 if (sd.xeq && sd.xeq != StructDeclaration.xerreq)
531                     sd.xeq.accept(this);
532                 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp)
533                     sd.xcmp.accept(this);
534                 if (sd.xhash)
535                     sd.xhash.accept(this);
536             }
537         }
538 
539         override void visit(VarDeclaration vd)
540         {
541 
542             //printf("VarDeclaration.toObjFile(%p '%s' type=%s) protection %d\n", vd, vd.toChars(), vd.type.toChars(), vd.protection);
543             //printf("\talign = %d\n", vd.alignment);
544 
545             if (vd.type.ty == Terror)
546             {
547                 vd.error("had semantic errors when compiling");
548                 return;
549             }
550 
551             if (vd.aliassym)
552             {
553                 visitNoMultiObj(vd.toAlias());
554                 return;
555             }
556 
557             // Do not store variables we cannot take the address of
558             if (!vd.canTakeAddressOf())
559             {
560                 return;
561             }
562 
563             if (!vd.isDataseg() || vd.storage_class & STC.extern_)
564                 return;
565 
566             Symbol *s = toSymbol(vd);
567             d_uns64 sz64 = vd.type.size(vd.loc);
568             if (sz64 == SIZE_INVALID)
569             {
570                 vd.error("size overflow");
571                 return;
572             }
573             if (sz64 >= target.maxStaticDataSize)
574             {
575                 vd.error("size of 0x%llx exceeds max allowed size 0x%llx", sz64, target.maxStaticDataSize);
576             }
577             uint sz = cast(uint)sz64;
578 
579             Dsymbol parent = vd.toParent();
580             s.Sclass = SCglobal;
581 
582             do
583             {
584                 /* Global template data members need to be in comdat's
585                  * in case multiple .obj files instantiate the same
586                  * template with the same types.
587                  */
588                 if (parent.isTemplateInstance() && !parent.isTemplateMixin())
589                 {
590                     s.Sclass = SCcomdat;
591                     break;
592                 }
593                 parent = parent.parent;
594             } while (parent);
595             s.Sfl = FLdata;
596 
597             if (!sz && vd.type.toBasetype().ty != Tsarray)
598                 assert(0); // this shouldn't be possible
599 
600             auto dtb = DtBuilder(0);
601             if (config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread)
602             {
603                 tlsToDt(vd, s, sz, dtb);
604             }
605             else if (!sz)
606             {
607                 /* Give it a byte of data
608                  * so we can take the 'address' of this symbol
609                  * and avoid problematic behavior of object file format
610                  */
611                 dtb.nzeros(1);
612             }
613             else if (vd._init)
614             {
615                 initializerToDt(vd, dtb);
616             }
617             else
618             {
619                 Type_toDt(vd.type, dtb);
620             }
621             s.Sdt = dtb.finish();
622 
623             // See if we can convert a comdat to a comdef,
624             // which saves on exe file space.
625             if (s.Sclass == SCcomdat &&
626                 s.Sdt &&
627                 dtallzeros(s.Sdt) &&
628                 !vd.isThreadlocal())
629             {
630                 s.Sclass = SCglobal;
631                 dt2common(&s.Sdt);
632             }
633 
634             outdata(s);
635             if (vd.type.isMutable() || !vd._init)
636                 write_pointers(vd.type, s, 0);
637             if (vd.isExport())
638                 objmod.export_symbol(s, 0);
639         }
640 
641         override void visit(EnumDeclaration ed)
642         {
643             if (ed.semanticRun >= PASS.obj)  // already written
644                 return;
645             //printf("EnumDeclaration.toObjFile('%s')\n", ed.toChars());
646 
647             if (ed.errors || ed.type.ty == Terror)
648             {
649                 ed.error("had semantic errors when compiling");
650                 return;
651             }
652 
653             if (ed.isAnonymous())
654                 return;
655 
656             if (global.params.symdebugref)
657                 Type_toCtype(ed.type); // calls toDebug() only once
658             else if (global.params.symdebug)
659                 toDebug(ed);
660 
661             if (global.params.useTypeInfo && Type.dtypeinfo)
662                 genTypeInfo(ed.loc, ed.type, null);
663 
664             TypeEnum tc = cast(TypeEnum)ed.type;
665             if (!tc.sym.members || ed.type.isZeroInit(Loc.initial))
666             {
667             }
668             else
669             {
670                 enum_SC scclass = SCglobal;
671                 if (ed.isInstantiated())
672                     scclass = SCcomdat;
673 
674                 // Generate static initializer
675                 toInitializer(ed);
676                 ed.sinit.Sclass = scclass;
677                 ed.sinit.Sfl = FLdata;
678                 auto dtb = DtBuilder(0);
679                 Expression_toDt(tc.sym.defaultval, dtb);
680                 ed.sinit.Sdt = dtb.finish();
681                 outdata(ed.sinit);
682             }
683             ed.semanticRun = PASS.obj;
684         }
685 
686         override void visit(TypeInfoDeclaration tid)
687         {
688             if (isSpeculativeType(tid.tinfo))
689             {
690                 //printf("-speculative '%s'\n", tid.toPrettyChars());
691                 return;
692             }
693             //printf("TypeInfoDeclaration.toObjFile(%p '%s') protection %d\n", tid, tid.toChars(), tid.protection);
694 
695             if (multiobj)
696             {
697                 obj_append(tid);
698                 return;
699             }
700 
701             Symbol *s = toSymbol(tid);
702             s.Sclass = SCcomdat;
703             s.Sfl = FLdata;
704 
705             auto dtb = DtBuilder(0);
706             TypeInfo_toDt(dtb, tid);
707             s.Sdt = dtb.finish();
708 
709             // See if we can convert a comdat to a comdef,
710             // which saves on exe file space.
711             if (s.Sclass == SCcomdat &&
712                 dtallzeros(s.Sdt))
713             {
714                 s.Sclass = SCglobal;
715                 dt2common(&s.Sdt);
716             }
717 
718             outdata(s);
719             if (tid.isExport())
720                 objmod.export_symbol(s, 0);
721         }
722 
723         override void visit(AttribDeclaration ad)
724         {
725             Dsymbols *d = ad.include(null);
726 
727             if (d)
728             {
729                 for (size_t i = 0; i < d.dim; i++)
730                 {
731                     Dsymbol s = (*d)[i];
732                     s.accept(this);
733                 }
734             }
735         }
736 
737         override void visit(PragmaDeclaration pd)
738         {
739             if (pd.ident == Id.lib)
740             {
741                 assert(pd.args && pd.args.dim == 1);
742 
743                 Expression e = (*pd.args)[0];
744 
745                 assert(e.op == TOK.string_);
746 
747                 StringExp se = cast(StringExp)e;
748                 char *name = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
749                 se.writeTo(name, true);
750 
751                 /* Embed the library names into the object file.
752                  * The linker will then automatically
753                  * search that library, too.
754                  */
755                 if (!obj_includelib(name))
756                 {
757                     /* The format does not allow embedded library names,
758                      * so instead append the library name to the list to be passed
759                      * to the linker.
760                      */
761                     global.params.libfiles.push(name);
762                 }
763             }
764             else if (pd.ident == Id.startaddress)
765             {
766                 assert(pd.args && pd.args.dim == 1);
767                 Expression e = (*pd.args)[0];
768                 Dsymbol sa = getDsymbol(e);
769                 FuncDeclaration f = sa.isFuncDeclaration();
770                 assert(f);
771                 Symbol *s = toSymbol(f);
772                 obj_startaddress(s);
773             }
774             else if (pd.ident == Id.linkerDirective)
775             {
776                 assert(pd.args && pd.args.dim == 1);
777 
778                 Expression e = (*pd.args)[0];
779 
780                 assert(e.op == TOK.string_);
781 
782                 StringExp se = cast(StringExp)e;
783                 char *directive = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
784                 se.writeTo(directive, true);
785 
786                 obj_linkerdirective(directive);
787             }
788             else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor)
789             {
790                 immutable isCtor = pd.ident == Id.crt_constructor;
791 
792                 static uint recurse(Dsymbol s, bool isCtor)
793                 {
794                     if (auto ad = s.isAttribDeclaration())
795                     {
796                         uint nestedCount;
797                         auto decls = ad.include(null);
798                         if (decls)
799                         {
800                             for (size_t i = 0; i < decls.dim; ++i)
801                                 nestedCount += recurse((*decls)[i], isCtor);
802                         }
803                         return nestedCount;
804                     }
805                     else if (auto f = s.isFuncDeclaration())
806                     {
807                         f.isCrtCtorDtor |= isCtor ? 1 : 2;
808                         if (f.linkage != LINK.c)
809                             f.error("must be `extern(C)` for `pragma(%s)`", isCtor ? "crt_constructor".ptr : "crt_destructor".ptr);
810                         return 1;
811                     }
812                     else
813                         return 0;
814                     assert(0);
815                 }
816 
817                 if (recurse(pd, isCtor) > 1)
818                     pd.error("can only apply to a single declaration");
819             }
820 
821             visit(cast(AttribDeclaration)pd);
822         }
823 
824         override void visit(TemplateInstance ti)
825         {
826             //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toChars());
827             if (!isError(ti) && ti.members)
828             {
829                 if (!ti.needsCodegen())
830                 {
831                     //printf("-speculative (%p, %s)\n", ti, ti.toPrettyChars());
832                     return;
833                 }
834                 //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toPrettyChars());
835 
836                 if (multiobj)
837                 {
838                     // Append to list of object files to be written later
839                     obj_append(ti);
840                 }
841                 else
842                 {
843                     ti.members.foreachDsymbol( (s) { s.accept(this); } );
844                 }
845             }
846         }
847 
848         override void visit(TemplateMixin tm)
849         {
850             //printf("TemplateMixin.toObjFile('%s')\n", tm.toChars());
851             if (!isError(tm))
852             {
853                 tm.members.foreachDsymbol( (s) { s.accept(this); } );
854             }
855         }
856 
857         override void visit(StaticAssert sa)
858         {
859         }
860 
861         override void visit(Nspace ns)
862         {
863             //printf("Nspace.toObjFile('%s', this = %p)\n", ns.toChars(), ns);
864             if (!isError(ns) && ns.members)
865             {
866                 if (multiobj)
867                 {
868                     // Append to list of object files to be written later
869                     obj_append(ns);
870                 }
871                 else
872                 {
873                     ns.members.foreachDsymbol( (s) { s.accept(this); } );
874                 }
875             }
876         }
877 
878     private:
879         static void initializerToDt(VarDeclaration vd, ref DtBuilder dtb)
880         {
881             Initializer_toDt(vd._init, dtb);
882 
883             // Look for static array that is block initialized
884             ExpInitializer ie = vd._init.isExpInitializer();
885 
886             Type tb = vd.type.toBasetype();
887             if (tb.ty == Tsarray && ie &&
888                 !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) &&
889                 ie.exp.implicitConvTo(tb.nextOf())
890                 )
891             {
892                 auto dim = (cast(TypeSArray)tb).dim.toInteger();
893 
894                 // Duplicate Sdt 'dim-1' times, as we already have the first one
895                 while (--dim > 0)
896                 {
897                     Expression_toDt(ie.exp, dtb);
898                 }
899             }
900         }
901 
902         /**
903          * Output a TLS symbol for Mach-O.
904          *
905          * A TLS variable in the Mach-O format consists of two symbols.
906          * One symbol for the data, which contains the initializer, if any.
907          * The name of this symbol is the same as the variable, but with the
908          * "$tlv$init" suffix. If the variable has an initializer it's placed in
909          * the __thread_data section. Otherwise it's placed in the __thread_bss
910          * section.
911          *
912          * The other symbol is for the TLV descriptor. The symbol has the same
913          * name as the variable and is placed in the __thread_vars section.
914          * A TLV descriptor has the following structure, where T is the type of
915          * the variable:
916          *
917          * struct TLVDescriptor(T)
918          * {
919          *     extern(C) T* function(TLVDescriptor*) thunk;
920          *     size_t key;
921          *     size_t offset;
922          * }
923          *
924          * Params:
925          *      vd = the variable declaration for the symbol
926          *      s = the backend Symbol corresponsing to vd
927          *      sz = data size of s
928          *      dtb = where to put the data
929          */
930         static void tlsToDt(VarDeclaration vd, Symbol *s, uint sz, ref DtBuilder dtb)
931         {
932             assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
933 
934             Symbol *tlvInit = createTLVDataSymbol(vd, s);
935             auto tlvInitDtb = DtBuilder(0);
936 
937             if (sz == 0)
938                 tlvInitDtb.nzeros(1);
939             else if (vd._init)
940                 initializerToDt(vd, tlvInitDtb);
941             else
942                 Type_toDt(vd.type, tlvInitDtb);
943 
944             tlvInit.Sdt = tlvInitDtb.finish();
945             outdata(tlvInit);
946 
947             if (global.params.is64bit)
948                 tlvInit.Sclass = SCextern;
949 
950             Symbol* tlvBootstrap = objmod.tlv_bootstrap();
951             dtb.xoff(tlvBootstrap, 0, TYnptr);
952             dtb.size(0);
953             dtb.xoff(tlvInit, 0, TYnptr);
954         }
955 
956         /**
957          * Creates the data symbol used to initialize a TLS variable for Mach-O.
958          *
959          * Params:
960          *      vd = the variable declaration for the symbol
961          *      s = the back end symbol corresponding to vd
962          *
963          * Returns: the newly created symbol
964          */
965         static Symbol *createTLVDataSymbol(VarDeclaration vd, Symbol *s)
966         {
967             assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
968 
969             // Compute identifier for tlv symbol
970             OutBuffer buffer;
971             buffer.writestring(s.Sident);
972             buffer.writestring("$tlv$init");
973             const(char) *tlvInitName = buffer.peekChars();
974 
975             // Compute type for tlv symbol
976             type *t = type_fake(vd.type.ty);
977             type_setty(&t, t.Tty | mTYthreadData);
978             type_setmangle(&t, mangle(vd));
979 
980             Symbol *tlvInit = symbol_name(tlvInitName, SCstatic, t);
981             tlvInit.Sdt = null;
982             tlvInit.Salignment = type_alignsize(s.Stype);
983             if (vd.linkage == LINK.cpp)
984                 tlvInit.Sflags |= SFLpublic;
985 
986             return tlvInit;
987         }
988 
989         /**
990          * Returns the target mangling mangle_t for the given variable.
991          *
992          * Params:
993          *      vd = the variable declaration
994          *
995          * Returns:
996          *      the mangling that should be used for variable
997          */
998         static mangle_t mangle(const VarDeclaration vd)
999         {
1000             final switch (vd.linkage)
1001             {
1002                 case LINK.windows:
1003                     return global.params.is64bit ? mTYman_c : mTYman_std;
1004 
1005                 case LINK.pascal:
1006                     return mTYman_pas;
1007 
1008                 case LINK.objc:
1009                 case LINK.c:
1010                     return mTYman_c;
1011 
1012                 case LINK.d:
1013                     return mTYman_d;
1014 
1015                 case LINK.cpp:
1016                     return mTYman_cpp;
1017 
1018                 case LINK.default_:
1019                 case LINK.system:
1020                     printf("linkage = %d\n", vd.linkage);
1021                     assert(0);
1022             }
1023         }
1024     }
1025 
1026     scope v = new ToObjFile(multiobj);
1027     ds.accept(v);
1028 }
1029 
1030 
1031 /*********************************
1032  * Finish semantic analysis of functions in vtbl[].
1033  * Params:
1034  *    cd = class which has the vtbl[]
1035  * Returns:
1036  *    true for success (no errors)
1037  */
1038 private bool finishVtbl(ClassDeclaration cd)
1039 {
1040     bool hasError = false;
1041 
1042     foreach (i; cd.vtblOffset() .. cd.vtbl.dim)
1043     {
1044         FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
1045 
1046         //printf("\tvtbl[%d] = %p\n", i, fd);
1047         if (!fd || !fd.fbody && cd.isAbstract())
1048         {
1049             // Nothing to do
1050             continue;
1051         }
1052         // Ensure function has a return value
1053         // https://issues.dlang.org/show_bug.cgi?id=4869
1054         if (!fd.functionSemantic())
1055         {
1056             hasError = true;
1057         }
1058 
1059         if (!cd.isFuncHidden(fd) || fd.isFuture())
1060         {
1061             // All good, no name hiding to check for
1062             continue;
1063         }
1064 
1065         /* fd is hidden from the view of this class.
1066          * If fd overlaps with any function in the vtbl[], then
1067          * issue 'hidden' error.
1068          */
1069         foreach (j; 1 .. cd.vtbl.dim)
1070         {
1071             if (j == i)
1072                 continue;
1073             FuncDeclaration fd2 = cd.vtbl[j].isFuncDeclaration();
1074             if (!fd2.ident.equals(fd.ident))
1075                 continue;
1076             if (fd2.isFuture())
1077                 continue;
1078             if (!fd.leastAsSpecialized(fd2) && !fd2.leastAsSpecialized(fd))
1079                 continue;
1080             // Hiding detected: same name, overlapping specializations
1081             TypeFunction tf = cast(TypeFunction)fd.type;
1082             if (tf.ty == Tfunction)
1083             {
1084                 cd.error("use of `%s%s` is hidden by `%s`; use `alias %s = %s.%s;` to introduce base class overload set",
1085                     fd.toPrettyChars(),
1086                     parametersTypeToChars(tf.parameterList),
1087                     cd.toChars(),
1088                     fd.toChars(),
1089                     fd.parent.toChars(),
1090                     fd.toChars());
1091             }
1092             else
1093             {
1094                 cd.error("use of `%s` is hidden by `%s`", fd.toPrettyChars(), cd.toChars());
1095             }
1096             hasError = true;
1097             break;
1098         }
1099     }
1100 
1101     return !hasError;
1102 }
1103 
1104 
1105 /******************************************
1106  * Get offset of base class's vtbl[] initializer from start of csym.
1107  * Returns ~0 if not this csym.
1108  */
1109 
1110 uint baseVtblOffset(ClassDeclaration cd, BaseClass *bc)
1111 {
1112     //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", cd.toChars(), bc);
1113     uint csymoffset = target.classinfosize;    // must be ClassInfo.size
1114     csymoffset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1115 
1116     for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1117     {
1118         BaseClass *b = (*cd.vtblInterfaces)[i];
1119 
1120         if (b == bc)
1121             return csymoffset;
1122         csymoffset += b.sym.vtbl.dim * target.ptrsize;
1123     }
1124 
1125     // Put out the overriding interface vtbl[]s.
1126     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1127     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1128     ClassDeclaration cd2;
1129 
1130     for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass)
1131     {
1132         foreach (k; 0 .. cd2.vtblInterfaces.dim)
1133         {
1134             BaseClass *bs = (*cd2.vtblInterfaces)[k];
1135             if (bs.fillVtbl(cd, null, 0))
1136             {
1137                 if (bc == bs)
1138                 {
1139                     //printf("\tcsymoffset = x%x\n", csymoffset);
1140                     return csymoffset;
1141                 }
1142                 csymoffset += bs.sym.vtbl.dim * target.ptrsize;
1143             }
1144         }
1145     }
1146 
1147     return ~0;
1148 }
1149 
1150 /*******************
1151  * Emit the vtbl[] to static data
1152  * Params:
1153  *    dtb = static data builder
1154  *    b = base class
1155  *    bvtbl = array of functions to put in this vtbl[]
1156  *    pc = classid for this vtbl[]
1157  *    k = offset from pc to classinfo
1158  * Returns:
1159  *    number of bytes emitted
1160  */
1161 private size_t emitVtbl(ref DtBuilder dtb, BaseClass *b, ref FuncDeclarations bvtbl, ClassDeclaration pc, size_t k)
1162 {
1163     //printf("\toverriding vtbl[] for %s\n", b.sym.toChars());
1164     ClassDeclaration id = b.sym;
1165 
1166     const id_vtbl_dim = id.vtbl.dim;
1167     assert(id_vtbl_dim <= bvtbl.dim);
1168 
1169     size_t jstart = 0;
1170     if (id.vtblOffset())
1171     {
1172         // First entry is struct Interface reference
1173         dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr);
1174         jstart = 1;
1175     }
1176 
1177     foreach (j; jstart .. id_vtbl_dim)
1178     {
1179         FuncDeclaration fd = bvtbl[j];
1180         if (fd)
1181         {
1182             auto offset2 = b.offset;
1183             if (fd.interfaceVirtual)
1184             {
1185                 offset2 -= fd.interfaceVirtual.offset;
1186             }
1187             dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr);
1188         }
1189         else
1190             dtb.size(0);
1191     }
1192     return id_vtbl_dim * target.ptrsize;
1193 }
1194 
1195 
1196 /******************************************************
1197  * Generate the ClassInfo for a Class (__classZ) symbol.
1198  * Write it to the object file.
1199  * Similar to genClassInfoForInterface().
1200  * Params:
1201  *      cd = the class
1202  *      sinit = the Initializer (__initZ) symbol for the class
1203  */
1204 private void genClassInfoForClass(ClassDeclaration cd, Symbol* sinit)
1205 {
1206     // Put out the ClassInfo, which will be the __ClassZ symbol in the object file
1207     enum_SC scclass = SCcomdat;
1208     cd.csym.Sclass = scclass;
1209     cd.csym.Sfl = FLdata;
1210 
1211     /* The layout is:
1212        {
1213             void **vptr;
1214             monitor_t monitor;
1215             byte[] m_init;              // static initialization data
1216             string name;                // class name
1217             void*[] vtbl;
1218             Interface[] interfaces;
1219             ClassInfo base;             // base class
1220             void* destructor;
1221             void function(Object) classInvariant;   // class invariant
1222             ClassFlags m_flags;
1223             void* deallocator;
1224             OffsetTypeInfo[] offTi;
1225             void function(Object) defaultConstructor;
1226             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1227             immutable(void)* m_RTInfo;
1228             //TypeInfo typeinfo;
1229        }
1230      */
1231     uint offset = target.classinfosize;    // must be ClassInfo.size
1232     if (Type.typeinfoclass)
1233     {
1234         if (Type.typeinfoclass.structsize != target.classinfosize)
1235         {
1236             debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize);
1237             cd.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1238             fatal();
1239         }
1240     }
1241 
1242     auto dtb = DtBuilder(0);
1243 
1244     if (auto tic = Type.typeinfoclass)
1245     {
1246         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo
1247         if (tic.hasMonitor())
1248             dtb.size(0);                        // monitor
1249     }
1250     else
1251     {
1252         dtb.size(0);                    // BUG: should be an assert()
1253         dtb.size(0);                    // call hasMonitor()?
1254     }
1255 
1256     // m_init[]
1257     assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4));
1258     dtb.size(cd.structsize);           // size
1259     dtb.xoff(sinit, 0, TYnptr);         // initializer
1260 
1261     // name[]
1262     const(char) *name = cd.ident.toChars();
1263     size_t namelen = strlen(name);
1264     if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0))
1265     {
1266         name = cd.toPrettyChars();
1267         namelen = strlen(name);
1268     }
1269     dtb.size(namelen);
1270     dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr);
1271 
1272     // vtbl[]
1273     dtb.size(cd.vtbl.dim);
1274     if (cd.vtbl.dim)
1275         dtb.xoff(cd.vtblsym.csym, 0, TYnptr);
1276     else
1277         dtb.size(0);
1278 
1279     // interfaces[]
1280     dtb.size(cd.vtblInterfaces.dim);
1281     if (cd.vtblInterfaces.dim)
1282         dtb.xoff(cd.csym, offset, TYnptr);      // (*)
1283     else
1284         dtb.size(0);
1285 
1286     // base
1287     if (cd.baseClass)
1288         dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr);
1289     else
1290         dtb.size(0);
1291 
1292     // destructor
1293     if (cd.tidtor)
1294         dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr);
1295     else
1296         dtb.size(0);
1297 
1298     // classInvariant
1299     if (cd.inv)
1300         dtb.xoff(toSymbol(cd.inv), 0, TYnptr);
1301     else
1302         dtb.size(0);
1303 
1304     // flags
1305     ClassFlags flags = ClassFlags.hasOffTi;
1306     if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass;
1307     if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass;
1308     flags |= ClassFlags.hasGetMembers;
1309     flags |= ClassFlags.hasTypeInfo;
1310     if (cd.ctor)
1311         flags |= ClassFlags.hasCtor;
1312     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1313     {
1314         if (pc.dtor)
1315         {
1316             flags |= ClassFlags.hasDtor;
1317             break;
1318         }
1319     }
1320     if (cd.isAbstract())
1321         flags |= ClassFlags.isAbstract;
1322 
1323     flags |= ClassFlags.noPointers;     // initially assume no pointers
1324 Louter:
1325     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1326     {
1327         if (pc.members)
1328         {
1329             for (size_t i = 0; i < pc.members.dim; i++)
1330             {
1331                 Dsymbol sm = (*pc.members)[i];
1332                 //printf("sm = %s %s\n", sm.kind(), sm.toChars());
1333                 if (sm.hasPointers())
1334                 {
1335                     flags &= ~ClassFlags.noPointers;  // not no-how, not no-way
1336                     break Louter;
1337                 }
1338             }
1339         }
1340     }
1341     dtb.size(flags);
1342 
1343     // deallocator
1344     dtb.size(0);
1345 
1346     // offTi[]
1347     dtb.size(0);
1348     dtb.size(0);            // null for now, fix later
1349 
1350     // defaultConstructor
1351     if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable))
1352         dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr);
1353     else
1354         dtb.size(0);
1355 
1356     // m_RTInfo
1357     if (cd.getRTInfo)
1358         Expression_toDt(cd.getRTInfo, dtb);
1359     else if (flags & ClassFlags.noPointers)
1360         dtb.size(0);
1361     else
1362         dtb.size(1);
1363 
1364     //dtb.xoff(toSymbol(cd.type.vtinfo), 0, TYnptr); // typeinfo
1365 
1366     //////////////////////////////////////////////
1367 
1368     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1369     // of the fixup (*)
1370 
1371     offset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1372     for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1373     {
1374         BaseClass *b = (*cd.vtblInterfaces)[i];
1375         ClassDeclaration id = b.sym;
1376 
1377         /* The layout is:
1378          *  struct Interface
1379          *  {
1380          *      ClassInfo classinfo;
1381          *      void*[] vtbl;
1382          *      size_t offset;
1383          *  }
1384          */
1385 
1386         // Fill in vtbl[]
1387         b.fillVtbl(cd, &b.vtbl, 1);
1388 
1389         // classinfo
1390         dtb.xoff(toSymbol(id), 0, TYnptr);
1391 
1392         // vtbl[]
1393         dtb.size(id.vtbl.dim);
1394         dtb.xoff(cd.csym, offset, TYnptr);
1395 
1396         // offset
1397         dtb.size(b.offset);
1398     }
1399 
1400     // Put out the (*vtblInterfaces)[].vtbl[]
1401     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1402     //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars());
1403     foreach (i; 0 .. cd.vtblInterfaces.dim)
1404     {
1405         BaseClass *b = (*cd.vtblInterfaces)[i];
1406         offset += emitVtbl(dtb, b, b.vtbl, cd, i);
1407     }
1408 
1409     // Put out the overriding interface vtbl[]s.
1410     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1411     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1412     for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass)
1413     {
1414         foreach (i; 0 .. pc.vtblInterfaces.dim)
1415         {
1416             BaseClass *b = (*pc.vtblInterfaces)[i];
1417             FuncDeclarations bvtbl;
1418             if (b.fillVtbl(cd, &bvtbl, 0))
1419             {
1420                 offset += emitVtbl(dtb, b, bvtbl, pc, i);
1421             }
1422         }
1423     }
1424 
1425     //////////////////////////////////////////////
1426 
1427     dtpatchoffset(pdtname, offset);
1428 
1429     dtb.nbytes(cast(uint)(namelen + 1), name);
1430     const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align
1431     dtb.nzeros(cast(uint)namepad);
1432 
1433     cd.csym.Sdt = dtb.finish();
1434     // ClassInfo cannot be const data, because we use the monitor on it
1435     outdata(cd.csym);
1436     if (cd.isExport())
1437         objmod.export_symbol(cd.csym, 0);
1438 }
1439 
1440 /******************************************************
1441  * Generate the ClassInfo for an Interface (classZ symbol).
1442  * Write it to the object file.
1443  * Params:
1444  *      id = the interface
1445  */
1446 private void genClassInfoForInterface(InterfaceDeclaration id)
1447 {
1448     enum_SC scclass = SCcomdat;
1449 
1450     // Put out the ClassInfo
1451     id.csym.Sclass = scclass;
1452     id.csym.Sfl = FLdata;
1453 
1454     /* The layout is:
1455        {
1456             void **vptr;
1457             monitor_t monitor;
1458             byte[] m_init;              // static initialization data
1459             string name;                // class name
1460             void*[] vtbl;
1461             Interface[] interfaces;
1462             ClassInfo base;             // base class
1463             void* destructor;
1464             void function(Object) classInvariant;   // class invariant
1465             ClassFlags m_flags;
1466             void* deallocator;
1467             OffsetTypeInfo[] offTi;
1468             void function(Object) defaultConstructor;
1469             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1470             immutable(void)* m_RTInfo;
1471             //TypeInfo typeinfo;
1472        }
1473      */
1474     auto dtb = DtBuilder(0);
1475 
1476     if (auto tic = Type.typeinfoclass)
1477     {
1478         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo
1479         if (tic.hasMonitor())
1480             dtb.size(0);                        // monitor
1481     }
1482     else
1483     {
1484         dtb.size(0);                    // BUG: should be an assert()
1485         dtb.size(0);                    // call hasMonitor()?
1486     }
1487 
1488     // m_init[]
1489     dtb.size(0);                        // size
1490     dtb.size(0);                        // initializer
1491 
1492     // name[]
1493     const(char) *name = id.toPrettyChars();
1494     size_t namelen = strlen(name);
1495     dtb.size(namelen);
1496     dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr);
1497 
1498     // vtbl[]
1499     dtb.size(0);
1500     dtb.size(0);
1501 
1502     // interfaces[]
1503     uint offset = target.classinfosize;
1504     dtb.size(id.vtblInterfaces.dim);
1505     if (id.vtblInterfaces.dim)
1506     {
1507         if (Type.typeinfoclass)
1508         {
1509             if (Type.typeinfoclass.structsize != offset)
1510             {
1511                 id.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1512                 fatal();
1513             }
1514         }
1515         dtb.xoff(id.csym, offset, TYnptr);      // (*)
1516     }
1517     else
1518     {
1519         dtb.size(0);
1520     }
1521 
1522     // base
1523     assert(!id.baseClass);
1524     dtb.size(0);
1525 
1526     // destructor
1527     dtb.size(0);
1528 
1529     // classInvariant
1530     dtb.size(0);
1531 
1532     // flags
1533     ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo;
1534     if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass;
1535     dtb.size(flags);
1536 
1537     // deallocator
1538     dtb.size(0);
1539 
1540     // offTi[]
1541     dtb.size(0);
1542     dtb.size(0);            // null for now, fix later
1543 
1544     // defaultConstructor
1545     dtb.size(0);
1546 
1547     // xgetMembers
1548     //dtb.size(0);
1549 
1550     // m_RTInfo
1551     if (id.getRTInfo)
1552         Expression_toDt(id.getRTInfo, dtb);
1553     else
1554         dtb.size(0);       // no pointers
1555 
1556     //dtb.xoff(toSymbol(id.type.vtinfo), 0, TYnptr); // typeinfo
1557 
1558     //////////////////////////////////////////////
1559 
1560     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1561     // of the fixup (*)
1562 
1563     offset += id.vtblInterfaces.dim * (4 * target.ptrsize);
1564     for (size_t i = 0; i < id.vtblInterfaces.dim; i++)
1565     {
1566         BaseClass *b = (*id.vtblInterfaces)[i];
1567         ClassDeclaration base = b.sym;
1568 
1569         // classinfo
1570         dtb.xoff(toSymbol(base), 0, TYnptr);
1571 
1572         // vtbl[]
1573         dtb.size(0);
1574         dtb.size(0);
1575 
1576         // offset
1577         dtb.size(b.offset);
1578     }
1579 
1580     //////////////////////////////////////////////
1581 
1582     dtpatchoffset(pdtname, offset);
1583 
1584     dtb.nbytes(cast(uint)(namelen + 1), name);
1585     const size_t namepad =  -(namelen + 1) & (target.ptrsize - 1); // align
1586     dtb.nzeros(cast(uint)namepad);
1587 
1588     id.csym.Sdt = dtb.finish();
1589     out_readonly(id.csym);
1590     outdata(id.csym);
1591     if (id.isExport())
1592         objmod.export_symbol(id.csym, 0);
1593 }