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 }