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