1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1984-1998 by Symantec
6  *              Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/out.d, backend/out.d)
10  */
11 
12 
13 module dmd.backend.dout;
14 
15 version (SPP) { } else
16 {
17 
18 import core.stdc.stdio;
19 import core.stdc.string;
20 
21 import dmd.backend.cc;
22 import dmd.backend.cdef;
23 import dmd.backend.cgcv;
24 import dmd.backend.code;
25 import dmd.backend.code_x86;
26 import dmd.backend.cv4;
27 import dmd.backend.dt;
28 import dmd.backend.dlist;
29 import dmd.backend.mem;
30 import dmd.backend.el;
31 import dmd.backend.exh;
32 import dmd.backend.global;
33 import dmd.backend.goh;
34 import dmd.backend.obj;
35 import dmd.backend.oper;
36 import dmd.backend.outbuf;
37 import dmd.backend.rtlsym;
38 import dmd.backend.ty;
39 import dmd.backend.type;
40 
41 version (SCPP)
42 {
43     import cpp;
44     import msgs2;
45     import parser;
46 }
47 version (HTOD)
48 {
49     import cpp;
50     import msgs2;
51     import parser;
52 }
53 
54 version (Windows)
55 {
56     extern (C)
57     {
58         int stricmp(const(char)*, const(char)*) pure nothrow @nogc;
59         int memicmp(const(void)*, const(void)*, size_t) pure nothrow @nogc;
60     }
61 }
62 
63 extern (C++):
64 
65 nothrow:
66 
67 void dt_writeToObj(Obj objmod, dt_t *dt, int seg, ref targ_size_t offset);
68 
69 // Determine if this Symbol is stored in a COMDAT
70 bool symbol_iscomdat2(Symbol* s)
71 {
72     version (MARS)
73     {
74         return s.Sclass == SCcomdat ||
75             config.flags2 & CFG2comdat && s.Sclass == SCinline ||
76             config.flags4 & CFG4allcomdat && s.Sclass == SCglobal;
77     }
78     else
79     {
80         return s.Sclass == SCcomdat ||
81             config.flags2 & CFG2comdat && s.Sclass == SCinline ||
82             config.flags4 & CFG4allcomdat && (s.Sclass == SCglobal || s.Sclass == SCstatic);
83     }
84 }
85 
86 version (SCPP)
87 {
88 
89 /**********************************
90  * We put out an external definition.
91  */
92 void out_extdef(Symbol *s)
93 {
94     pstate.STflags |= PFLextdef;
95     if (//config.flags2 & CFG2phgen ||
96         (config.flags2 & (CFG2phauto | CFG2phautoy) &&
97             !(pstate.STflags & (PFLhxwrote | PFLhxdone)))
98        )
99 
100         synerr(EM_data_in_pch,prettyident(s));          // data or code in precompiled header
101 }
102 
103 /********************************
104  * Put out code segment name record.
105  */
106 void outcsegname(char *csegname)
107 {
108     Obj.codeseg(csegname,0);
109 }
110 
111 }
112 
113 version (HTOD)
114 {
115     void outcsegname(char *csegname) { }
116 }
117 
118 /***********************************
119  * Output function thunk.
120  */
121 extern (C) void outthunk(Symbol *sthunk,Symbol *sfunc,uint p,tym_t thisty,
122         targ_size_t d,int i,targ_size_t d2)
123 {
124 version (HTOD) { } else
125 {
126     sthunk.Sseg = cseg;
127     cod3_thunk(sthunk,sfunc,p,thisty,cast(uint)d,i,cast(uint)d2);
128     sthunk.Sfunc.Fflags &= ~Fpending;
129     sthunk.Sfunc.Fflags |= Foutput;   /* mark it as having been output */
130 }
131 }
132 
133 
134 /***************************
135  * Write out statically allocated data.
136  * Input:
137  *      s               symbol to be initialized
138  */
139 
140 void outdata(Symbol *s)
141 {
142 version (HTOD)
143 {
144     return;
145 }
146 
147     int seg;
148     targ_size_t offset;
149     int flags;
150     const int codeseg = cseg;
151 
152     symbol_debug(s);
153 
154     debug
155     debugy && printf("outdata('%s')\n",s.Sident.ptr);
156 
157     //printf("outdata('%s', ty=x%x)\n",s.Sident.ptr,s.Stype.Tty);
158     //symbol_print(s);
159 
160     // Data segment variables are always live on exit from a function
161     s.Sflags |= SFLlivexit;
162 
163     dt_t *dtstart = s.Sdt;
164     s.Sdt = null;                      // it will be free'd
165     targ_size_t datasize = 0;
166     tym_t ty = s.ty();
167 version (SCPP)
168 {
169     if (eecontext.EEcompile)
170     {   s.Sfl = (s.ty() & mTYfar) ? FLfardata : FLextern;
171         s.Sseg = UNKNOWN;
172         goto Lret;                      // don't output any data
173     }
174 }
175     if (ty & mTYexport && config.wflags & WFexpdef && s.Sclass != SCstatic)
176         objmod.export_symbol(s,0);        // export data definition
177     for (dt_t *dt = dtstart; dt; dt = dt.DTnext)
178     {
179         //printf("\tdt = %p, dt = %d\n",dt,dt.dt);
180         switch (dt.dt)
181         {   case DT_abytes:
182             {   // Put out the data for the string, and
183                 // reserve a spot for a pointer to that string
184                 datasize += size(dt.Dty);      // reserve spot for pointer to string
185                 if (tybasic(dt.Dty) == TYcptr)
186                 {   dt.DTseg = codeseg;
187                     dt.DTabytes += Offset(codeseg);
188                     goto L1;
189                 }
190                 else if (tybasic(dt.Dty) == TYfptr &&
191                          dt.DTnbytes > config.threshold)
192                 {
193 version (SCPP)
194 {
195                     {
196                     targ_size_t foffset;
197                     dt.DTseg = objmod.fardata(s.Sident.ptr,dt.DTnbytes,&foffset);
198                     dt.DTabytes += foffset;
199                     }
200 }
201                 L1:
202                     objmod.write_bytes(SegData[dt.DTseg],dt.DTnbytes,dt.DTpbytes);
203                     break;
204                 }
205                 else
206                 {
207                     dt.DTabytes += objmod.data_readonly(cast(char*)dt.DTpbytes,dt.DTnbytes,&dt.DTseg);
208                 }
209                 break;
210             }
211 
212             case DT_ibytes:
213                 datasize += dt.DTn;
214                 break;
215 
216             case DT_nbytes:
217                 //printf("DT_nbytes %d\n", dt.DTnbytes);
218                 datasize += dt.DTnbytes;
219                 break;
220 
221             case DT_azeros:
222                 /* A block of zeros
223                  */
224                 //printf("DT_azeros %d\n", dt.DTazeros);
225                 datasize += dt.DTazeros;
226                 if (dt == dtstart && !dt.DTnext && s.Sclass != SCcomdat &&
227                     (s.Sseg == UNKNOWN || s.Sseg <= UDATA))
228                 {   /* first and only, so put in BSS segment
229                      */
230                     switch (ty & mTYLINK)
231                     {
232 version (SCPP)
233 {
234                         case mTYfar:                    // if far data
235                             s.Sseg = objmod.fardata(s.Sident.ptr,datasize,&s.Soffset);
236                             s.Sfl = FLfardata;
237                             break;
238 }
239 
240                         case mTYcs:
241                             s.Sseg = codeseg;
242                             Offset(codeseg) = _align(datasize,Offset(codeseg));
243                             s.Soffset = Offset(codeseg);
244                             Offset(codeseg) += datasize;
245                             s.Sfl = FLcsdata;
246                             break;
247 
248                         case mTYthreadData:
249                             assert(config.objfmt == OBJ_MACH && I64);
250                             goto case;
251                         case mTYthread:
252                         {   seg_data *pseg = objmod.tlsseg_bss();
253                             s.Sseg = pseg.SDseg;
254                             objmod.data_start(s, datasize, pseg.SDseg);
255                             if (config.objfmt == OBJ_OMF)
256                                 pseg.SDoffset += datasize;
257                             else
258                                 objmod.lidata(pseg.SDseg, pseg.SDoffset, datasize);
259                             s.Sfl = FLtlsdata;
260                             break;
261                         }
262 
263                         default:
264                             s.Sseg = UDATA;
265                             objmod.data_start(s,datasize,UDATA);
266                             objmod.lidata(s.Sseg,s.Soffset,datasize);
267                             s.Sfl = FLudata;           // uninitialized data
268                             break;
269                     }
270                     assert(s.Sseg && s.Sseg != UNKNOWN);
271                     if (s.Sclass == SCglobal || (s.Sclass == SCstatic && config.objfmt != OBJ_OMF)) // if a pubdef to be done
272                         objmod.pubdefsize(s.Sseg,s,s.Soffset,datasize);   // do the definition
273                     searchfixlist(s);
274                     if (config.fulltypes &&
275                         !(s.Sclass == SCstatic && funcsym_p)) // not local static
276                         cv_outsym(s);
277 version (SCPP)
278 {
279                     out_extdef(s);
280 }
281                     goto Lret;
282                 }
283                 break;
284 
285             case DT_common:
286                 assert(!dt.DTnext);
287                 outcommon(s,dt.DTazeros);
288                 goto Lret;
289 
290             case DT_xoff:
291             {   Symbol *sb = dt.DTsym;
292 
293                 if (tyfunc(sb.ty()))
294                 {
295 version (SCPP)
296 {
297                     nwc_mustwrite(sb);
298 }
299                 }
300                 else if (sb.Sdt)               // if initializer for symbol
301 { if (!s.Sseg) s.Sseg = DATA;
302                     outdata(sb);                // write out data for symbol
303 }
304             }
305                 goto case;
306             case DT_coff:
307                 datasize += size(dt.Dty);
308                 break;
309             default:
310                 debug
311                 printf("dt = %p, dt = %d\n",dt,dt.dt);
312                 assert(0);
313         }
314     }
315 
316     if (s.Sclass == SCcomdat)          // if initialized common block
317     {
318         seg = objmod.comdatsize(s, datasize);
319         switch (ty & mTYLINK)
320         {
321             case mTYfar:                // if far data
322                 s.Sfl = FLfardata;
323                 break;
324 
325             case mTYcs:
326                 s.Sfl = FLcsdata;
327                 break;
328 
329             case mTYnear:
330             case 0:
331                 s.Sfl = FLdata;        // initialized data
332                 break;
333 
334             case mTYthread:
335                 s.Sfl = FLtlsdata;
336                 break;
337 
338             default:
339                 assert(0);
340         }
341     }
342     else
343     {
344       switch (ty & mTYLINK)
345       {
346 version (SCPP)
347 {
348         case mTYfar:                    // if far data
349             seg = objmod.fardata(s.Sident.ptr,datasize,&s.Soffset);
350             s.Sfl = FLfardata;
351             break;
352 }
353 
354         case mTYcs:
355             seg = codeseg;
356             Offset(codeseg) = _align(datasize,Offset(codeseg));
357             s.Soffset = Offset(codeseg);
358             s.Sfl = FLcsdata;
359             break;
360 
361         case mTYthreadData:
362         {
363             assert(config.objfmt == OBJ_MACH && I64);
364 
365             seg_data *pseg = objmod.tlsseg_data();
366             s.Sseg = pseg.SDseg;
367             objmod.data_start(s, datasize, s.Sseg);
368             seg = pseg.SDseg;
369             s.Sfl = FLtlsdata;
370             break;
371         }
372         case mTYthread:
373         {
374             seg_data *pseg = objmod.tlsseg();
375             s.Sseg = pseg.SDseg;
376             objmod.data_start(s, datasize, s.Sseg);
377             seg = pseg.SDseg;
378             s.Sfl = FLtlsdata;
379             break;
380         }
381         case mTYnear:
382         case 0:
383             if (
384                 s.Sseg == 0 ||
385                 s.Sseg == UNKNOWN)
386                 s.Sseg = DATA;
387             seg = objmod.data_start(s,datasize,DATA);
388             s.Sfl = FLdata;            // initialized data
389             break;
390 
391         default:
392             assert(0);
393       }
394     }
395     if (s.Sseg == UNKNOWN && (config.objfmt == OBJ_ELF || config.objfmt == OBJ_MACH))
396         s.Sseg = seg;
397     else if (config.objfmt == OBJ_OMF)
398         s.Sseg = seg;
399     else
400         seg = s.Sseg;
401 
402     if (s.Sclass == SCglobal || (s.Sclass == SCstatic && config.objfmt != OBJ_OMF))
403         objmod.pubdefsize(seg,s,s.Soffset,datasize);    /* do the definition            */
404 
405     assert(s.Sseg != UNKNOWN);
406     if (config.fulltypes &&
407         !(s.Sclass == SCstatic && funcsym_p)) // not local static
408         cv_outsym(s);
409     searchfixlist(s);
410 
411     /* Go back through list, now that we know its size, and send out    */
412     /* the data.                                                        */
413 
414     offset = s.Soffset;
415 
416     dt_writeToObj(objmod, dtstart, seg, offset);
417     Offset(seg) = offset;
418 version (SCPP)
419 {
420     out_extdef(s);
421 }
422 Lret:
423     dt_free(dtstart);
424 }
425 
426 
427 /********************************************
428  * Write dt to Object file.
429  * Params:
430  *      objmod = reference to object file
431  *      dt = data to write
432  *      seg = segment to write it to
433  *      offset = starting offset in segment - will get updated to reflect ending offset
434  */
435 
436 void dt_writeToObj(Obj objmod, dt_t *dt, int seg, ref targ_size_t offset)
437 {
438     for (; dt; dt = dt.DTnext)
439     {
440         switch (dt.dt)
441         {
442             case DT_abytes:
443             {
444                 int flags;
445                 if (tyreg(dt.Dty))
446                     flags = CFoff;
447                 else
448                     flags = CFoff | CFseg;
449                 if (I64)
450                     flags |= CFoffset64;
451                 if (tybasic(dt.Dty) == TYcptr)
452                     objmod.reftocodeseg(seg,offset,dt.DTabytes);
453                 else
454                 {
455 static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_DRAGONFLYBSD || TARGET_SOLARIS)
456 {
457                     objmod.reftodatseg(seg,offset,dt.DTabytes,dt.DTseg,flags);
458 }
459 else
460 {
461                     if (dt.DTseg == DATA)
462                         objmod.reftodatseg(seg,offset,dt.DTabytes,DATA,flags);
463                     else
464                     {
465 version (MARS)
466 {
467                         if (dt.DTseg == CDATA)
468                             objmod.reftodatseg(seg,offset,dt.DTabytes,CDATA,flags);
469                         else
470                             objmod.reftofarseg(seg,offset,dt.DTabytes,dt.DTseg,flags);
471 }
472 else
473 {
474                         objmod.reftofarseg(seg,offset,dt.DTabytes,dt.DTseg,flags);
475 }
476                     }
477 }
478                 }
479                 offset += size(dt.Dty);
480                 break;
481             }
482 
483             case DT_ibytes:
484                 objmod.bytes(seg,offset,dt.DTn,dt.DTdata.ptr);
485                 offset += dt.DTn;
486                 break;
487 
488             case DT_nbytes:
489                 objmod.bytes(seg,offset,dt.DTnbytes,dt.DTpbytes);
490                 offset += dt.DTnbytes;
491                 break;
492 
493             case DT_azeros:
494                 //printf("objmod.lidata(seg = %d, offset = %d, azeros = %d)\n", seg, offset, dt.DTazeros);
495                 SegData[seg].SDoffset = offset;
496                 objmod.lidata(seg,offset,dt.DTazeros);
497                 offset = SegData[seg].SDoffset;
498                 break;
499 
500             case DT_xoff:
501             {
502                 Symbol *sb = dt.DTsym;          // get external symbol pointer
503                 targ_size_t a = dt.DToffset;    // offset from it
504                 int flags;
505                 if (tyreg(dt.Dty))
506                     flags = CFoff;
507                 else
508                     flags = CFoff | CFseg;
509                 if (I64 && tysize(dt.Dty) == 8)
510                     flags |= CFoffset64;
511                 offset += objmod.reftoident(seg,offset,sb,a,flags);
512                 break;
513             }
514 
515             case DT_coff:
516                 objmod.reftocodeseg(seg,offset,dt.DToffset);
517                 offset += _tysize[TYint];
518                 break;
519 
520             default:
521                 //printf("dt = %p, dt = %d\n",dt,dt.dt);
522                 assert(0);
523         }
524     }
525 }
526 
527 
528 /******************************
529  * Output n bytes of a common block, n > 0.
530  */
531 
532 void outcommon(Symbol *s,targ_size_t n)
533 {
534     //printf("outcommon('%s',%d)\n",s.Sident.ptr,n);
535     if (n != 0)
536     {
537         assert(s.Sclass == SCglobal);
538         if (s.ty() & mTYcs) // if store in code segment
539         {
540             /* COMDEFs not supported in code segment
541              * so put them out as initialized 0s
542              */
543             auto dtb = DtBuilder(0);
544             dtb.nzeros(cast(uint)n);
545             s.Sdt = dtb.finish();
546             outdata(s);
547 version (SCPP)
548 {
549             out_extdef(s);
550 }
551         }
552         else if (s.ty() & mTYthread) // if store in thread local segment
553         {
554             if (config.objfmt == OBJ_ELF)
555             {
556                 s.Sclass = SCcomdef;
557                 objmod.common_block(s, 0, n, 1);
558             }
559             else
560             {
561                 /* COMDEFs not supported in tls segment
562                  * so put them out as COMDATs with initialized 0s
563                  */
564                 s.Sclass = SCcomdat;
565                 auto dtb = DtBuilder(0);
566                 dtb.nzeros(cast(uint)n);
567                 s.Sdt = dtb.finish();
568                 outdata(s);
569 version (SCPP)
570 {
571                 if (config.objfmt == OBJ_OMF)
572                     out_extdef(s);
573 }
574             }
575         }
576         else
577         {
578             s.Sclass = SCcomdef;
579             if (config.objfmt == OBJ_OMF)
580             {
581                 s.Sxtrnnum = objmod.common_block(s,(s.ty() & mTYfar) == 0,n,1);
582                 if (s.ty() & mTYfar)
583                     s.Sfl = FLfardata;
584                 else
585                     s.Sfl = FLextern;
586                 s.Sseg = UNKNOWN;
587                 pstate.STflags |= PFLcomdef;
588 version (SCPP)
589 {
590                 ph_comdef(s);               // notify PH that a COMDEF went out
591 }
592             }
593             else
594                 objmod.common_block(s, 0, n, 1);
595         }
596         if (config.fulltypes)
597             cv_outsym(s);
598     }
599 }
600 
601 /*************************************
602  * Mark a Symbol as going into a read-only segment.
603  */
604 
605 void out_readonly(Symbol *s)
606 {
607     if (config.objfmt == OBJ_ELF || config.objfmt == OBJ_MACH)
608     {
609         /* Cannot have pointers in CDATA when compiling PIC code, because
610          * they require dynamic relocations of the read-only segment.
611          * Instead use the .data.rel.ro section.
612          * https://issues.dlang.org/show_bug.cgi?id=11171
613          */
614         if (config.flags3 & CFG3pic && dtpointers(s.Sdt))
615             s.Sseg = CDATAREL;
616         else
617             s.Sseg = CDATA;
618     }
619     else
620     {
621         s.Sseg = CDATA;
622     }
623 }
624 
625 /*************************************
626  * Write out a readonly string literal in an implementation-defined
627  * manner.
628  * Params:
629  *      str = pointer to string data (need not have terminating 0)
630  *      len = number of characters in string
631  *      sz = size of each character (1, 2 or 4)
632  * Returns: a Symbol pointing to it.
633  */
634 Symbol *out_string_literal(const(char)* str, uint len, uint sz)
635 {
636     tym_t ty = TYchar;
637     if (sz == 2)
638         ty = TYchar16;
639     else if (sz == 4)
640         ty = TYdchar;
641     Symbol *s = symbol_generate(SCstatic,type_static_array(len, tstypes[ty]));
642     switch (config.objfmt)
643     {
644         case OBJ_ELF:
645         case OBJ_MACH:
646             s.Sseg = objmod.string_literal_segment(sz);
647             break;
648 
649         case OBJ_MSCOFF:
650         case OBJ_OMF:   // goes into COMDATs, handled elsewhere
651         default:
652             assert(0);
653     }
654 
655     /* If there are any embedded zeros, this can't go in the special string segments
656      * which assume that 0 is the end of the string.
657      */
658     switch (sz)
659     {
660         case 1:
661             if (memchr(str, 0, len))
662                 s.Sseg = CDATA;
663             break;
664 
665         case 2:
666             for (int i = 0; i < len; ++i)
667             {
668                 const(ushort)* p = cast(const(ushort)*)str;
669                 if (p[i] == 0)
670                 {
671                     s.Sseg = CDATA;
672                     break;
673                 }
674             }
675             break;
676 
677         case 4:
678             for (int i = 0; i < len; ++i)
679             {
680                 const(uint)* p = cast(const(uint)*)str;
681                 if (p[i] == 0)
682                 {
683                     s.Sseg = CDATA;
684                     break;
685                 }
686             }
687             break;
688 
689         default:
690             assert(0);
691     }
692 
693     auto dtb = DtBuilder(0);
694     dtb.nbytes(cast(uint)(len * sz), str);
695     dtb.nzeros(cast(uint)sz);       // include terminating 0
696     s.Sdt = dtb.finish();
697     s.Sfl = FLdata;
698     s.Salignment = sz;
699     outdata(s);
700     return s;
701 }
702 
703 
704 /******************************
705  * Walk expression tree, converting it from a PARSER tree to
706  * a code generator tree.
707  */
708 
709 /*private*/ void outelem(elem *e, ref bool addressOfParam)
710 {
711     Symbol *s;
712     tym_t tym;
713     elem *e1;
714 version (SCPP)
715 {
716     type *t;
717 }
718 
719 again:
720     assert(e);
721     elem_debug(e);
722 
723 debug
724 {
725     if (OTbinary(e.Eoper))
726         assert(e.EV.E1 && e.EV.E2);
727 //    else if (OTunary(e.Eoper))
728 //      assert(e.EV.E1 && !e.EV.E2);
729 }
730 
731 version (SCPP)
732 {
733     t = e.ET;
734     assert(t);
735     type_debug(t);
736     tym = t.Tty;
737     switch (tybasic(tym))
738     {
739         case TYstruct:
740             t.Tcount++;
741             break;
742 
743         case TYarray:
744             t.Tcount++;
745             break;
746 
747         case TYbool:
748         case TYwchar_t:
749         case TYchar16:
750         case TYmemptr:
751         case TYvtshape:
752         case TYnullptr:
753             tym = tym_conv(t);
754             e.ET = null;
755             break;
756 
757         case TYenum:
758             tym = tym_conv(t.Tnext);
759             e.ET = null;
760             break;
761 
762         default:
763             e.ET = null;
764             break;
765     }
766     e.Nflags = 0;
767     e.Ety = tym;
768 }
769 
770     switch (e.Eoper)
771     {
772     default:
773     Lop:
774 debug
775 {
776         //if (!EOP(e)) printf("e.Eoper = x%x\n",e.Eoper);
777 }
778         if (OTbinary(e.Eoper))
779         {   outelem(e.EV.E1, addressOfParam);
780             e = e.EV.E2;
781         }
782         else if (OTunary(e.Eoper))
783         {
784             e = e.EV.E1;
785         }
786         else
787             break;
788 version (SCPP)
789 {
790         type_free(t);
791 }
792         goto again;                     /* iterate instead of recurse   */
793     case OPaddr:
794         e1 = e.EV.E1;
795         if (e1.Eoper == OPvar)
796         {   // Fold into an OPrelconst
797 version (SCPP)
798 {
799             el_copy(e,e1);
800             e.ET = t;
801 }
802 else
803 {
804             tym = e.Ety;
805             el_copy(e,e1);
806             e.Ety = tym;
807 }
808             e.Eoper = OPrelconst;
809             el_free(e1);
810             goto again;
811         }
812         goto Lop;
813 
814     case OPrelconst:
815     case OPvar:
816     L6:
817         s = e.EV.Vsym;
818         assert(s);
819         symbol_debug(s);
820         switch (s.Sclass)
821         {
822             case SCregpar:
823             case SCparameter:
824             case SCshadowreg:
825                 if (e.Eoper == OPrelconst)
826                 {
827                     if (I16)
828                         addressOfParam = true;   // taking addr of param list
829                     else
830                         s.Sflags &= ~(SFLunambig | GTregcand);
831                 }
832                 break;
833 
834             case SCstatic:
835             case SClocstat:
836             case SCextern:
837             case SCglobal:
838             case SCcomdat:
839             case SCcomdef:
840             case SCpseudo:
841             case SCinline:
842             case SCsinline:
843             case SCeinline:
844                 s.Sflags |= SFLlivexit;
845                 goto case;
846             case SCauto:
847             case SCregister:
848             case SCfastpar:
849             case SCbprel:
850                 if (e.Eoper == OPrelconst)
851                 {
852                     s.Sflags &= ~(SFLunambig | GTregcand);
853                 }
854                 else if (s.ty() & mTYfar)
855                     e.Ety |= mTYfar;
856                 break;
857 version (SCPP)
858 {
859             case SCmember:
860                 err_noinstance(s.Sscope,s);
861                 goto L5;
862 
863             case SCstruct:
864                 cpperr(EM_no_instance,s.Sident.ptr);       // no instance of class
865             L5:
866                 e.Eoper = OPconst;
867                 e.Ety = TYint;
868                 return;
869 
870             case SCfuncalias:
871                 e.EV.Vsym = s.Sfunc.Falias;
872                 goto L6;
873 
874             case SCstack:
875                 break;
876 
877             case SCfunctempl:
878                 cpperr(EM_no_template_instance, s.Sident.ptr);
879                 break;
880 
881             default:
882                 symbol_print(s);
883                 WRclass(cast(SC) s.Sclass);
884                 assert(0);
885 }
886 else
887 {
888             default:
889                 break;
890 }
891         }
892 version (SCPP)
893 {
894         if (tyfunc(s.ty()))
895         {
896             nwc_mustwrite(s);           /* must write out function      */
897         }
898         else if (s.Sdt)                /* if initializer for symbol    */
899             outdata(s);                 // write out data for symbol
900         if (config.flags3 & CFG3pic)
901         {
902             objmod.gotref(s);
903         }
904 }
905         break;
906 
907     case OPstring:
908     case OPconst:
909     case OPstrthis:
910         break;
911 
912     case OPsizeof:
913 version (SCPP)
914 {
915         e.Eoper = OPconst;
916         e.EV.Vlong = type_size(e.EV.Vsym.Stype);
917         break;
918 }
919 else
920 {
921         assert(0);
922 }
923 
924 version (SCPP)
925 {
926     case OPstreq:
927     case OPstrpar:
928     case OPstrctor:
929         type_size(e.EV.E1.ET);
930         goto Lop;
931 
932     case OPasm:
933         break;
934 
935     case OPctor:
936         nwc_mustwrite(e.EV.Edtor);
937         goto case;
938     case OPdtor:
939         // Don't put 'this' pointers in registers if we need
940         // them for EH stack cleanup.
941         e1 = e.EV.E1;
942         elem_debug(e1);
943         if (e1.Eoper == OPadd)
944             e1 = e1.EV.E1;
945         if (e1.Eoper == OPvar)
946             e1.EV.Vsym.Sflags &= ~GTregcand;
947         goto Lop;
948 
949     case OPmark:
950         break;
951 }
952     }
953 version (SCPP)
954 {
955     type_free(t);
956 }
957 }
958 
959 /*************************************
960  * Determine register candidates.
961  */
962 
963 void out_regcand(symtab_t *psymtab)
964 {
965     //printf("out_regcand()\n");
966     const bool ifunc = (tybasic(funcsym_p.ty()) == TYifunc);
967     for (SYMIDX si = 0; si < psymtab.top; si++)
968     {   Symbol *s = psymtab.tab[si];
969 
970         symbol_debug(s);
971         //assert(sytab[s.Sclass] & SCSS);      // only stack variables
972         s.Ssymnum = si;                        // Ssymnum trashed by cpp_inlineexpand
973         if (!(s.ty() & (mTYvolatile | mTYshared)) &&
974             !(ifunc && (s.Sclass == SCparameter || s.Sclass == SCregpar)) &&
975             s.Sclass != SCstatic)
976             s.Sflags |= (GTregcand | SFLunambig);      // assume register candidate
977         else
978             s.Sflags &= ~(GTregcand | SFLunambig);
979     }
980 
981     bool addressOfParam = false;                  // haven't taken addr of param yet
982     for (block *b = startblock; b; b = b.Bnext)
983     {
984         if (b.Belem)
985             out_regcand_walk(b.Belem, addressOfParam);
986 
987         // Any assembler blocks make everything ambiguous
988         if (b.BC == BCasm)
989             for (SYMIDX si = 0; si < psymtab.top; si++)
990                 psymtab.tab[si].Sflags &= ~(SFLunambig | GTregcand);
991     }
992 
993     // If we took the address of one parameter, assume we took the
994     // address of all non-register parameters.
995     if (addressOfParam)                      // if took address of a parameter
996     {
997         for (SYMIDX si = 0; si < psymtab.top; si++)
998             if (psymtab.tab[si].Sclass == SCparameter || psymtab.tab[si].Sclass == SCshadowreg)
999                 psymtab.tab[si].Sflags &= ~(SFLunambig | GTregcand);
1000     }
1001 
1002 }
1003 
1004 private void out_regcand_walk(elem *e, ref bool addressOfParam)
1005 {
1006     while (1)
1007     {   elem_debug(e);
1008 
1009         if (OTbinary(e.Eoper))
1010         {   if (e.Eoper == OPstreq)
1011             {   if (e.EV.E1.Eoper == OPvar)
1012                 {
1013                     Symbol *s = e.EV.E1.EV.Vsym;
1014                     s.Sflags &= ~(SFLunambig | GTregcand);
1015                 }
1016                 if (e.EV.E2.Eoper == OPvar)
1017                 {
1018                     Symbol *s = e.EV.E2.EV.Vsym;
1019                     s.Sflags &= ~(SFLunambig | GTregcand);
1020                 }
1021             }
1022             out_regcand_walk(e.EV.E1, addressOfParam);
1023             e = e.EV.E2;
1024         }
1025         else if (OTunary(e.Eoper))
1026         {
1027             // Don't put 'this' pointers in registers if we need
1028             // them for EH stack cleanup.
1029             if (e.Eoper == OPctor)
1030             {   elem *e1 = e.EV.E1;
1031 
1032                 if (e1.Eoper == OPadd)
1033                     e1 = e1.EV.E1;
1034                 if (e1.Eoper == OPvar)
1035                     e1.EV.Vsym.Sflags &= ~GTregcand;
1036             }
1037             e = e.EV.E1;
1038         }
1039         else
1040         {   if (e.Eoper == OPrelconst)
1041             {
1042                 Symbol *s = e.EV.Vsym;
1043                 assert(s);
1044                 symbol_debug(s);
1045                 switch (s.Sclass)
1046                 {
1047                     case SCregpar:
1048                     case SCparameter:
1049                     case SCshadowreg:
1050                         if (I16)
1051                             addressOfParam = true;       // taking addr of param list
1052                         else
1053                             s.Sflags &= ~(SFLunambig | GTregcand);
1054                         break;
1055 
1056                     case SCauto:
1057                     case SCregister:
1058                     case SCfastpar:
1059                     case SCbprel:
1060                         s.Sflags &= ~(SFLunambig | GTregcand);
1061                         break;
1062 
1063                     default:
1064                         break;
1065                 }
1066             }
1067             else if (e.Eoper == OPvar)
1068             {
1069                 if (e.EV.Voffset)
1070                 {   if (!(e.EV.Voffset == 1 && tybyte(e.Ety)) &&
1071                         !(e.EV.Voffset == REGSIZE && tysize(e.Ety) == REGSIZE))
1072                     {
1073                         e.EV.Vsym.Sflags &= ~GTregcand;
1074                     }
1075                 }
1076             }
1077             break;
1078         }
1079     }
1080 }
1081 
1082 
1083 /**************************
1084  * Optimize function,
1085  * generate code for it,
1086  * and write it out.
1087  */
1088 
1089 void writefunc(Symbol *sfunc)
1090 {
1091 version (HTOD)
1092 {
1093     return;
1094 }
1095 else version (SCPP)
1096 {
1097     writefunc2(sfunc);
1098 }
1099 else
1100 {
1101     cstate.CSpsymtab = &globsym;
1102     writefunc2(sfunc);
1103     cstate.CSpsymtab = null;
1104 }
1105 }
1106 
1107 private void writefunc2(Symbol *sfunc)
1108 {
1109     func_t *f = sfunc.Sfunc;
1110 
1111     //printf("writefunc(%s)\n",sfunc.Sident.ptr);
1112     debug debugy && printf("writefunc(%s)\n",sfunc.Sident.ptr);
1113 version (SCPP)
1114 {
1115     if (CPP)
1116     {
1117 
1118     // If constructor or destructor, make sure it has been fixed.
1119     if (f.Fflags & (Fctor | Fdtor))
1120         assert(errcnt || f.Fflags & Ffixed);
1121 
1122     // If this function is the 'trigger' to output the vtbl[], do so
1123     if (f.Fflags3 & Fvtblgen && !eecontext.EEcompile)
1124     {
1125         Classsym *stag = cast(Classsym *) sfunc.Sscope;
1126         {
1127             SC scvtbl;
1128 
1129             scvtbl = cast(SC) ((config.flags2 & CFG2comdat) ? SCcomdat : SCglobal);
1130             n2_genvtbl(stag,scvtbl,1);
1131             n2_genvbtbl(stag,scvtbl,1);
1132 static if (SYMDEB_CODEVIEW)
1133 {
1134             if (config.fulltypes == CV4)
1135                 cv4_struct(stag,2);
1136 }
1137         }
1138     }
1139     }
1140 }
1141 
1142     /* Signify that function has been output                    */
1143     /* (before inline_do() to prevent infinite recursion!)      */
1144     f.Fflags &= ~Fpending;
1145     f.Fflags |= Foutput;
1146 
1147 version (SCPP)
1148 {
1149     if (errcnt)
1150         return;
1151 }
1152 
1153     if (eecontext.EEcompile && eecontext.EEfunc != sfunc)
1154         return;
1155 
1156     /* Copy local symbol table onto main one, making sure       */
1157     /* that the symbol numbers are adjusted accordingly */
1158     //printf("f.Flocsym.top = %d\n",f.Flocsym.top);
1159     uint nsymbols = f.Flocsym.top;
1160     if (nsymbols > globsym.symmax)
1161     {   /* Reallocate globsym.tab[]     */
1162         globsym.symmax = nsymbols;
1163         globsym.tab = symtab_realloc(globsym.tab, globsym.symmax);
1164     }
1165     debug debugy && printf("appending symbols to symtab...\n");
1166     assert(globsym.top == 0);
1167     memcpy(&globsym.tab[0],&f.Flocsym.tab[0],nsymbols * (Symbol *).sizeof);
1168     globsym.top = nsymbols;
1169 
1170     assert(startblock == null);
1171     if (f.Fflags & Finline)            // if keep function around
1172     {   // Generate copy of function
1173 
1174         block **pb = &startblock;
1175         for (block *bf = f.Fstartblock; bf; bf = bf.Bnext)
1176         {
1177             block *b = block_calloc();
1178             *pb = b;
1179             pb = &b.Bnext;
1180 
1181             *b = *bf;
1182             assert(b.numSucc() == 0);
1183             assert(!b.Bpred);
1184             b.Belem = el_copytree(b.Belem);
1185         }
1186     }
1187     else
1188     {   startblock = sfunc.Sfunc.Fstartblock;
1189         sfunc.Sfunc.Fstartblock = null;
1190     }
1191     assert(startblock);
1192 
1193     /* Do any in-line expansion of function calls inside sfunc  */
1194 version (SCPP)
1195 {
1196     inline_do(sfunc);
1197 }
1198 
1199 version (SCPP)
1200 {
1201     /* If function is _STIxxxx, add in the auto destructors             */
1202     if (cpp_stidtors && memcmp("__SI".ptr,sfunc.Sident.ptr,4) == 0)
1203     {
1204         assert(startblock.Bnext == null);
1205         list_t el = cpp_stidtors;
1206         do
1207         {
1208             startblock.Belem = el_combine(startblock.Belem,list_elem(el));
1209             el = list_next(el);
1210         } while (el);
1211         list_free(&cpp_stidtors,FPNULL);
1212     }
1213 }
1214     assert(funcsym_p == null);
1215     funcsym_p = sfunc;
1216     tym_t tyf = tybasic(sfunc.ty());
1217 
1218 version (SCPP)
1219 {
1220     out_extdef(sfunc);
1221 }
1222 
1223     // TX86 computes parameter offsets in stackoffsets()
1224     //printf("globsym.top = %d\n", globsym.top);
1225 
1226 version (SCPP)
1227 {
1228     FuncParamRegs fpr = FuncParamRegs_create(tyf);
1229 }
1230 
1231     for (SYMIDX si = 0; si < globsym.top; si++)
1232     {   Symbol *s = globsym.tab[si];
1233 
1234         symbol_debug(s);
1235         //printf("symbol %d '%s'\n",si,s.Sident.ptr);
1236 
1237         type_size(s.Stype);    // do any forward template instantiations
1238 
1239         s.Ssymnum = si;        // Ssymnum trashed by cpp_inlineexpand
1240         s.Sflags &= ~(SFLunambig | GTregcand);
1241         switch (s.Sclass)
1242         {
1243             case SCbprel:
1244                 s.Sfl = FLbprel;
1245                 goto L3;
1246 
1247             case SCauto:
1248             case SCregister:
1249                 s.Sfl = FLauto;
1250                 goto L3;
1251 
1252 version (SCPP)
1253 {
1254             case SCfastpar:
1255             case SCregpar:
1256             case SCparameter:
1257                 if (si == 0 && FuncParamRegs_alloc(fpr, s.Stype, s.Stype.Tty, &s.Spreg, &s.Spreg2))
1258                 {
1259                     assert(s.Spreg == ((tyf == TYmfunc) ? CX : AX));
1260                     assert(s.Spreg2 == NOREG);
1261                     assert(si == 0);
1262                     s.Sclass = SCfastpar;
1263                     s.Sfl = FLfast;
1264                     goto L3;
1265                 }
1266                 assert(s.Sclass != SCfastpar);
1267 }
1268 else
1269 {
1270             case SCfastpar:
1271                 s.Sfl = FLfast;
1272                 goto L3;
1273 
1274             case SCregpar:
1275             case SCparameter:
1276             case SCshadowreg:
1277 }
1278                 s.Sfl = FLpara;
1279                 if (tyf == TYifunc)
1280                 {   s.Sflags |= SFLlivexit;
1281                     break;
1282                 }
1283             L3:
1284                 if (!(s.ty() & (mTYvolatile | mTYshared)))
1285                     s.Sflags |= GTregcand | SFLunambig; // assume register candidate   */
1286                 break;
1287 
1288             case SCpseudo:
1289                 s.Sfl = FLpseudo;
1290                 break;
1291 
1292             case SCstatic:
1293                 break;                  // already taken care of by datadef()
1294 
1295             case SCstack:
1296                 s.Sfl = FLstack;
1297                 break;
1298 
1299             default:
1300                 symbol_print(s);
1301                 assert(0);
1302         }
1303     }
1304 
1305     bool addressOfParam = false;  // see if any parameters get their address taken
1306     bool anyasm = false;
1307     numblks = 0;
1308     for (block *b = startblock; b; b = b.Bnext)
1309     {
1310         numblks++;                              // redo count
1311         memset(&b._BLU,0,block.sizeof - block._BLU.offsetof);
1312         if (b.Belem)
1313         {   outelem(b.Belem, addressOfParam);
1314 version (SCPP)
1315 {
1316             if (!el_returns(b.Belem) && !(config.flags3 & CFG3eh))
1317             {   b.BC = BCexit;
1318                 list_free(&b.Bsucc,FPNULL);
1319             }
1320 }
1321 version (MARS)
1322 {
1323             if (b.Belem.Eoper == OPhalt)
1324             {   b.BC = BCexit;
1325                 list_free(&b.Bsucc,FPNULL);
1326             }
1327 }
1328         }
1329         if (b.BC == BCasm)
1330             anyasm = true;
1331         if (sfunc.Sflags & SFLexit && (b.BC == BCret || b.BC == BCretexp))
1332         {   b.BC = BCexit;
1333             list_free(&b.Bsucc,FPNULL);
1334         }
1335         assert(b != b.Bnext);
1336     }
1337     PARSER = 0;
1338     if (eecontext.EEelem)
1339     {   uint marksi = globsym.top;
1340 
1341         eecontext.EEin++;
1342         outelem(eecontext.EEelem, addressOfParam);
1343         eecontext.EEelem = doptelem(eecontext.EEelem,true);
1344         eecontext.EEin--;
1345         eecontext_convs(marksi);
1346     }
1347     maxblks = 3 * numblks;              // allow for increase in # of blocks
1348     // If we took the address of one parameter, assume we took the
1349     // address of all non-register parameters.
1350     if (addressOfParam | anyasm)        // if took address of a parameter
1351     {
1352         for (SYMIDX si = 0; si < globsym.top; si++)
1353             if (anyasm || globsym.tab[si].Sclass == SCparameter)
1354                 globsym.tab[si].Sflags &= ~(SFLunambig | GTregcand);
1355     }
1356 
1357     block_pred();                       // compute predecessors to blocks
1358     block_compbcount();                 // eliminate unreachable blocks
1359     if (go.mfoptim)
1360     {   OPTIMIZER = 1;
1361         optfunc();                      /* optimize function            */
1362         OPTIMIZER = 0;
1363     }
1364     else
1365     {
1366         //printf("blockopt()\n");
1367         blockopt(0);                    /* optimize                     */
1368     }
1369 
1370 version (SCPP)
1371 {
1372     if (CPP)
1373     {
1374         version (DEBUG_XSYMGEN)
1375         {
1376             /* the internal dataview function is allowed to lie about its return value */
1377             enum noret = compile_state != kDataView;
1378         }
1379         else
1380             enum noret = true;
1381 
1382         // Look for any blocks that return nothing.
1383         // Do it after optimization to eliminate any spurious
1384         // messages like the implicit return on { while(1) { ... } }
1385         if (tybasic(funcsym_p.Stype.Tnext.Tty) != TYvoid &&
1386             !(funcsym_p.Sfunc.Fflags & (Fctor | Fdtor | Finvariant))
1387             && noret
1388            )
1389         {
1390             char err = 0;
1391             for (block *b = startblock; b; b = b.Bnext)
1392             {   if (b.BC == BCasm)     // no errors if any asm blocks
1393                     err |= 2;
1394                 else if (b.BC == BCret)
1395                     err |= 1;
1396             }
1397             if (err == 1)
1398                 func_noreturnvalue();
1399         }
1400     }
1401 }
1402     assert(funcsym_p == sfunc);
1403     const int CSEGSAVE_DEFAULT = -10000;        // some unlikely number
1404     int csegsave = CSEGSAVE_DEFAULT;
1405     if (eecontext.EEcompile != 1)
1406     {
1407         if (symbol_iscomdat2(sfunc))
1408         {
1409             csegsave = cseg;
1410             objmod.comdat(sfunc);
1411             cseg = sfunc.Sseg;
1412         }
1413         else
1414             if (config.flags & CFGsegs) // if user set switch for this
1415             {
1416 version (SCPP)
1417 {
1418                 objmod.codeseg(cpp_mangle(funcsym_p),1);
1419 }
1420 else static if (TARGET_WINDOS)
1421 {
1422                 objmod.codeseg(cast(char*)cpp_mangle(funcsym_p),1);
1423 }
1424 else
1425 {
1426                 objmod.codeseg(funcsym_p.Sident.ptr, 1);
1427 }
1428                                         // generate new code segment
1429             }
1430         cod3_align(cseg);               // align start of function
1431 version (HTOD) { } else
1432 {
1433         objmod.func_start(sfunc);
1434 }
1435         searchfixlist(sfunc);           // backpatch any refs to this function
1436     }
1437 
1438     //printf("codgen()\n");
1439 version (SCPP)
1440 {
1441     if (!errcnt)
1442         codgen(sfunc);                  // generate code
1443 }
1444 else
1445 {
1446     codgen(sfunc);                  // generate code
1447 }
1448     //printf("after codgen for %s Coffset %x\n",sfunc.Sident.ptr,Offset(cseg));
1449     blocklist_free(&startblock);
1450 version (SCPP)
1451 {
1452     PARSER = 1;
1453 }
1454 version (HTOD) { } else
1455 {
1456     objmod.func_term(sfunc);
1457 }
1458     if (eecontext.EEcompile == 1)
1459         goto Ldone;
1460     if (sfunc.Sclass == SCglobal)
1461     {
1462         if ((config.objfmt == OBJ_OMF || config.objfmt == OBJ_MSCOFF) && !(config.flags4 & CFG4allcomdat))
1463         {
1464             assert(sfunc.Sseg == cseg);
1465             objmod.pubdef(sfunc.Sseg,sfunc,sfunc.Soffset);       // make a public definition
1466         }
1467 
1468 version (SCPP)
1469 {
1470 version (Win32)
1471 {
1472         // Determine which startup code to reference
1473         if (!CPP || !isclassmember(sfunc))              // if not member function
1474         {   __gshared const(char)*[6] startup =
1475             [   "__acrtused","__acrtused_winc","__acrtused_dll",
1476                 "__acrtused_con","__wacrtused","__wacrtused_con",
1477             ];
1478             int i;
1479 
1480             const(char)* id = sfunc.Sident.ptr;
1481             switch (id[0])
1482             {
1483                 case 'D': if (strcmp(id,"DllMain"))
1484                                 break;
1485                           if (config.exe == EX_WIN32)
1486                           {     i = 2;
1487                                 goto L2;
1488                           }
1489                           break;
1490 
1491                 case 'm': if (strcmp(id,"main"))
1492                                 break;
1493                           if (config.exe == EX_WIN32)
1494                                 i = 3;
1495                           else if (config.wflags & WFwindows)
1496                                 i = 1;
1497                           else
1498                                 i = 0;
1499                           goto L2;
1500 
1501                 case 'w': if (strcmp(id,"wmain") == 0)
1502                           {
1503                                 if (config.exe == EX_WIN32)
1504                                 {   i = 5;
1505                                     goto L2;
1506                                 }
1507                                 break;
1508                           }
1509                           goto case;
1510                 case 'W': if (stricmp(id,"WinMain") == 0)
1511                           {
1512                                 i = 0;
1513                                 goto L2;
1514                           }
1515                           if (stricmp(id,"wWinMain") == 0)
1516                           {
1517                                 if (config.exe == EX_WIN32)
1518                                 {   i = 4;
1519                                     goto L2;
1520                                 }
1521                           }
1522                           break;
1523 
1524                 case 'L':
1525                 case 'l': if (stricmp(id,"LibMain"))
1526                                 break;
1527                           if (config.exe != EX_WIN32 && config.wflags & WFwindows)
1528                           {     i = 2;
1529                                 goto L2;
1530                           }
1531                           break;
1532 
1533                 L2:     objmod.external_def(startup[i]);          // pull in startup code
1534                         break;
1535 
1536                 default:
1537                     break;
1538             }
1539         }
1540 }
1541 }
1542     }
1543     if (config.wflags & WFexpdef &&
1544         sfunc.Sclass != SCstatic &&
1545         sfunc.Sclass != SCsinline &&
1546         !(sfunc.Sclass == SCinline && !(config.flags2 & CFG2comdat)) &&
1547         sfunc.ty() & mTYexport)
1548         objmod.export_symbol(sfunc,cast(uint)Para.offset);      // export function definition
1549 
1550     if (config.fulltypes && config.fulltypes != CV8)
1551         cv_func(sfunc);                 // debug info for function
1552 
1553 version (MARS)
1554 {
1555     /* This is to make uplevel references to SCfastpar variables
1556      * from nested functions work.
1557      */
1558     for (SYMIDX si = 0; si < globsym.top; si++)
1559     {
1560         Symbol *s = globsym.tab[si];
1561 
1562         switch (s.Sclass)
1563         {   case SCfastpar:
1564                 s.Sclass = SCauto;
1565                 break;
1566 
1567             default:
1568                 break;
1569         }
1570     }
1571     /* After codgen() and writing debug info for the locals,
1572      * readjust the offsets of all stack variables so they
1573      * are relative to the frame pointer.
1574      * Necessary for nested function access to lexically enclosing frames.
1575      */
1576      cod3_adjSymOffsets();
1577 }
1578 
1579     if (symbol_iscomdat2(sfunc))         // if generated a COMDAT
1580     {
1581         assert(csegsave != CSEGSAVE_DEFAULT);
1582         objmod.setcodeseg(csegsave);       // reset to real code seg
1583         if (config.objfmt == OBJ_MACH)
1584             assert(cseg == CODE);
1585     }
1586 
1587     /* Check if function is a constructor or destructor, by     */
1588     /* seeing if the function name starts with _STI or _STD     */
1589     {
1590 version (LittleEndian)
1591 {
1592         short *p = cast(short *) sfunc.Sident.ptr;
1593         if (p[0] == (('S' << 8) | '_') && (p[1] == (('I' << 8) | 'T') || p[1] == (('D' << 8) | 'T')))
1594             objmod.setModuleCtorDtor(sfunc, sfunc.Sident.ptr[3] == 'I');
1595 }
1596 else
1597 {
1598         char *p = sfunc.Sident.ptr;
1599         if (p[0] == '_' && p[1] == 'S' && p[2] == 'T' &&
1600             (p[3] == 'I' || p[3] == 'D'))
1601             objmod.setModuleCtorDtor(sfunc, sfunc.Sident.ptr[3] == 'I');
1602 }
1603     }
1604 
1605 Ldone:
1606     funcsym_p = null;
1607 
1608 version (SCPP)
1609 {
1610     // Free any added symbols
1611     freesymtab(globsym.tab,nsymbols,globsym.top);
1612 }
1613     globsym.top = 0;
1614 
1615     //printf("done with writefunc()\n");
1616     //dfo.dtor();       // save allocation for next time
1617 }
1618 
1619 /*************************
1620  * Align segment offset.
1621  * Input:
1622  *      seg             segment to be aligned
1623  *      datasize        size in bytes of object to be aligned
1624  */
1625 
1626 void alignOffset(int seg,targ_size_t datasize)
1627 {
1628     targ_size_t alignbytes = _align(datasize,Offset(seg)) - Offset(seg);
1629     //printf("seg %d datasize = x%x, Offset(seg) = x%x, alignbytes = x%x\n",
1630       //seg,datasize,Offset(seg),alignbytes);
1631     if (alignbytes)
1632         objmod.lidata(seg,Offset(seg),alignbytes);
1633 }
1634 
1635 /***************************************
1636  * Write data into read-only data segment.
1637  * Return symbol for it.
1638  */
1639 
1640 enum ROMAX = 32;
1641 struct Readonly
1642 {
1643     Symbol *sym;
1644     size_t length;
1645     ubyte[ROMAX] p;
1646 }
1647 
1648 enum RMAX = 16;
1649 private __gshared
1650 {
1651     Readonly[RMAX] readonly;
1652     size_t readonly_length;
1653     size_t readonly_i;
1654 }
1655 
1656 void out_reset()
1657 {
1658     readonly_length = 0;
1659     readonly_i = 0;
1660 }
1661 
1662 Symbol *out_readonly_sym(tym_t ty, void *p, int len)
1663 {
1664 version (HTOD)
1665 {
1666     return null;
1667 }
1668 else
1669 {
1670 static if (0)
1671 {
1672     printf("out_readonly_sym(ty = x%x)\n", ty);
1673     for (int i = 0; i < len; i++)
1674         printf(" [%d] = %02x\n", i, (cast(ubyte*)p)[i]);
1675 }
1676     // Look for previous symbol we can reuse
1677     for (int i = 0; i < readonly_length; i++)
1678     {
1679         Readonly *r = &readonly[i];
1680         if (r.length == len && memcmp(p, r.p.ptr, len) == 0)
1681             return r.sym;
1682     }
1683 
1684     Symbol *s;
1685 
1686 version (MARS)
1687 {
1688     bool cdata = config.objfmt == OBJ_ELF ||
1689                  config.objfmt == OBJ_OMF ||
1690                  config.objfmt == OBJ_MSCOFF;
1691 }
1692 else
1693 {
1694     bool cdata = config.objfmt == OBJ_ELF;
1695 }
1696     if (cdata)
1697     {
1698         /* MACHOBJ can't go here, because the const data segment goes into
1699          * the _TEXT segment, and one cannot have a fixup from _TEXT to _TEXT.
1700          */
1701         s = objmod.sym_cdata(ty, cast(char *)p, len);
1702     }
1703     else
1704     {
1705         uint sz = tysize(ty);
1706 
1707         alignOffset(DATA, sz);
1708         s = symboldata(Offset(DATA),ty | mTYconst);
1709         s.Sseg = DATA;
1710         objmod.write_bytes(SegData[DATA], len, p);
1711         //printf("s.Sseg = %d:x%x\n", s.Sseg, s.Soffset);
1712     }
1713 
1714     if (len <= ROMAX)
1715     {   Readonly *r;
1716 
1717         if (readonly_length < RMAX)
1718         {
1719             r = &readonly[readonly_length];
1720             readonly_length++;
1721         }
1722         else
1723         {   r = &readonly[readonly_i];
1724             readonly_i++;
1725             if (readonly_i >= RMAX)
1726                 readonly_i = 0;
1727         }
1728         r.length = len;
1729         r.sym = s;
1730         memcpy(r.p.ptr, p, len);
1731     }
1732     return s;
1733 }
1734 }
1735 
1736 /*************************************
1737  * Output Symbol as a readonly comdat.
1738  * Params:
1739  *      s = comdat symbol
1740  *      p = pointer to the data to write
1741  *      len = length of that data
1742  *      nzeros = number of trailing zeros to append
1743  */
1744 void out_readonly_comdat(Symbol *s, const(void)* p, uint len, uint nzeros)
1745 {
1746     objmod.readonly_comdat(s);         // create comdat segment
1747     objmod.write_bytes(SegData[s.Sseg], len, cast(void *)p);
1748     objmod.lidata(s.Sseg, len, nzeros);
1749 }
1750 
1751 void Srcpos_print(ref const Srcpos srcpos, const(char)* func)
1752 {
1753     printf("%s(", func);
1754 version (MARS)
1755 {
1756     printf("Sfilename = %s", srcpos.Sfilename ? srcpos.Sfilename : "null".ptr);
1757 }
1758 else
1759 {
1760     const sf = srcpos.Sfilptr ? *srcpos.Sfilptr : null;
1761     printf("Sfilptr = %p (filename = %s)", sf, sf ? sf.SFname : "null".ptr);
1762 }
1763     printf(", Slinnum = %u", srcpos.Slinnum);
1764     printf(")\n");
1765 }
1766 
1767 
1768 }