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