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