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 = fd.type.toTypeFunction();
1082             cd.error("use of `%s%s` is hidden by `%s`; use `alias %s = %s.%s;` to introduce base class overload set",
1083                 fd.toPrettyChars(),
1084                 parametersTypeToChars(tf.parameterList),
1085                 cd.toChars(),
1086                 fd.toChars(),
1087                 fd.parent.toChars(),
1088                 fd.toChars());
1089             hasError = true;
1090             break;
1091         }
1092     }
1093 
1094     return !hasError;
1095 }
1096 
1097 
1098 /******************************************
1099  * Get offset of base class's vtbl[] initializer from start of csym.
1100  * Returns ~0 if not this csym.
1101  */
1102 
1103 uint baseVtblOffset(ClassDeclaration cd, BaseClass *bc)
1104 {
1105     //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", cd.toChars(), bc);
1106     uint csymoffset = target.classinfosize;    // must be ClassInfo.size
1107     csymoffset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1108 
1109     for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1110     {
1111         BaseClass *b = (*cd.vtblInterfaces)[i];
1112 
1113         if (b == bc)
1114             return csymoffset;
1115         csymoffset += b.sym.vtbl.dim * target.ptrsize;
1116     }
1117 
1118     // Put out the overriding interface vtbl[]s.
1119     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1120     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1121     ClassDeclaration cd2;
1122 
1123     for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass)
1124     {
1125         foreach (k; 0 .. cd2.vtblInterfaces.dim)
1126         {
1127             BaseClass *bs = (*cd2.vtblInterfaces)[k];
1128             if (bs.fillVtbl(cd, null, 0))
1129             {
1130                 if (bc == bs)
1131                 {
1132                     //printf("\tcsymoffset = x%x\n", csymoffset);
1133                     return csymoffset;
1134                 }
1135                 csymoffset += bs.sym.vtbl.dim * target.ptrsize;
1136             }
1137         }
1138     }
1139 
1140     return ~0;
1141 }
1142 
1143 /*******************
1144  * Emit the vtbl[] to static data
1145  * Params:
1146  *    dtb = static data builder
1147  *    b = base class
1148  *    bvtbl = array of functions to put in this vtbl[]
1149  *    pc = classid for this vtbl[]
1150  *    k = offset from pc to classinfo
1151  * Returns:
1152  *    number of bytes emitted
1153  */
1154 private size_t emitVtbl(ref DtBuilder dtb, BaseClass *b, ref FuncDeclarations bvtbl, ClassDeclaration pc, size_t k)
1155 {
1156     //printf("\toverriding vtbl[] for %s\n", b.sym.toChars());
1157     ClassDeclaration id = b.sym;
1158 
1159     const id_vtbl_dim = id.vtbl.dim;
1160     assert(id_vtbl_dim <= bvtbl.dim);
1161 
1162     size_t jstart = 0;
1163     if (id.vtblOffset())
1164     {
1165         // First entry is struct Interface reference
1166         dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr);
1167         jstart = 1;
1168     }
1169 
1170     foreach (j; jstart .. id_vtbl_dim)
1171     {
1172         FuncDeclaration fd = bvtbl[j];
1173         if (fd)
1174         {
1175             auto offset2 = b.offset;
1176             if (fd.interfaceVirtual)
1177             {
1178                 offset2 -= fd.interfaceVirtual.offset;
1179             }
1180             dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr);
1181         }
1182         else
1183             dtb.size(0);
1184     }
1185     return id_vtbl_dim * target.ptrsize;
1186 }
1187 
1188 
1189 /******************************************************
1190  * Generate the ClassInfo for a Class (__classZ) symbol.
1191  * Write it to the object file.
1192  * Similar to genClassInfoForInterface().
1193  * Params:
1194  *      cd = the class
1195  *      sinit = the Initializer (__initZ) symbol for the class
1196  */
1197 private void genClassInfoForClass(ClassDeclaration cd, Symbol* sinit)
1198 {
1199     // Put out the ClassInfo, which will be the __ClassZ symbol in the object file
1200     enum_SC scclass = SCcomdat;
1201     cd.csym.Sclass = scclass;
1202     cd.csym.Sfl = FLdata;
1203 
1204     /* The layout is:
1205        {
1206             void **vptr;
1207             monitor_t monitor;
1208             byte[] m_init;              // static initialization data
1209             string name;                // class name
1210             void*[] vtbl;
1211             Interface[] interfaces;
1212             ClassInfo base;             // base class
1213             void* destructor;
1214             void function(Object) classInvariant;   // class invariant
1215             ClassFlags m_flags;
1216             void* deallocator;
1217             OffsetTypeInfo[] offTi;
1218             void function(Object) defaultConstructor;
1219             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1220             immutable(void)* m_RTInfo;
1221             //TypeInfo typeinfo;
1222        }
1223      */
1224     uint offset = target.classinfosize;    // must be ClassInfo.size
1225     if (Type.typeinfoclass)
1226     {
1227         if (Type.typeinfoclass.structsize != target.classinfosize)
1228         {
1229             debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize);
1230             cd.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1231             fatal();
1232         }
1233     }
1234 
1235     auto dtb = DtBuilder(0);
1236 
1237     if (auto tic = Type.typeinfoclass)
1238     {
1239         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo
1240         if (tic.hasMonitor())
1241             dtb.size(0);                        // monitor
1242     }
1243     else
1244     {
1245         dtb.size(0);                    // BUG: should be an assert()
1246         dtb.size(0);                    // call hasMonitor()?
1247     }
1248 
1249     // m_init[]
1250     assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4));
1251     dtb.size(cd.structsize);           // size
1252     dtb.xoff(sinit, 0, TYnptr);         // initializer
1253 
1254     // name[]
1255     const(char) *name = cd.ident.toChars();
1256     size_t namelen = strlen(name);
1257     if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0))
1258     {
1259         name = cd.toPrettyChars();
1260         namelen = strlen(name);
1261     }
1262     dtb.size(namelen);
1263     dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr);
1264 
1265     // vtbl[]
1266     dtb.size(cd.vtbl.dim);
1267     if (cd.vtbl.dim)
1268         dtb.xoff(cd.vtblsym.csym, 0, TYnptr);
1269     else
1270         dtb.size(0);
1271 
1272     // interfaces[]
1273     dtb.size(cd.vtblInterfaces.dim);
1274     if (cd.vtblInterfaces.dim)
1275         dtb.xoff(cd.csym, offset, TYnptr);      // (*)
1276     else
1277         dtb.size(0);
1278 
1279     // base
1280     if (cd.baseClass)
1281         dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr);
1282     else
1283         dtb.size(0);
1284 
1285     // destructor
1286     if (cd.tidtor)
1287         dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr);
1288     else
1289         dtb.size(0);
1290 
1291     // classInvariant
1292     if (cd.inv)
1293         dtb.xoff(toSymbol(cd.inv), 0, TYnptr);
1294     else
1295         dtb.size(0);
1296 
1297     // flags
1298     ClassFlags flags = ClassFlags.hasOffTi;
1299     if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass;
1300     if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass;
1301     flags |= ClassFlags.hasGetMembers;
1302     flags |= ClassFlags.hasTypeInfo;
1303     if (cd.ctor)
1304         flags |= ClassFlags.hasCtor;
1305     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1306     {
1307         if (pc.dtor)
1308         {
1309             flags |= ClassFlags.hasDtor;
1310             break;
1311         }
1312     }
1313     if (cd.isAbstract())
1314         flags |= ClassFlags.isAbstract;
1315 
1316     flags |= ClassFlags.noPointers;     // initially assume no pointers
1317 Louter:
1318     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1319     {
1320         if (pc.members)
1321         {
1322             for (size_t i = 0; i < pc.members.dim; i++)
1323             {
1324                 Dsymbol sm = (*pc.members)[i];
1325                 //printf("sm = %s %s\n", sm.kind(), sm.toChars());
1326                 if (sm.hasPointers())
1327                 {
1328                     flags &= ~ClassFlags.noPointers;  // not no-how, not no-way
1329                     break Louter;
1330                 }
1331             }
1332         }
1333     }
1334     dtb.size(flags);
1335 
1336     // deallocator
1337     dtb.size(0);
1338 
1339     // offTi[]
1340     dtb.size(0);
1341     dtb.size(0);            // null for now, fix later
1342 
1343     // defaultConstructor
1344     if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable))
1345         dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr);
1346     else
1347         dtb.size(0);
1348 
1349     // m_RTInfo
1350     if (cd.getRTInfo)
1351         Expression_toDt(cd.getRTInfo, dtb);
1352     else if (flags & ClassFlags.noPointers)
1353         dtb.size(0);
1354     else
1355         dtb.size(1);
1356 
1357     //dtb.xoff(toSymbol(cd.type.vtinfo), 0, TYnptr); // typeinfo
1358 
1359     //////////////////////////////////////////////
1360 
1361     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1362     // of the fixup (*)
1363 
1364     offset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1365     for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1366     {
1367         BaseClass *b = (*cd.vtblInterfaces)[i];
1368         ClassDeclaration id = b.sym;
1369 
1370         /* The layout is:
1371          *  struct Interface
1372          *  {
1373          *      ClassInfo classinfo;
1374          *      void*[] vtbl;
1375          *      size_t offset;
1376          *  }
1377          */
1378 
1379         // Fill in vtbl[]
1380         b.fillVtbl(cd, &b.vtbl, 1);
1381 
1382         // classinfo
1383         dtb.xoff(toSymbol(id), 0, TYnptr);
1384 
1385         // vtbl[]
1386         dtb.size(id.vtbl.dim);
1387         dtb.xoff(cd.csym, offset, TYnptr);
1388 
1389         // offset
1390         dtb.size(b.offset);
1391     }
1392 
1393     // Put out the (*vtblInterfaces)[].vtbl[]
1394     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1395     //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars());
1396     foreach (i; 0 .. cd.vtblInterfaces.dim)
1397     {
1398         BaseClass *b = (*cd.vtblInterfaces)[i];
1399         offset += emitVtbl(dtb, b, b.vtbl, cd, i);
1400     }
1401 
1402     // Put out the overriding interface vtbl[]s.
1403     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1404     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1405     for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass)
1406     {
1407         foreach (i; 0 .. pc.vtblInterfaces.dim)
1408         {
1409             BaseClass *b = (*pc.vtblInterfaces)[i];
1410             FuncDeclarations bvtbl;
1411             if (b.fillVtbl(cd, &bvtbl, 0))
1412             {
1413                 offset += emitVtbl(dtb, b, bvtbl, pc, i);
1414             }
1415         }
1416     }
1417 
1418     //////////////////////////////////////////////
1419 
1420     dtpatchoffset(pdtname, offset);
1421 
1422     dtb.nbytes(cast(uint)(namelen + 1), name);
1423     const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align
1424     dtb.nzeros(cast(uint)namepad);
1425 
1426     cd.csym.Sdt = dtb.finish();
1427     // ClassInfo cannot be const data, because we use the monitor on it
1428     outdata(cd.csym);
1429     if (cd.isExport())
1430         objmod.export_symbol(cd.csym, 0);
1431 }
1432 
1433 /******************************************************
1434  * Generate the ClassInfo for an Interface (classZ symbol).
1435  * Write it to the object file.
1436  * Params:
1437  *      id = the interface
1438  */
1439 private void genClassInfoForInterface(InterfaceDeclaration id)
1440 {
1441     enum_SC scclass = SCcomdat;
1442 
1443     // Put out the ClassInfo
1444     id.csym.Sclass = scclass;
1445     id.csym.Sfl = FLdata;
1446 
1447     /* The layout is:
1448        {
1449             void **vptr;
1450             monitor_t monitor;
1451             byte[] m_init;              // static initialization data
1452             string name;                // class name
1453             void*[] vtbl;
1454             Interface[] interfaces;
1455             ClassInfo base;             // base class
1456             void* destructor;
1457             void function(Object) classInvariant;   // class invariant
1458             ClassFlags m_flags;
1459             void* deallocator;
1460             OffsetTypeInfo[] offTi;
1461             void function(Object) defaultConstructor;
1462             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1463             immutable(void)* m_RTInfo;
1464             //TypeInfo typeinfo;
1465        }
1466      */
1467     auto dtb = DtBuilder(0);
1468 
1469     if (auto tic = Type.typeinfoclass)
1470     {
1471         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo
1472         if (tic.hasMonitor())
1473             dtb.size(0);                        // monitor
1474     }
1475     else
1476     {
1477         dtb.size(0);                    // BUG: should be an assert()
1478         dtb.size(0);                    // call hasMonitor()?
1479     }
1480 
1481     // m_init[]
1482     dtb.size(0);                        // size
1483     dtb.size(0);                        // initializer
1484 
1485     // name[]
1486     const(char) *name = id.toPrettyChars();
1487     size_t namelen = strlen(name);
1488     dtb.size(namelen);
1489     dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr);
1490 
1491     // vtbl[]
1492     dtb.size(0);
1493     dtb.size(0);
1494 
1495     // interfaces[]
1496     uint offset = target.classinfosize;
1497     dtb.size(id.vtblInterfaces.dim);
1498     if (id.vtblInterfaces.dim)
1499     {
1500         if (Type.typeinfoclass)
1501         {
1502             if (Type.typeinfoclass.structsize != offset)
1503             {
1504                 id.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1505                 fatal();
1506             }
1507         }
1508         dtb.xoff(id.csym, offset, TYnptr);      // (*)
1509     }
1510     else
1511     {
1512         dtb.size(0);
1513     }
1514 
1515     // base
1516     assert(!id.baseClass);
1517     dtb.size(0);
1518 
1519     // destructor
1520     dtb.size(0);
1521 
1522     // classInvariant
1523     dtb.size(0);
1524 
1525     // flags
1526     ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo;
1527     if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass;
1528     dtb.size(flags);
1529 
1530     // deallocator
1531     dtb.size(0);
1532 
1533     // offTi[]
1534     dtb.size(0);
1535     dtb.size(0);            // null for now, fix later
1536 
1537     // defaultConstructor
1538     dtb.size(0);
1539 
1540     // xgetMembers
1541     //dtb.size(0);
1542 
1543     // m_RTInfo
1544     if (id.getRTInfo)
1545         Expression_toDt(id.getRTInfo, dtb);
1546     else
1547         dtb.size(0);       // no pointers
1548 
1549     //dtb.xoff(toSymbol(id.type.vtinfo), 0, TYnptr); // typeinfo
1550 
1551     //////////////////////////////////////////////
1552 
1553     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1554     // of the fixup (*)
1555 
1556     offset += id.vtblInterfaces.dim * (4 * target.ptrsize);
1557     for (size_t i = 0; i < id.vtblInterfaces.dim; i++)
1558     {
1559         BaseClass *b = (*id.vtblInterfaces)[i];
1560         ClassDeclaration base = b.sym;
1561 
1562         // classinfo
1563         dtb.xoff(toSymbol(base), 0, TYnptr);
1564 
1565         // vtbl[]
1566         dtb.size(0);
1567         dtb.size(0);
1568 
1569         // offset
1570         dtb.size(b.offset);
1571     }
1572 
1573     //////////////////////////////////////////////
1574 
1575     dtpatchoffset(pdtname, offset);
1576 
1577     dtb.nbytes(cast(uint)(namelen + 1), name);
1578     const size_t namepad =  -(namelen + 1) & (target.ptrsize - 1); // align
1579     dtb.nzeros(cast(uint)namepad);
1580 
1581     id.csym.Sdt = dtb.finish();
1582     out_readonly(id.csym);
1583     outdata(id.csym);
1584     if (id.isExport())
1585         objmod.export_symbol(id.csym, 0);
1586 }