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