1 /**
2  * Convert an AST that went through all semantic phases into an object file.
3  *
4  * Copyright:   Copyright (C) 1999-2021 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             // Objetive-C protocols are only output if implemented as a class.
453             // If so, they're output via the class declaration.
454             if (id.classKind == ClassKind.objc)
455                 return;
456 
457             // Generate C symbols
458             toSymbol(id);
459 
460             //////////////////////////////////////////////
461 
462             // Put out the TypeInfo
463             if (global.params.useTypeInfo && Type.dtypeinfo)
464             {
465                 genTypeInfo(id.loc, id.type, null);
466                 id.type.vtinfo.accept(this);
467             }
468 
469             //////////////////////////////////////////////
470 
471             genClassInfoForInterface(id);
472         }
473 
474         override void visit(StructDeclaration sd)
475         {
476             //printf("StructDeclaration.toObjFile('%s')\n", sd.toChars());
477 
478             if (sd.type.ty == Terror)
479             {
480                 sd.error("had semantic errors when compiling");
481                 return;
482             }
483 
484             if (multiobj && !sd.hasStaticCtorOrDtor())
485             {
486                 obj_append(sd);
487                 return;
488             }
489 
490             // Anonymous structs/unions only exist as part of others,
491             // do not output forward referenced structs's
492             if (!sd.isAnonymous() && sd.members)
493             {
494                 if (global.params.symdebugref)
495                     Type_toCtype(sd.type); // calls toDebug() only once
496                 else if (global.params.symdebug)
497                     toDebug(sd);
498 
499                 if (global.params.useTypeInfo && Type.dtypeinfo)
500                     genTypeInfo(sd.loc, sd.type, null);
501 
502                 // Generate static initializer
503                 auto sinit = toInitializer(sd);
504                 if (sinit.Sclass == SCextern)
505                 {
506                     if (sinit == bzeroSymbol) assert(0);
507                     sinit.Sclass = sd.isInstantiated() ? SCcomdat : SCglobal;
508                     sinit.Sfl = FLdata;
509                     auto dtb = DtBuilder(0);
510                     StructDeclaration_toDt(sd, dtb);
511                     sinit.Sdt = dtb.finish();
512 
513                     /* fails to link on OBJ_MACH 64 with:
514                      *  ld: in generated/osx/release/64/libphobos2.a(dwarfeh_8dc_56a.o),
515                      *  in section __TEXT,__textcoal_nt reloc 6:
516                      *  symbol index out of range for architecture x86_64
517                      */
518                     if (config.objfmt != OBJ_MACH &&
519                         dtallzeros(sinit.Sdt))
520                     {
521                         sinit.Sclass = SCglobal;
522                         dt2common(&sinit.Sdt);
523                     }
524                     else
525                         out_readonly(sinit);    // put in read-only segment
526                     outdata(sinit);
527                 }
528 
529                 // Put out the members
530                 /* There might be static ctors in the members, and they cannot
531                  * be put in separate obj files.
532                  */
533                 sd.members.foreachDsymbol( (s) { s.accept(this); } );
534 
535                 if (sd.xeq && sd.xeq != StructDeclaration.xerreq)
536                     sd.xeq.accept(this);
537                 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp)
538                     sd.xcmp.accept(this);
539                 if (sd.xhash)
540                     sd.xhash.accept(this);
541             }
542         }
543 
544         override void visit(VarDeclaration vd)
545         {
546 
547             //printf("VarDeclaration.toObjFile(%p '%s' type=%s) visibility %d\n", vd, vd.toChars(), vd.type.toChars(), vd.visibility);
548             //printf("\talign = %d\n", vd.alignment);
549 
550             if (vd.type.ty == Terror)
551             {
552                 vd.error("had semantic errors when compiling");
553                 return;
554             }
555 
556             if (vd.aliassym)
557             {
558                 visitNoMultiObj(vd.toAlias());
559                 return;
560             }
561 
562             // Do not store variables we cannot take the address of
563             if (!vd.canTakeAddressOf())
564             {
565                 return;
566             }
567 
568             if (!vd.isDataseg() || vd.storage_class & STC.extern_)
569                 return;
570 
571             Symbol *s = toSymbol(vd);
572             d_uns64 sz64 = vd.type.size(vd.loc);
573             if (sz64 == SIZE_INVALID)
574             {
575                 vd.error("size overflow");
576                 return;
577             }
578             if (sz64 >= target.maxStaticDataSize)
579             {
580                 vd.error("size of 0x%llx exceeds max allowed size 0x%llx", sz64, target.maxStaticDataSize);
581             }
582             uint sz = cast(uint)sz64;
583 
584             Dsymbol parent = vd.toParent();
585             s.Sclass = SCglobal;
586 
587             do
588             {
589                 /* Global template data members need to be in comdat's
590                  * in case multiple .obj files instantiate the same
591                  * template with the same types.
592                  */
593                 if (parent.isTemplateInstance() && !parent.isTemplateMixin())
594                 {
595                     s.Sclass = SCcomdat;
596                     break;
597                 }
598                 parent = parent.parent;
599             } while (parent);
600             s.Sfl = FLdata;
601 
602             if (!sz && vd.type.toBasetype().ty != Tsarray)
603                 assert(0); // this shouldn't be possible
604 
605             auto dtb = DtBuilder(0);
606             if (config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread)
607             {
608                 tlsToDt(vd, s, sz, dtb);
609             }
610             else if (!sz)
611             {
612                 /* Give it a byte of data
613                  * so we can take the 'address' of this symbol
614                  * and avoid problematic behavior of object file format
615                  */
616                 dtb.nzeros(1);
617             }
618             else if (vd._init)
619             {
620                 initializerToDt(vd, dtb);
621             }
622             else
623             {
624                 Type_toDt(vd.type, dtb);
625             }
626             s.Sdt = dtb.finish();
627 
628             // See if we can convert a comdat to a comdef,
629             // which saves on exe file space.
630             if (s.Sclass == SCcomdat &&
631                 s.Sdt &&
632                 dtallzeros(s.Sdt) &&
633                 !vd.isThreadlocal())
634             {
635                 s.Sclass = SCglobal;
636                 dt2common(&s.Sdt);
637             }
638 
639             outdata(s);
640             if (vd.type.isMutable() || !vd._init)
641                 write_pointers(vd.type, s, 0);
642             if (vd.isExport())
643                 objmod.export_symbol(s, 0);
644         }
645 
646         override void visit(EnumDeclaration ed)
647         {
648             if (ed.semanticRun >= PASS.obj)  // already written
649                 return;
650             //printf("EnumDeclaration.toObjFile('%s')\n", ed.toChars());
651 
652             if (ed.errors || ed.type.ty == Terror)
653             {
654                 ed.error("had semantic errors when compiling");
655                 return;
656             }
657 
658             if (ed.isAnonymous())
659                 return;
660 
661             if (global.params.symdebugref)
662                 Type_toCtype(ed.type); // calls toDebug() only once
663             else if (global.params.symdebug)
664                 toDebug(ed);
665 
666             if (global.params.useTypeInfo && Type.dtypeinfo)
667                 genTypeInfo(ed.loc, ed.type, null);
668 
669             TypeEnum tc = cast(TypeEnum)ed.type;
670             if (!tc.sym.members || ed.type.isZeroInit(Loc.initial))
671             {
672             }
673             else
674             {
675                 enum_SC scclass = SCglobal;
676                 if (ed.isInstantiated())
677                     scclass = SCcomdat;
678 
679                 // Generate static initializer
680                 toInitializer(ed);
681                 ed.sinit.Sclass = scclass;
682                 ed.sinit.Sfl = FLdata;
683                 auto dtb = DtBuilder(0);
684                 Expression_toDt(tc.sym.defaultval, dtb);
685                 ed.sinit.Sdt = dtb.finish();
686                 outdata(ed.sinit);
687             }
688             ed.semanticRun = PASS.obj;
689         }
690 
691         override void visit(TypeInfoDeclaration tid)
692         {
693             if (isSpeculativeType(tid.tinfo))
694             {
695                 //printf("-speculative '%s'\n", tid.toPrettyChars());
696                 return;
697             }
698             //printf("TypeInfoDeclaration.toObjFile(%p '%s') visibility %d\n", tid, tid.toChars(), tid.visibility);
699 
700             if (multiobj)
701             {
702                 obj_append(tid);
703                 return;
704             }
705 
706             Symbol *s = toSymbol(tid);
707             s.Sclass = SCcomdat;
708             s.Sfl = FLdata;
709 
710             auto dtb = DtBuilder(0);
711             TypeInfo_toDt(dtb, tid);
712             s.Sdt = dtb.finish();
713 
714             // See if we can convert a comdat to a comdef,
715             // which saves on exe file space.
716             if (s.Sclass == SCcomdat &&
717                 dtallzeros(s.Sdt))
718             {
719                 s.Sclass = SCglobal;
720                 dt2common(&s.Sdt);
721             }
722 
723             outdata(s);
724             if (tid.isExport())
725                 objmod.export_symbol(s, 0);
726         }
727 
728         override void visit(AttribDeclaration ad)
729         {
730             Dsymbols *d = ad.include(null);
731 
732             if (d)
733             {
734                 for (size_t i = 0; i < d.dim; i++)
735                 {
736                     Dsymbol s = (*d)[i];
737                     s.accept(this);
738                 }
739             }
740         }
741 
742         override void visit(PragmaDeclaration pd)
743         {
744             if (pd.ident == Id.lib)
745             {
746                 assert(pd.args && pd.args.dim == 1);
747 
748                 Expression e = (*pd.args)[0];
749 
750                 assert(e.op == TOK.string_);
751 
752                 StringExp se = cast(StringExp)e;
753                 char *name = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
754                 se.writeTo(name, true);
755 
756                 /* Embed the library names into the object file.
757                  * The linker will then automatically
758                  * search that library, too.
759                  */
760                 if (!obj_includelib(name))
761                 {
762                     /* The format does not allow embedded library names,
763                      * so instead append the library name to the list to be passed
764                      * to the linker.
765                      */
766                     global.params.libfiles.push(name);
767                 }
768             }
769             else if (pd.ident == Id.startaddress)
770             {
771                 assert(pd.args && pd.args.dim == 1);
772                 Expression e = (*pd.args)[0];
773                 Dsymbol sa = getDsymbol(e);
774                 FuncDeclaration f = sa.isFuncDeclaration();
775                 assert(f);
776                 Symbol *s = toSymbol(f);
777                 obj_startaddress(s);
778             }
779             else if (pd.ident == Id.linkerDirective)
780             {
781                 assert(pd.args && pd.args.dim == 1);
782 
783                 Expression e = (*pd.args)[0];
784 
785                 assert(e.op == TOK.string_);
786 
787                 StringExp se = cast(StringExp)e;
788                 char *directive = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
789                 se.writeTo(directive, true);
790 
791                 obj_linkerdirective(directive);
792             }
793             else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor)
794             {
795                 immutable isCtor = pd.ident == Id.crt_constructor;
796 
797                 static uint recurse(Dsymbol s, bool isCtor)
798                 {
799                     if (auto ad = s.isAttribDeclaration())
800                     {
801                         uint nestedCount;
802                         auto decls = ad.include(null);
803                         if (decls)
804                         {
805                             for (size_t i = 0; i < decls.dim; ++i)
806                                 nestedCount += recurse((*decls)[i], isCtor);
807                         }
808                         return nestedCount;
809                     }
810                     else if (auto f = s.isFuncDeclaration())
811                     {
812                         f.isCrtCtorDtor |= isCtor ? 1 : 2;
813                         if (f.linkage != LINK.c)
814                             f.error("must be `extern(C)` for `pragma(%s)`", isCtor ? "crt_constructor".ptr : "crt_destructor".ptr);
815                         return 1;
816                     }
817                     else
818                         return 0;
819                     assert(0);
820                 }
821 
822                 if (recurse(pd, isCtor) > 1)
823                     pd.error("can only apply to a single declaration");
824             }
825 
826             visit(cast(AttribDeclaration)pd);
827         }
828 
829         override void visit(TemplateInstance ti)
830         {
831             //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toChars());
832             if (!isError(ti) && ti.members)
833             {
834                 if (!ti.needsCodegen())
835                 {
836                     //printf("-speculative (%p, %s)\n", ti, ti.toPrettyChars());
837                     return;
838                 }
839                 //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toPrettyChars());
840 
841                 if (multiobj)
842                 {
843                     // Append to list of object files to be written later
844                     obj_append(ti);
845                 }
846                 else
847                 {
848                     ti.members.foreachDsymbol( (s) { s.accept(this); } );
849                 }
850             }
851         }
852 
853         override void visit(TemplateMixin tm)
854         {
855             //printf("TemplateMixin.toObjFile('%s')\n", tm.toChars());
856             if (!isError(tm))
857             {
858                 tm.members.foreachDsymbol( (s) { s.accept(this); } );
859             }
860         }
861 
862         override void visit(StaticAssert sa)
863         {
864         }
865 
866         override void visit(Nspace ns)
867         {
868             //printf("Nspace.toObjFile('%s', this = %p)\n", ns.toChars(), ns);
869             if (!isError(ns) && ns.members)
870             {
871                 if (multiobj)
872                 {
873                     // Append to list of object files to be written later
874                     obj_append(ns);
875                 }
876                 else
877                 {
878                     ns.members.foreachDsymbol( (s) { s.accept(this); } );
879                 }
880             }
881         }
882 
883     private:
884         static void initializerToDt(VarDeclaration vd, ref DtBuilder dtb)
885         {
886             Initializer_toDt(vd._init, dtb);
887 
888             // Look for static array that is block initialized
889             ExpInitializer ie = vd._init.isExpInitializer();
890 
891             Type tb = vd.type.toBasetype();
892             if (tb.ty == Tsarray && ie &&
893                 !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) &&
894                 ie.exp.implicitConvTo(tb.nextOf())
895                 )
896             {
897                 auto dim = (cast(TypeSArray)tb).dim.toInteger();
898 
899                 // Duplicate Sdt 'dim-1' times, as we already have the first one
900                 while (--dim > 0)
901                 {
902                     Expression_toDt(ie.exp, dtb);
903                 }
904             }
905         }
906 
907         /**
908          * Output a TLS symbol for Mach-O.
909          *
910          * A TLS variable in the Mach-O format consists of two symbols.
911          * One symbol for the data, which contains the initializer, if any.
912          * The name of this symbol is the same as the variable, but with the
913          * "$tlv$init" suffix. If the variable has an initializer it's placed in
914          * the __thread_data section. Otherwise it's placed in the __thread_bss
915          * section.
916          *
917          * The other symbol is for the TLV descriptor. The symbol has the same
918          * name as the variable and is placed in the __thread_vars section.
919          * A TLV descriptor has the following structure, where T is the type of
920          * the variable:
921          *
922          * struct TLVDescriptor(T)
923          * {
924          *     extern(C) T* function(TLVDescriptor*) thunk;
925          *     size_t key;
926          *     size_t offset;
927          * }
928          *
929          * Params:
930          *      vd = the variable declaration for the symbol
931          *      s = the backend Symbol corresponsing to vd
932          *      sz = data size of s
933          *      dtb = where to put the data
934          */
935         static void tlsToDt(VarDeclaration vd, Symbol *s, uint sz, ref DtBuilder dtb)
936         {
937             assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
938 
939             Symbol *tlvInit = createTLVDataSymbol(vd, s);
940             auto tlvInitDtb = DtBuilder(0);
941 
942             if (sz == 0)
943                 tlvInitDtb.nzeros(1);
944             else if (vd._init)
945                 initializerToDt(vd, tlvInitDtb);
946             else
947                 Type_toDt(vd.type, tlvInitDtb);
948 
949             tlvInit.Sdt = tlvInitDtb.finish();
950             outdata(tlvInit);
951 
952             if (global.params.is64bit)
953                 tlvInit.Sclass = SCextern;
954 
955             Symbol* tlvBootstrap = objmod.tlv_bootstrap();
956             dtb.xoff(tlvBootstrap, 0, TYnptr);
957             dtb.size(0);
958             dtb.xoff(tlvInit, 0, TYnptr);
959         }
960 
961         /**
962          * Creates the data symbol used to initialize a TLS variable for Mach-O.
963          *
964          * Params:
965          *      vd = the variable declaration for the symbol
966          *      s = the back end symbol corresponding to vd
967          *
968          * Returns: the newly created symbol
969          */
970         static Symbol *createTLVDataSymbol(VarDeclaration vd, Symbol *s)
971         {
972             assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
973 
974             // Compute identifier for tlv symbol
975             OutBuffer buffer;
976             buffer.writestring(s.Sident);
977             buffer.writestring("$tlv$init");
978             const(char) *tlvInitName = buffer.peekChars();
979 
980             // Compute type for tlv symbol
981             type *t = type_fake(vd.type.ty);
982             type_setty(&t, t.Tty | mTYthreadData);
983             type_setmangle(&t, mangle(vd));
984 
985             Symbol *tlvInit = symbol_name(tlvInitName, SCstatic, t);
986             tlvInit.Sdt = null;
987             tlvInit.Salignment = type_alignsize(s.Stype);
988             if (vd.linkage == LINK.cpp)
989                 tlvInit.Sflags |= SFLpublic;
990 
991             return tlvInit;
992         }
993 
994         /**
995          * Returns the target mangling mangle_t for the given variable.
996          *
997          * Params:
998          *      vd = the variable declaration
999          *
1000          * Returns:
1001          *      the mangling that should be used for variable
1002          */
1003         static mangle_t mangle(const VarDeclaration vd)
1004         {
1005             final switch (vd.linkage)
1006             {
1007                 case LINK.windows:
1008                     return global.params.is64bit ? mTYman_c : mTYman_std;
1009 
1010                 case LINK.objc:
1011                 case LINK.c:
1012                     return mTYman_c;
1013 
1014                 case LINK.d:
1015                     return mTYman_d;
1016 
1017                 case LINK.cpp:
1018                     return mTYman_cpp;
1019 
1020                 case LINK.default_:
1021                 case LINK.system:
1022                     printf("linkage = %d\n", vd.linkage);
1023                     assert(0);
1024             }
1025         }
1026     }
1027 
1028     scope v = new ToObjFile(multiobj);
1029     ds.accept(v);
1030 }
1031 
1032 
1033 /*********************************
1034  * Finish semantic analysis of functions in vtbl[].
1035  * Params:
1036  *    cd = class which has the vtbl[]
1037  * Returns:
1038  *    true for success (no errors)
1039  */
1040 private bool finishVtbl(ClassDeclaration cd)
1041 {
1042     bool hasError = false;
1043 
1044     foreach (i; cd.vtblOffset() .. cd.vtbl.dim)
1045     {
1046         FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
1047 
1048         //printf("\tvtbl[%d] = %p\n", i, fd);
1049         if (!fd || !fd.fbody && cd.isAbstract())
1050         {
1051             // Nothing to do
1052             continue;
1053         }
1054         // Ensure function has a return value
1055         // https://issues.dlang.org/show_bug.cgi?id=4869
1056         if (!fd.functionSemantic())
1057         {
1058             hasError = true;
1059         }
1060 
1061         if (!cd.isFuncHidden(fd) || fd.isFuture())
1062         {
1063             // All good, no name hiding to check for
1064             continue;
1065         }
1066 
1067         /* fd is hidden from the view of this class.
1068          * If fd overlaps with any function in the vtbl[], then
1069          * issue 'hidden' error.
1070          */
1071         foreach (j; 1 .. cd.vtbl.dim)
1072         {
1073             if (j == i)
1074                 continue;
1075             FuncDeclaration fd2 = cd.vtbl[j].isFuncDeclaration();
1076             if (!fd2.ident.equals(fd.ident))
1077                 continue;
1078             if (fd2.isFuture())
1079                 continue;
1080             if (!fd.leastAsSpecialized(fd2) && !fd2.leastAsSpecialized(fd))
1081                 continue;
1082             // Hiding detected: same name, overlapping specializations
1083             TypeFunction tf = fd.type.toTypeFunction();
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             hasError = true;
1092             break;
1093         }
1094     }
1095 
1096     return !hasError;
1097 }
1098 
1099 
1100 /******************************************
1101  * Get offset of base class's vtbl[] initializer from start of csym.
1102  * Returns ~0 if not this csym.
1103  */
1104 
1105 uint baseVtblOffset(ClassDeclaration cd, BaseClass *bc)
1106 {
1107     //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", cd.toChars(), bc);
1108     uint csymoffset = target.classinfosize;    // must be ClassInfo.size
1109     csymoffset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1110 
1111     for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1112     {
1113         BaseClass *b = (*cd.vtblInterfaces)[i];
1114 
1115         if (b == bc)
1116             return csymoffset;
1117         csymoffset += b.sym.vtbl.dim * target.ptrsize;
1118     }
1119 
1120     // Put out the overriding interface vtbl[]s.
1121     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1122     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1123     ClassDeclaration cd2;
1124 
1125     for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass)
1126     {
1127         foreach (k; 0 .. cd2.vtblInterfaces.dim)
1128         {
1129             BaseClass *bs = (*cd2.vtblInterfaces)[k];
1130             if (bs.fillVtbl(cd, null, 0))
1131             {
1132                 if (bc == bs)
1133                 {
1134                     //printf("\tcsymoffset = x%x\n", csymoffset);
1135                     return csymoffset;
1136                 }
1137                 csymoffset += bs.sym.vtbl.dim * target.ptrsize;
1138             }
1139         }
1140     }
1141 
1142     return ~0;
1143 }
1144 
1145 /*******************
1146  * Emit the vtbl[] to static data
1147  * Params:
1148  *    dtb = static data builder
1149  *    b = base class
1150  *    bvtbl = array of functions to put in this vtbl[]
1151  *    pc = classid for this vtbl[]
1152  *    k = offset from pc to classinfo
1153  * Returns:
1154  *    number of bytes emitted
1155  */
1156 private size_t emitVtbl(ref DtBuilder dtb, BaseClass *b, ref FuncDeclarations bvtbl, ClassDeclaration pc, size_t k)
1157 {
1158     //printf("\toverriding vtbl[] for %s\n", b.sym.toChars());
1159     ClassDeclaration id = b.sym;
1160 
1161     const id_vtbl_dim = id.vtbl.dim;
1162     assert(id_vtbl_dim <= bvtbl.dim);
1163 
1164     size_t jstart = 0;
1165     if (id.vtblOffset())
1166     {
1167         // First entry is struct Interface reference
1168         dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr);
1169         jstart = 1;
1170     }
1171 
1172     foreach (j; jstart .. id_vtbl_dim)
1173     {
1174         FuncDeclaration fd = bvtbl[j];
1175         if (fd)
1176         {
1177             auto offset2 = b.offset;
1178             if (fd.interfaceVirtual)
1179             {
1180                 offset2 -= fd.interfaceVirtual.offset;
1181             }
1182             dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr);
1183         }
1184         else
1185             dtb.size(0);
1186     }
1187     return id_vtbl_dim * target.ptrsize;
1188 }
1189 
1190 
1191 /******************************************************
1192  * Generate the ClassInfo for a Class (__classZ) symbol.
1193  * Write it to the object file.
1194  * Similar to genClassInfoForInterface().
1195  * Params:
1196  *      cd = the class
1197  *      sinit = the Initializer (__initZ) symbol for the class
1198  */
1199 private void genClassInfoForClass(ClassDeclaration cd, Symbol* sinit)
1200 {
1201     // Put out the ClassInfo, which will be the __ClassZ symbol in the object file
1202     enum_SC scclass = SCcomdat;
1203     cd.csym.Sclass = scclass;
1204     cd.csym.Sfl = FLdata;
1205 
1206     /* The layout is:
1207        {
1208             void **vptr;
1209             monitor_t monitor;
1210             byte[] m_init;              // static initialization data
1211             string name;                // class name
1212             void*[] vtbl;
1213             Interface[] interfaces;
1214             ClassInfo base;             // base class
1215             void* destructor;
1216             void function(Object) classInvariant;   // class invariant
1217             ClassFlags m_flags;
1218             void* deallocator;
1219             OffsetTypeInfo[] offTi;
1220             void function(Object) defaultConstructor;
1221             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1222             immutable(void)* m_RTInfo;
1223             //TypeInfo typeinfo;
1224        }
1225      */
1226     uint offset = target.classinfosize;    // must be ClassInfo.size
1227     if (Type.typeinfoclass)
1228     {
1229         if (Type.typeinfoclass.structsize != target.classinfosize)
1230         {
1231             debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize);
1232             cd.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1233             fatal();
1234         }
1235     }
1236 
1237     auto dtb = DtBuilder(0);
1238 
1239     if (auto tic = Type.typeinfoclass)
1240     {
1241         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo
1242         if (tic.hasMonitor())
1243             dtb.size(0);                        // monitor
1244     }
1245     else
1246     {
1247         dtb.size(0);                    // BUG: should be an assert()
1248         dtb.size(0);                    // call hasMonitor()?
1249     }
1250 
1251     // m_init[]
1252     assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4));
1253     dtb.size(cd.structsize);           // size
1254     dtb.xoff(sinit, 0, TYnptr);         // initializer
1255 
1256     // name[]
1257     const(char) *name = cd.ident.toChars();
1258     size_t namelen = strlen(name);
1259     if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0))
1260     {
1261         name = cd.toPrettyChars();
1262         namelen = strlen(name);
1263     }
1264     dtb.size(namelen);
1265     dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr);
1266 
1267     // vtbl[]
1268     dtb.size(cd.vtbl.dim);
1269     if (cd.vtbl.dim)
1270         dtb.xoff(cd.vtblsym.csym, 0, TYnptr);
1271     else
1272         dtb.size(0);
1273 
1274     // interfaces[]
1275     dtb.size(cd.vtblInterfaces.dim);
1276     if (cd.vtblInterfaces.dim)
1277         dtb.xoff(cd.csym, offset, TYnptr);      // (*)
1278     else
1279         dtb.size(0);
1280 
1281     // base
1282     if (cd.baseClass)
1283         dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr);
1284     else
1285         dtb.size(0);
1286 
1287     // destructor
1288     if (cd.tidtor)
1289         dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr);
1290     else
1291         dtb.size(0);
1292 
1293     // classInvariant
1294     if (cd.inv)
1295         dtb.xoff(toSymbol(cd.inv), 0, TYnptr);
1296     else
1297         dtb.size(0);
1298 
1299     // flags
1300     ClassFlags flags = ClassFlags.hasOffTi;
1301     if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass;
1302     if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass;
1303     flags |= ClassFlags.hasGetMembers;
1304     flags |= ClassFlags.hasTypeInfo;
1305     if (cd.ctor)
1306         flags |= ClassFlags.hasCtor;
1307     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1308     {
1309         if (pc.dtor)
1310         {
1311             flags |= ClassFlags.hasDtor;
1312             break;
1313         }
1314     }
1315     if (cd.isAbstract())
1316         flags |= ClassFlags.isAbstract;
1317 
1318     flags |= ClassFlags.noPointers;     // initially assume no pointers
1319 Louter:
1320     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1321     {
1322         if (pc.members)
1323         {
1324             for (size_t i = 0; i < pc.members.dim; i++)
1325             {
1326                 Dsymbol sm = (*pc.members)[i];
1327                 //printf("sm = %s %s\n", sm.kind(), sm.toChars());
1328                 if (sm.hasPointers())
1329                 {
1330                     flags &= ~ClassFlags.noPointers;  // not no-how, not no-way
1331                     break Louter;
1332                 }
1333             }
1334         }
1335     }
1336     dtb.size(flags);
1337 
1338     // deallocator
1339     dtb.size(0);
1340 
1341     // offTi[]
1342     dtb.size(0);
1343     dtb.size(0);            // null for now, fix later
1344 
1345     // defaultConstructor
1346     if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable))
1347         dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr);
1348     else
1349         dtb.size(0);
1350 
1351     // m_RTInfo
1352     if (cd.getRTInfo)
1353         Expression_toDt(cd.getRTInfo, dtb);
1354     else if (flags & ClassFlags.noPointers)
1355         dtb.size(0);
1356     else
1357         dtb.size(1);
1358 
1359     //dtb.xoff(toSymbol(cd.type.vtinfo), 0, TYnptr); // typeinfo
1360 
1361     //////////////////////////////////////////////
1362 
1363     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1364     // of the fixup (*)
1365 
1366     offset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1367     for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1368     {
1369         BaseClass *b = (*cd.vtblInterfaces)[i];
1370         ClassDeclaration id = b.sym;
1371 
1372         /* The layout is:
1373          *  struct Interface
1374          *  {
1375          *      ClassInfo classinfo;
1376          *      void*[] vtbl;
1377          *      size_t offset;
1378          *  }
1379          */
1380 
1381         // Fill in vtbl[]
1382         b.fillVtbl(cd, &b.vtbl, 1);
1383 
1384         // classinfo
1385         dtb.xoff(toSymbol(id), 0, TYnptr);
1386 
1387         // vtbl[]
1388         dtb.size(id.vtbl.dim);
1389         dtb.xoff(cd.csym, offset, TYnptr);
1390 
1391         // offset
1392         dtb.size(b.offset);
1393     }
1394 
1395     // Put out the (*vtblInterfaces)[].vtbl[]
1396     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1397     //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars());
1398     foreach (i; 0 .. cd.vtblInterfaces.dim)
1399     {
1400         BaseClass *b = (*cd.vtblInterfaces)[i];
1401         offset += emitVtbl(dtb, b, b.vtbl, cd, i);
1402     }
1403 
1404     // Put out the overriding interface vtbl[]s.
1405     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1406     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1407     for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass)
1408     {
1409         foreach (i; 0 .. pc.vtblInterfaces.dim)
1410         {
1411             BaseClass *b = (*pc.vtblInterfaces)[i];
1412             FuncDeclarations bvtbl;
1413             if (b.fillVtbl(cd, &bvtbl, 0))
1414             {
1415                 offset += emitVtbl(dtb, b, bvtbl, pc, i);
1416             }
1417         }
1418     }
1419 
1420     //////////////////////////////////////////////
1421 
1422     dtpatchoffset(pdtname, offset);
1423 
1424     dtb.nbytes(cast(uint)(namelen + 1), name);
1425     const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align
1426     dtb.nzeros(cast(uint)namepad);
1427 
1428     cd.csym.Sdt = dtb.finish();
1429     // ClassInfo cannot be const data, because we use the monitor on it
1430     outdata(cd.csym);
1431     if (cd.isExport())
1432         objmod.export_symbol(cd.csym, 0);
1433 }
1434 
1435 /******************************************************
1436  * Generate the ClassInfo for an Interface (classZ symbol).
1437  * Write it to the object file.
1438  * Params:
1439  *      id = the interface
1440  */
1441 private void genClassInfoForInterface(InterfaceDeclaration id)
1442 {
1443     enum_SC scclass = SCcomdat;
1444 
1445     // Put out the ClassInfo
1446     id.csym.Sclass = scclass;
1447     id.csym.Sfl = FLdata;
1448 
1449     /* The layout is:
1450        {
1451             void **vptr;
1452             monitor_t monitor;
1453             byte[] m_init;              // static initialization data
1454             string name;                // class name
1455             void*[] vtbl;
1456             Interface[] interfaces;
1457             ClassInfo base;             // base class
1458             void* destructor;
1459             void function(Object) classInvariant;   // class invariant
1460             ClassFlags m_flags;
1461             void* deallocator;
1462             OffsetTypeInfo[] offTi;
1463             void function(Object) defaultConstructor;
1464             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1465             immutable(void)* m_RTInfo;
1466             //TypeInfo typeinfo;
1467        }
1468      */
1469     auto dtb = DtBuilder(0);
1470 
1471     if (auto tic = Type.typeinfoclass)
1472     {
1473         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo
1474         if (tic.hasMonitor())
1475             dtb.size(0);                        // monitor
1476     }
1477     else
1478     {
1479         dtb.size(0);                    // BUG: should be an assert()
1480         dtb.size(0);                    // call hasMonitor()?
1481     }
1482 
1483     // m_init[]
1484     dtb.size(0);                        // size
1485     dtb.size(0);                        // initializer
1486 
1487     // name[]
1488     const(char) *name = id.toPrettyChars();
1489     size_t namelen = strlen(name);
1490     dtb.size(namelen);
1491     dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr);
1492 
1493     // vtbl[]
1494     dtb.size(0);
1495     dtb.size(0);
1496 
1497     // interfaces[]
1498     uint offset = target.classinfosize;
1499     dtb.size(id.vtblInterfaces.dim);
1500     if (id.vtblInterfaces.dim)
1501     {
1502         if (Type.typeinfoclass)
1503         {
1504             if (Type.typeinfoclass.structsize != offset)
1505             {
1506                 id.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1507                 fatal();
1508             }
1509         }
1510         dtb.xoff(id.csym, offset, TYnptr);      // (*)
1511     }
1512     else
1513     {
1514         dtb.size(0);
1515     }
1516 
1517     // base
1518     assert(!id.baseClass);
1519     dtb.size(0);
1520 
1521     // destructor
1522     dtb.size(0);
1523 
1524     // classInvariant
1525     dtb.size(0);
1526 
1527     // flags
1528     ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo;
1529     if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass;
1530     dtb.size(flags);
1531 
1532     // deallocator
1533     dtb.size(0);
1534 
1535     // offTi[]
1536     dtb.size(0);
1537     dtb.size(0);            // null for now, fix later
1538 
1539     // defaultConstructor
1540     dtb.size(0);
1541 
1542     // xgetMembers
1543     //dtb.size(0);
1544 
1545     // m_RTInfo
1546     if (id.getRTInfo)
1547         Expression_toDt(id.getRTInfo, dtb);
1548     else
1549         dtb.size(0);       // no pointers
1550 
1551     //dtb.xoff(toSymbol(id.type.vtinfo), 0, TYnptr); // typeinfo
1552 
1553     //////////////////////////////////////////////
1554 
1555     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1556     // of the fixup (*)
1557 
1558     offset += id.vtblInterfaces.dim * (4 * target.ptrsize);
1559     for (size_t i = 0; i < id.vtblInterfaces.dim; i++)
1560     {
1561         BaseClass *b = (*id.vtblInterfaces)[i];
1562         ClassDeclaration base = b.sym;
1563 
1564         // classinfo
1565         dtb.xoff(toSymbol(base), 0, TYnptr);
1566 
1567         // vtbl[]
1568         dtb.size(0);
1569         dtb.size(0);
1570 
1571         // offset
1572         dtb.size(b.offset);
1573     }
1574 
1575     //////////////////////////////////////////////
1576 
1577     dtpatchoffset(pdtname, offset);
1578 
1579     dtb.nbytes(cast(uint)(namelen + 1), name);
1580     const size_t namepad =  -(namelen + 1) & (target.ptrsize - 1); // align
1581     dtb.nzeros(cast(uint)namepad);
1582 
1583     id.csym.Sdt = dtb.finish();
1584     out_readonly(id.csym);
1585     outdata(id.csym);
1586     if (id.isExport())
1587         objmod.export_symbol(id.csym, 0);
1588 }