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