1 /** 2 * Generate the object file for function declarations and critical sections. 3 * 4 * generateCodeAndWrite() is the only function seen by the front end. 5 * 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/glue.d, _glue.d) 10 * Documentation: $(LINK https://dlang.org/phobos/dmd_glue.html) 11 * Coverage: $(LINK https://codecov.io/gh/dlang/dmd/src/master/src/dmd/glue.d) 12 */ 13 14 module dmd.glue; 15 16 import core.stdc.stdio; 17 import core.stdc.string; 18 import core.stdc.stdlib; 19 20 import dmd.root.array; 21 import dmd.root.file; 22 import dmd.root.filename; 23 import dmd.common.outbuffer; 24 import dmd.root.rmem; 25 import dmd.root.string; 26 27 import dmd.backend.cdef; 28 import dmd.backend.cc; 29 import dmd.backend.code; 30 import dmd.backend.dt; 31 import dmd.backend.el; 32 import dmd.backend.global; 33 import dmd.backend.obj; 34 import dmd.backend.oper; 35 import dmd.backend.rtlsym; 36 import dmd.backend.symtab; 37 import dmd.backend.ty; 38 import dmd.backend.type; 39 40 import dmd.aggregate; 41 import dmd.arraytypes; 42 import dmd.astenums; 43 import dmd.blockexit; 44 import dmd.dclass; 45 import dmd.declaration; 46 import dmd.dmangle; 47 import dmd.dmdparams; 48 import dmd.dmodule; 49 import dmd.dmsc; 50 import dmd.dstruct; 51 import dmd.dsymbol; 52 import dmd.dtemplate; 53 import dmd.e2ir; 54 import dmd.errors; 55 import dmd.expression; 56 import dmd.func; 57 import dmd.globals; 58 import dmd.identifier; 59 import dmd.id; 60 import dmd.lib; 61 import dmd.location; 62 import dmd.mtype; 63 import dmd.objc_glue; 64 import dmd.s2ir; 65 import dmd.statement; 66 import dmd.target; 67 import dmd.tocsym; 68 import dmd.toctype; 69 import dmd.toir; 70 import dmd.toobj; 71 import dmd.typesem; 72 import dmd.utils; 73 74 private: 75 76 alias symbols = Array!(Symbol*); 77 78 public alias toSymbol = dmd.tocsym.toSymbol; 79 80 /** 81 * Generate code for `modules` and write objects/libraries 82 * 83 * Params: 84 * modules = array of `Module`s to generate code for 85 * libmodules = array of objects/libraries already generated (passed on command line) 86 * libname = {.lib,.a} file output name 87 * objdir = directory to write object files to 88 * writeLibrary = write library file instead of object file(s) 89 * obj = generate object files 90 * oneobj = write one object file instead of multiple ones 91 * multiobj = break one object file into multiple ones 92 * verbose = print progress message when generatig code 93 */ 94 public void generateCodeAndWrite(Module[] modules, const(char)*[] libmodules, 95 const(char)[] libname, const(char)[] objdir, 96 bool writeLibrary, bool obj, bool oneobj, bool multiobj, 97 bool verbose) 98 { 99 auto eSink = global.errorSink; 100 101 Library library = null; 102 if (writeLibrary) 103 { 104 library = Library.factory(target.objectFormat(), target.lib_ext, eSink); 105 106 /* Determine actual file name of library to write to by combining 107 * objdir, libname, the first object file name, and lib_ext 108 */ 109 const(char)[] arg; 110 if (!libname.length) 111 { 112 // get name of the first object file 113 const(char)[] n = global.params.objfiles[0].toDString; 114 n = FileName.name(n); // remove its path 115 arg = FileName.forceExt(n, library.lib_ext); // force library name extension 116 } 117 else 118 arg = FileName.defaultExt(libname, library.lib_ext); 119 if (!FileName.absolute(arg)) 120 arg = FileName.combine(objdir, arg); 121 122 library.setFilename(arg); 123 124 // Add input object and input library files to output library 125 foreach (p; libmodules) 126 library.addObject(p.toDString(), null); 127 } 128 129 if (!obj) 130 { 131 } 132 else if (oneobj) 133 { 134 OutBuffer objbuf; 135 Module firstm; // first module we generate code for 136 foreach (m; modules) 137 { 138 if (m.filetype == FileType.dhdr) 139 continue; 140 if (!firstm) 141 { 142 firstm = m; 143 obj_start(objbuf, m.srcfile.toChars()); 144 } 145 if (verbose) 146 message("code %s", m.toChars()); 147 genObjFile(m, false); 148 } 149 if (!global.errors && firstm) 150 { 151 obj_end(objbuf, library, firstm.objfile.toChars()); 152 } 153 } 154 else 155 { 156 OutBuffer objbuf; 157 foreach (m; modules) 158 { 159 if (m.filetype == FileType.dhdr) 160 continue; 161 if (verbose) 162 message("code %s", m.toChars()); 163 obj_start(objbuf, m.srcfile.toChars()); 164 genObjFile(m, multiobj); 165 obj_end(objbuf, library, m.objfile.toChars()); 166 obj_write_deferred(objbuf, library, glue.obj_symbols_towrite); 167 if (global.errors && !writeLibrary) 168 m.deleteObjFile(); 169 } 170 } 171 if (writeLibrary && !global.errors) 172 { 173 if (global.params.v.verbose) 174 eSink.message(Loc.initial, "library %s", library.loc.filename); 175 176 auto filenameString = library.loc.filename.toDString; 177 if (!ensurePathToNameExists(Loc.initial, filenameString)) 178 fatal(); 179 180 /* Write library to temporary file. If that is successful, 181 * then and only then replace the existing file with the temporary file 182 */ 183 auto tmpname = filenameString ~ ".tmp\0"; 184 185 auto libbuf = OutBuffer(tmpname.ptr); 186 library.writeLibToBuffer(libbuf); 187 188 if (!libbuf.moveToFile(library.loc.filename)) 189 { 190 eSink.error(library.loc, "error writing file '%s'", library.loc.filename); 191 destroy(tmpname); 192 fatal(); 193 } 194 destroy(tmpname); 195 } 196 } 197 198 extern (C++): 199 200 //extern 201 public __gshared Symbol* bzeroSymbol; /// common location for immutable zeros 202 203 struct Glue 204 { 205 elem *eictor; 206 Symbol *ictorlocalgot; 207 208 symbols sctors; 209 StaticDtorDeclarations ectorgates; 210 symbols sdtors; 211 symbols stests; 212 213 symbols ssharedctors; 214 SharedStaticDtorDeclarations esharedctorgates; 215 symbols sshareddtors; 216 217 const(char)* lastmname; 218 Dsymbols obj_symbols_towrite; 219 } 220 221 private __gshared Glue glue; 222 223 224 /************************************** 225 * Append s to list of object files to generate later. 226 * Only happens with multiobj. 227 */ 228 public void obj_append(Dsymbol s) 229 { 230 //printf("deferred: %s\n", s.toChars()); 231 glue.obj_symbols_towrite.push(s); 232 } 233 234 /******************************* 235 * Generating multiple object files, one per Dsymbol 236 * in symbols_towrite[]. 237 * Params: 238 * library = library to write object files to 239 * symbols_towrite = array of Dsymbols 240 */ 241 extern (D) 242 private void obj_write_deferred(ref OutBuffer objbuf, Library library, ref Dsymbols symbols_towrite) 243 { 244 // this array can grow during the loop; do not replace with foreach 245 for (size_t i = 0; i < symbols_towrite.length; ++i) 246 { 247 Dsymbol s = symbols_towrite[i]; 248 Module m = s.getModule(); 249 250 const(char)* mname; 251 if (m) 252 { 253 mname = m.srcfile.toChars(); 254 glue.lastmname = mname; 255 } 256 else 257 { 258 //mname = s.ident.toChars(); 259 mname = glue.lastmname; 260 assert(mname); 261 } 262 263 obj_start(objbuf, mname); 264 265 __gshared int count; 266 count++; // sequence for generating names 267 268 /* Create a module that's a doppelganger of m, with just 269 * enough to be able to create the moduleinfo. 270 */ 271 OutBuffer idbuf; 272 idbuf.printf("%s.%d", m ? m.ident.toChars() : mname, count); 273 274 if (!m) 275 { 276 // it doesn't make sense to make up a module if we don't know where to put the symbol 277 // so output it into its own object file without ModuleInfo 278 objmod.initfile(idbuf.peekChars(), null, mname); 279 toObjFile(s, false); 280 objmod.termfile(); 281 } 282 else 283 { 284 Identifier id = Identifier.create(idbuf.extractChars()); 285 286 Module md = new Module(mname.toDString, id, 0, 0); 287 md.members = new Dsymbols(); 288 md.members.push(s); // its only 'member' is s 289 md.doppelganger = 1; // identify this module as doppelganger 290 md.md = m.md; 291 md.aimports.push(m); // it only 'imports' m 292 293 genObjFile(md, false); 294 } 295 296 /* Set object file name to be source name with sequence number, 297 * as mangled symbol names get way too long. 298 */ 299 const(char)* fname = FileName.removeExt(mname); 300 OutBuffer namebuf; 301 uint hash = 0; 302 for (const(char)* p = s.toChars(); *p; p++) 303 hash += *p; 304 namebuf.printf("%s_%x_%x.%.*s", fname, count, hash, 305 cast(int)target.obj_ext.length, target.obj_ext.ptr); 306 FileName.free(cast(char *)fname); 307 fname = namebuf.extractChars(); 308 309 //printf("writing '%s'\n", fname); 310 obj_end(objbuf, library, fname); 311 } 312 glue.obj_symbols_towrite.length = 0; 313 } 314 315 316 /*********************************************** 317 * Generate function that calls array of functions and gates. 318 * Params: 319 * m = module symbol (for name mangling purposes) 320 * sctors = array of functions 321 * ectorgates = array of gates 322 * id = identifier string for generator function 323 * Returns: 324 * function Symbol generated 325 */ 326 327 extern (D) 328 private Symbol *callFuncsAndGates(Module m, Symbol*[] sctors, StaticDtorDeclaration[] ectorgates, 329 const(char)* id) 330 { 331 if (!sctors.length && !ectorgates.length) 332 return null; 333 334 Symbol *sctor = null; 335 336 __gshared type *t; 337 if (!t) 338 { 339 /* t will be the type of the functions generated: 340 * extern (C) void func(); 341 */ 342 t = type_function(TYnfunc, null, false, tstypes[TYvoid]); 343 t.Tmangle = mTYman_c; 344 } 345 346 localgot = null; 347 sctor = toSymbolX(m, id, SC.global, t, "FZv"); 348 cstate.CSpsymtab = &sctor.Sfunc.Flocsym; 349 elem *ector = null; 350 351 foreach (f; ectorgates) 352 { 353 Symbol *s = toSymbol(f.vgate); 354 elem *e = el_var(s); 355 e = el_bin(OPaddass, TYint, e, el_long(TYint, 1)); 356 ector = el_combine(ector, e); 357 } 358 359 foreach (s; sctors) 360 { 361 elem *e = el_una(OPucall, TYvoid, el_var(s)); 362 ector = el_combine(ector, e); 363 } 364 365 block *b = block_calloc(); 366 b.BC = BCret; 367 b.Belem = ector; 368 sctor.Sfunc.Fstartline.Sfilename = m.arg.xarraydup.ptr; 369 sctor.Sfunc.Fstartblock = b; 370 writefunc(sctor); // hand off to backend 371 372 return sctor; 373 } 374 375 /************************************** 376 * Prepare for generating obj file. 377 * Params: 378 * objbuf = write object file contents to this 379 * srcfile = name of the source file 380 */ 381 382 private void obj_start(ref OutBuffer objbuf, const(char)* srcfile) 383 { 384 //printf("obj_start()\n"); 385 386 bzeroSymbol = null; 387 rtlsym_reset(); 388 clearStringTab(); 389 390 version (Windows) 391 { 392 import dmd.backend.mscoffobj; 393 import dmd.backend.cgobj; 394 395 // Produce Ms COFF files by default, OMF for -m32omf 396 assert(objbuf.length() == 0); 397 switch (target.objectFormat()) 398 { 399 case Target.ObjectFormat.coff: objmod = MsCoffObj_init(&objbuf, srcfile, null); break; 400 case Target.ObjectFormat.omf: objmod = OmfObj_init(&objbuf, srcfile, null); break; 401 default: assert(0); 402 } 403 } 404 else 405 { 406 objmod = Obj.initialize(&objbuf, srcfile, null); 407 } 408 409 OutBuffer buf; 410 buf.write("DMD "); 411 buf.write(global.versionString()); 412 Obj.compiler(buf.peekChars()); 413 414 el_reset(); 415 cg87_reset(); 416 out_reset(); 417 objc.reset(); 418 } 419 420 421 /**************************************** 422 * Finish creating the object module and writing it to objbuf[]. 423 * Then either write the object module to an actual file, 424 * or add it to a library. 425 * Params: 426 * objbuf = contains the generated contents of the object file 427 * objfilename = what to call the object module 428 * library = if non-null, add object module to this library 429 */ 430 private void obj_end(ref OutBuffer objbuf, Library library, const(char)* objfilename) 431 { 432 objmod.term(objfilename); 433 //delete objmod; 434 objmod = null; 435 436 if (library) 437 { 438 // Transfer ownership of image buffer to library 439 library.addObject(objfilename.toDString(), cast(ubyte[]) objbuf.extractSlice[]); 440 } 441 else 442 { 443 //printf("write obj %s\n", objfilename); 444 if (!writeFile(Loc.initial, objfilename.toDString, objbuf[])) 445 return fatal(); 446 447 // For non-libraries, the object buffer should be cleared to 448 // avoid repetitions. 449 objbuf.destroy(); 450 } 451 } 452 453 public extern (D) bool obj_includelib(scope const char[] name) nothrow 454 { 455 return objmod.includelib(name); 456 } 457 458 public void obj_startaddress(Symbol *s) 459 { 460 return objmod.startaddress(s); 461 } 462 463 public bool obj_linkerdirective(const(char)* directive) 464 { 465 return objmod.linkerdirective(directive); 466 } 467 468 469 /************************************** 470 * Generate .obj file for Module. 471 */ 472 473 private void genObjFile(Module m, bool multiobj) 474 { 475 //EEcontext *ee = env.getEEcontext(); 476 477 //printf("Module.genobjfile(multiobj = %d) %s\n", multiobj, m.toChars()); 478 479 glue.lastmname = m.srcfile.toChars(); 480 481 objmod.initfile(glue.lastmname, null, m.toPrettyChars()); 482 483 glue.eictor = null; 484 glue.ictorlocalgot = null; 485 glue.sctors.setDim(0); 486 glue.ectorgates.setDim(0); 487 glue.sdtors.setDim(0); 488 glue.ssharedctors.setDim(0); 489 glue.esharedctorgates.setDim(0); 490 glue.sshareddtors.setDim(0); 491 glue.stests.setDim(0); 492 493 if (m.doppelganger) 494 { 495 /* Generate a reference to the moduleinfo, so the module constructors 496 * and destructors get linked in. 497 */ 498 Module mod = m.aimports[0]; 499 assert(mod); 500 if (mod.sictor || mod.sctor || mod.sdtor || mod.ssharedctor || mod.sshareddtor) 501 { 502 Symbol *s = toSymbol(mod); 503 //objextern(s); 504 //if (!s.Sxtrnnum) objextdef(s.Sident); 505 if (!s.Sxtrnnum) 506 { 507 //printf("%s\n", s.Sident); 508 //#if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ 509 // objextdef(s.Sident); 510 //#else 511 Symbol *sref = symbol_generate(SC.static_, type_fake(TYnptr)); 512 sref.Sfl = FLdata; 513 auto dtb = DtBuilder(0); 514 dtb.xoff(s, 0, TYnptr); 515 sref.Sdt = dtb.finish(); 516 outdata(sref); 517 //#endif 518 } 519 } 520 } 521 522 if (global.params.cov) 523 { 524 /* Create coverage identifier: 525 * uint[numlines] __coverage; 526 */ 527 m.cov = toSymbolX(m, "__coverage", SC.static_, type_fake(TYint), "Z"); 528 m.cov.Sflags |= SFLhidden; 529 m.cov.Stype.Tmangle = mTYman_d; 530 m.cov.Sfl = FLdata; 531 532 auto dtb = DtBuilder(0); 533 534 if (m.ctfe_cov) 535 { 536 // initalize the uint[] __coverage symbol with data from ctfe. 537 static extern (C) int comp_uints (const scope void* a, const scope void* b) 538 { return (*cast(uint*) a) - (*cast(uint*) b); } 539 540 uint[] sorted_lines = m.ctfe_cov.keys; 541 qsort(sorted_lines.ptr, sorted_lines.length, sorted_lines[0].sizeof, 542 &comp_uints); 543 544 uint lastLine = 0; 545 foreach (line;sorted_lines) 546 { 547 // zero fill from last line to line. 548 if (line) 549 { 550 assert(line > lastLine); 551 dtb.nzeros((line - lastLine - 1) * 4); 552 } 553 dtb.dword(m.ctfe_cov[line]); 554 lastLine = line; 555 } 556 // zero fill from last line to end 557 if (m.numlines > lastLine) 558 dtb.nzeros((m.numlines - lastLine) * 4); 559 } 560 else 561 { 562 dtb.nzeros(4 * m.numlines); 563 } 564 m.cov.Sdt = dtb.finish(); 565 566 outdata(m.cov); 567 568 size_t sz = m.covb[0].sizeof; 569 size_t n = (m.numlines + sz * 8) / (sz * 8); 570 uint* p = cast(uint*)Mem.check(calloc(n, sz)); 571 m.covb = p[0 .. n]; 572 } 573 574 for (int i = 0; i < m.members.length; i++) 575 { 576 auto member = (*m.members)[i]; 577 //printf("toObjFile %s %s\n", member.kind(), member.toChars()); 578 toObjFile(member, multiobj); 579 } 580 581 if (global.params.cov) 582 { 583 /* Generate 584 * private bit[numlines] __bcoverage; 585 */ 586 Symbol *bcov = symbol_calloc("__bcoverage"); 587 bcov.Stype = type_fake(TYuint); 588 bcov.Stype.Tcount++; 589 bcov.Sclass = SC.static_; 590 bcov.Sfl = FLdata; 591 592 auto dtb = DtBuilder(0); 593 dtb.nbytes(cast(uint)(m.covb.length * m.covb[0].sizeof), cast(char*)m.covb.ptr); 594 bcov.Sdt = dtb.finish(); 595 596 outdata(bcov); 597 598 free(m.covb.ptr); 599 m.covb = null; 600 601 /* Generate: 602 * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); 603 * and prepend it to the static constructor. 604 */ 605 606 /* t will be the type of the functions generated: 607 * extern (C) void func(); 608 */ 609 type *t = type_function(TYnfunc, null, false, tstypes[TYvoid]); 610 t.Tmangle = mTYman_c; 611 612 m.sictor = toSymbolX(m, "__modictor", SC.global, t, "FZv"); 613 cstate.CSpsymtab = &m.sictor.Sfunc.Flocsym; 614 localgot = glue.ictorlocalgot; 615 616 elem *ecov = el_pair(TYdarray, el_long(TYsize_t, m.numlines), el_ptr(m.cov)); 617 elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, m.numlines), el_ptr(bcov)); 618 619 if (target.os == Target.OS.Windows && target.isX86_64) 620 { 621 ecov = addressElem(ecov, Type.tvoid.arrayOf(), false); 622 ebcov = addressElem(ebcov, Type.tvoid.arrayOf(), false); 623 } 624 625 elem *efilename = toEfilename(m); 626 if (target.os == Target.OS.Windows && target.isX86_64) 627 efilename = addressElem(efilename, Type.tstring, true); 628 629 elem *e = el_params( 630 el_long(TYuchar, global.params.covPercent), 631 ecov, 632 ebcov, 633 efilename, 634 null); 635 e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM.DCOVER2)), e); 636 glue.eictor = el_combine(e, glue.eictor); 637 glue.ictorlocalgot = localgot; 638 } 639 640 // If coverage / static constructor / destructor / unittest calls 641 if (glue.eictor || glue.sctors.length || glue.ectorgates.length || glue.sdtors.length || 642 glue.ssharedctors.length || glue.esharedctorgates.length || glue.sshareddtors.length || glue.stests.length) 643 { 644 if (glue.eictor) 645 { 646 localgot = glue.ictorlocalgot; 647 648 block *b = block_calloc(); 649 b.BC = BCret; 650 b.Belem = glue.eictor; 651 m.sictor.Sfunc.Fstartline.Sfilename = m.arg.xarraydup.ptr; 652 m.sictor.Sfunc.Fstartblock = b; 653 writefunc(m.sictor); 654 } 655 656 m.sctor = callFuncsAndGates(m, glue.sctors[], glue.ectorgates[], "__modctor"); 657 m.sdtor = callFuncsAndGates(m, glue.sdtors[], null, "__moddtor"); 658 659 m.ssharedctor = callFuncsAndGates(m, glue.ssharedctors[], cast(StaticDtorDeclaration[])glue.esharedctorgates[], "__modsharedctor"); 660 m.sshareddtor = callFuncsAndGates(m, glue.sshareddtors[], null, "__modshareddtor"); 661 m.stest = callFuncsAndGates(m, glue.stests[], null, "__modtest"); 662 663 if (m.doppelganger) 664 genModuleInfo(m); 665 } 666 667 if (m.doppelganger) 668 { 669 objc.generateModuleInfo(m); 670 objmod.termfile(); 671 return; 672 } 673 674 /* Generate module info for templates and -cov. 675 * Don't generate ModuleInfo if `object.ModuleInfo` is not declared or 676 * explicitly disabled through compiler switches such as `-betterC`. 677 * Don't generate ModuleInfo for C files. 678 */ 679 if (global.params.useModuleInfo && Module.moduleinfo && m.filetype != FileType.c/*|| needModuleInfo()*/) 680 genModuleInfo(m); 681 682 objmod.termfile(); 683 } 684 685 686 687 /* ================================================================== */ 688 689 private UnitTestDeclaration needsDeferredNested(FuncDeclaration fd) 690 { 691 while (fd && fd.isNested()) 692 { 693 FuncDeclaration fdp = fd.toParent2().isFuncDeclaration(); 694 if (!fdp) 695 break; 696 if (UnitTestDeclaration udp = fdp.isUnitTestDeclaration()) 697 return udp.semanticRun < PASS.obj ? udp : null; 698 fd = fdp; 699 } 700 return null; 701 } 702 703 public void FuncDeclaration_toObjFile(FuncDeclaration fd, bool multiobj) 704 { 705 ClassDeclaration cd = fd.parent.isClassDeclaration(); 706 //printf("FuncDeclaration_toObjFile(%p, %s.%s)\n", fd, fd.parent.toChars(), fd.toChars()); 707 //printf("storage_class: %llx\n", fd.storage_class); 708 709 //if (type) printf("type = %s\n", type.toChars()); 710 version (none) 711 { 712 //printf("line = %d\n", getWhere() / LINEINC); 713 EEcontext *ee = env.getEEcontext(); 714 if (ee.EEcompile == 2) 715 { 716 if (ee.EElinnum < (getWhere() / LINEINC) || 717 ee.EElinnum > (endwhere / LINEINC) 718 ) 719 return; // don't compile this function 720 ee.EEfunc = toSymbol(this); 721 } 722 } 723 724 if (fd.semanticRun >= PASS.obj) // if toObjFile() already run 725 return; 726 727 if (fd.type && fd.type.ty == Tfunction && (cast(TypeFunction)fd.type).next is null) 728 return; 729 730 // If errors occurred compiling it, such as https://issues.dlang.org/show_bug.cgi?id=6118 731 if (fd.type && fd.type.ty == Tfunction && (cast(TypeFunction)fd.type).next.ty == Terror) 732 return; 733 734 if (fd.hasSemantic3Errors) 735 return; 736 737 if (global.errors) 738 return; 739 740 if (!fd.fbody) 741 return; 742 743 if (fd.skipCodegen) 744 return; 745 746 UnitTestDeclaration ud = fd.isUnitTestDeclaration(); 747 if (ud && !global.params.useUnitTests) 748 return; 749 750 if (multiobj && !fd.isStaticDtorDeclaration() && !fd.isStaticCtorDeclaration() 751 && !(fd.isCrtCtor || fd.isCrtDtor)) 752 { 753 obj_append(fd); 754 return; 755 } 756 757 if (fd.semanticRun == PASS.semanticdone) 758 { 759 /* What happened is this function failed semantic3() with errors, 760 * but the errors were gagged. 761 * Try to reproduce those errors, and then fail. 762 */ 763 .error(fd.loc, "%s `%s` errors compiling the function", fd.kind, fd.toPrettyChars); 764 return; 765 } 766 assert(fd.semanticRun == PASS.semantic3done); 767 assert(fd.ident != Id.empty); 768 769 for (FuncDeclaration fd2 = fd; fd2; ) 770 { 771 if (fd2.inNonRoot()) 772 return; 773 if (fd2.isNested()) 774 fd2 = fd2.toParent2().isFuncDeclaration(); 775 else 776 break; 777 } 778 779 if (UnitTestDeclaration udp = needsDeferredNested(fd)) 780 { 781 /* Can't do unittest's out of order, they are order dependent in that their 782 * execution is done in lexical order. 783 */ 784 udp.deferredNested.push(fd); 785 //printf("%s @[%s]\n\t-. pushed to unittest @[%s]\n", 786 // fd.toPrettyChars(), fd.loc.toChars(), udp.loc.toChars()); 787 return; 788 } 789 790 Symbol *s = toSymbol(fd); // may set skipCodegen 791 func_t *f = s.Sfunc; 792 if (fd.skipCodegen) // test it again, as toSymbol() might have set it 793 return; 794 795 // start code generation 796 fd.semanticRun = PASS.obj; 797 798 if (global.params.v.verbose) 799 message("function %s", fd.toPrettyChars()); 800 801 // tunnel type of "this" to debug info generation 802 if (AggregateDeclaration ad = fd.parent.isAggregateDeclaration()) 803 { 804 .type* t = Type_toCtype(ad.getType()); 805 if (cd) 806 t = t.Tnext; // skip reference 807 f.Fclass = cast(Classsym *)t; 808 } 809 810 /* This is done so that the 'this' pointer on the stack is the same 811 * distance away from the function parameters, so that an overriding 812 * function can call the nested fdensure or fdrequire of its overridden function 813 * and the stack offsets are the same. 814 */ 815 if (fd.isVirtual() && (fd.fensure || fd.frequire)) 816 f.Fflags3 |= Ffakeeh; 817 818 if (fd.hasNoEH()) 819 // Same as config.ehmethod==EH_NONE, but only for this function 820 f.Fflags3 |= Feh_none; 821 822 s.Sclass = target.os == Target.OS.OSX ? SC.comdat : SC.global; 823 824 /* Make C static functions SCstatic 825 */ 826 if (fd.storage_class & STC.static_ && fd.isCsymbol()) 827 s.Sclass = SC.static_; 828 829 for (Dsymbol p = fd.parent; p; p = p.parent) 830 { 831 if (p.isTemplateInstance()) 832 { 833 // functions without D or C++ name mangling mixed in at global scope 834 // shouldn't have multiple definitions 835 const linkage = fd.resolvedLinkage(); 836 if (p.isTemplateMixin() && (linkage == LINK.c || linkage == LINK.windows || 837 linkage == LINK.objc)) 838 { 839 const q = p.toParent(); 840 if (q && q.isModule()) 841 { 842 s.Sclass = SC.global; 843 break; 844 } 845 } 846 s.Sclass = SC.comdat; 847 break; 848 } 849 } 850 851 if (fd.inlinedNestedCallees) 852 { 853 /* https://issues.dlang.org/show_bug.cgi?id=15333 854 * If fd contains inlined expressions that come from 855 * nested function bodies, the enclosing of the functions must be 856 * generated first, in order to calculate correct frame pointer offset. 857 */ 858 foreach (fdc; *fd.inlinedNestedCallees) 859 { 860 FuncDeclaration fp = fdc.toParent2().isFuncDeclaration(); 861 if (fp && fp.semanticRun < PASS.obj) 862 { 863 toObjFile(fp, multiobj); 864 } 865 } 866 } 867 868 if (fd.isNested()) 869 { 870 //if (!(config.flags3 & CFG3pic)) 871 // s.Sclass = SCstatic; 872 f.Fflags3 |= Fnested; 873 874 /* The enclosing function must have its code generated first, 875 * in order to calculate correct frame pointer offset. 876 */ 877 FuncDeclaration fdp = fd.toParent2().isFuncDeclaration(); 878 if (fdp && fdp.semanticRun < PASS.obj) 879 { 880 toObjFile(fdp, multiobj); 881 } 882 } 883 else 884 { 885 if (entryPointFunctions(objmod, fd)) 886 s.Sclass = SC.global; 887 } 888 889 symtab_t *symtabsave = cstate.CSpsymtab; 890 cstate.CSpsymtab = &f.Flocsym; 891 892 // Find module m for this function 893 Module m = null; 894 for (Dsymbol p = fd.parent; p; p = p.parent) 895 { 896 m = p.isModule(); 897 if (m) 898 break; 899 } 900 901 Dsymbols deferToObj; // write these to OBJ file later 902 Array!(elem*) varsInScope; 903 Label*[void*] labels = null; 904 IRState irs = IRState(m, fd, &varsInScope, &deferToObj, &labels, &global.params, &target, global.errorSink); 905 906 Symbol *shidden = null; 907 Symbol *sthis = null; 908 tym_t tyf = tybasic(s.Stype.Tty); 909 //printf("linkage = %d, tyf = x%x\n", linkage, tyf); 910 int reverse = tyrevfunc(s.Stype.Tty); 911 912 assert(fd.type.ty == Tfunction); 913 TypeFunction tf = cast(TypeFunction)fd.type; 914 RET retmethod = retStyle(tf, fd.needThis()); 915 if (retmethod == RET.stack) 916 { 917 // If function returns a struct, put a pointer to that 918 // as the first argument 919 .type *thidden = Type_toCtype(tf.next.pointerTo()); 920 const hiddenparamLen = 5 + 10 + 1; 921 char[hiddenparamLen] hiddenparam = void; 922 __gshared uint hiddenparami; // how many we've generated so far 923 924 const(char)* name; 925 if (fd.isNRVO() && fd.nrvo_var) 926 name = fd.nrvo_var.ident.toChars(); 927 else 928 { 929 snprintf(hiddenparam.ptr, hiddenparamLen, "__HID%u", ++hiddenparami); 930 name = hiddenparam.ptr; 931 } 932 shidden = symbol_name(name[0 .. strlen(name)], SC.parameter, thidden); 933 shidden.Sflags |= SFLtrue | SFLfree; 934 if (fd.isNRVO() && fd.nrvo_var && fd.nrvo_var.nestedrefs.length) 935 type_setcv(&shidden.Stype, shidden.Stype.Tty | mTYvolatile); 936 irs.shidden = shidden; 937 fd.shidden = shidden; 938 } 939 else 940 { 941 // Register return style cannot make nrvo. 942 // Auto functions keep the NRVO flag up to here, 943 // so we should eliminate it before entering backend. 944 fd.isNRVO = false; 945 } 946 947 if (fd.vthis) 948 { 949 assert(!fd.vthis.csym); 950 sthis = toSymbol(fd.vthis); 951 sthis.Stype = getParentClosureType(sthis, fd); 952 irs.sthis = sthis; 953 if (!(f.Fflags3 & Fnested)) 954 f.Fflags3 |= Fmember; 955 } 956 957 // Estimate number of parameters, pi 958 size_t pi = (fd.v_arguments !is null); 959 if (fd.parameters) 960 pi += fd.parameters.length; 961 if (fd.objc.selector) 962 pi++; // Extra argument for Objective-C selector 963 // Create a temporary buffer, params[], to hold function parameters 964 Symbol*[10] paramsbuf = void; 965 Symbol **params = paramsbuf.ptr; // allocate on stack if possible 966 if (pi + 2 > paramsbuf.length) // allow extra 2 for sthis and shidden 967 { 968 params = cast(Symbol **)Mem.check(malloc((pi + 2) * (Symbol *).sizeof)); 969 } 970 971 // Get the actual number of parameters, pi, and fill in the params[] 972 pi = 0; 973 if (fd.v_arguments) 974 { 975 params[pi] = toSymbol(fd.v_arguments); 976 pi += 1; 977 } 978 Symbol* lastParam; 979 if (fd.parameters) 980 { 981 foreach (i, v; *fd.parameters) 982 { 983 //printf("param[%d] = %p, %s\n", cast(int)i, v, v.toChars()); 984 assert(!v.csym); 985 lastParam = toSymbol(v); 986 params[pi + i] = lastParam; 987 } 988 pi += fd.parameters.length; 989 } 990 991 if (reverse) 992 { 993 // Reverse params[] entries 994 foreach (i, sptmp; params[0 .. pi/2]) 995 { 996 params[i] = params[pi - 1 - i]; 997 params[pi - 1 - i] = sptmp; 998 } 999 } 1000 1001 if (shidden) 1002 { 1003 // shidden becomes last parameter 1004 //params[pi] = shidden; 1005 1006 // shidden becomes first parameter 1007 memmove(params + 1, params, pi * (params[0]).sizeof); 1008 params[0] = shidden; 1009 1010 pi++; 1011 } 1012 1013 pi = objc.addSelectorParameterSymbol(fd, params, pi); 1014 1015 if (sthis) 1016 { 1017 // sthis becomes last parameter 1018 //params[pi] = sthis; 1019 1020 // sthis becomes first parameter 1021 memmove(params + 1, params, pi * (params[0]).sizeof); 1022 params[0] = sthis; 1023 1024 pi++; 1025 } 1026 1027 if (target.isPOSIX && fd._linkage != LINK.d && shidden && sthis) 1028 { 1029 /* swap shidden and sthis 1030 */ 1031 Symbol *sp = params[0]; 1032 params[0] = params[1]; 1033 params[1] = sp; 1034 } 1035 1036 foreach (sp; params[0 .. pi]) 1037 { 1038 sp.Sclass = SC.parameter; 1039 sp.Sflags &= ~SFLspill; 1040 sp.Sfl = FLpara; 1041 symbol_add(sp); 1042 } 1043 1044 // Determine register assignments 1045 if (pi) 1046 { 1047 FuncParamRegs fpr = FuncParamRegs.create(tyf); 1048 1049 foreach (sp; params[0 .. pi]) 1050 { 1051 if (fpr.alloc(sp.Stype, sp.Stype.Tty, &sp.Spreg, &sp.Spreg2)) 1052 { 1053 sp.Sclass = (target.os == Target.OS.Windows && target.isX86_64) ? SC.shadowreg : SC.fastpar; 1054 sp.Sfl = (sp.Sclass == SC.shadowreg) ? FLpara : FLfast; 1055 } 1056 } 1057 } 1058 1059 // Done with params 1060 if (params != paramsbuf.ptr) 1061 free(params); 1062 params = null; 1063 1064 localgot = null; 1065 1066 Statement sbody = fd.fbody; 1067 1068 Blockx bx; 1069 bx.startblock = block_calloc(); 1070 bx.curblock = bx.startblock; 1071 bx.funcsym = s; 1072 bx.scope_index = -1; 1073 bx.classdec = cast(void*)cd; 1074 bx.member = cast(void*)fd; 1075 bx._module = cast(void*)fd.getModule(); 1076 irs.blx = &bx; 1077 1078 // Initialize argptr 1079 if (fd.v_argptr) 1080 { 1081 // Declare va_argsave 1082 if (target.isX86_64 && 1083 target.os & Target.OS.Posix) 1084 { 1085 type *t = type_struct_class("__va_argsave_t", 16, 8 * 6 + 8 * 16 + 8 * 3 + 8, null, null, false, false, true, false); 1086 // The backend will pick this up by name 1087 Symbol *sv = symbol_name("__va_argsave", SC.auto_, t); 1088 sv.Stype.Tty |= mTYvolatile; 1089 symbol_add(sv); 1090 } 1091 1092 // Declare _argptr, but only for D files 1093 if (!irs.Cfile) 1094 { 1095 Symbol *sa = toSymbol(fd.v_argptr); 1096 symbol_add(sa); 1097 elem *e = el_bin(OPva_start, TYnptr, el_ptr(sa), lastParam ? el_ptr(lastParam) : el_long(TYnptr, 0)); 1098 block_appendexp(irs.blx.curblock, e); 1099 } 1100 } 1101 1102 /* Doing this in semantic3() caused all kinds of problems: 1103 * 1. couldn't reliably get the final mangling of the function name due to fwd refs 1104 * 2. impact on function inlining 1105 * 3. what to do when writing out .di files, or other pretty printing 1106 */ 1107 if (global.params.trace && !fd.isCMain() && !fd.isNaked() && !(fd.hasReturnExp & 8)) 1108 { 1109 /* The profiler requires TLS, and TLS may not be set up yet when C main() 1110 * gets control (i.e. OSX), leading to a crash. 1111 */ 1112 /* Wrap the entire function body in: 1113 * trace_pro("funcname"); 1114 * try 1115 * body; 1116 * finally 1117 * _c_trace_epi(); 1118 */ 1119 StringExp se = StringExp.create(Loc.initial, s.Sident.ptr); 1120 se.type = Type.tstring; 1121 se.type = se.type.typeSemantic(Loc.initial, null); 1122 Expressions *exps = new Expressions(); 1123 exps.push(se); 1124 FuncDeclaration fdpro = FuncDeclaration.genCfunc(null, Type.tvoid, "trace_pro"); 1125 Expression ec = VarExp.create(Loc.initial, fdpro); 1126 Expression e = CallExp.create(Loc.initial, ec, exps); 1127 e.type = Type.tvoid; 1128 Statement sp = ExpStatement.create(fd.loc, e); 1129 1130 FuncDeclaration fdepi = FuncDeclaration.genCfunc(null, Type.tvoid, "_c_trace_epi"); 1131 ec = VarExp.create(Loc.initial, fdepi); 1132 e = CallExp.create(Loc.initial, ec); 1133 e.type = Type.tvoid; 1134 Statement sf = ExpStatement.create(fd.loc, e); 1135 1136 Statement stf; 1137 if (sbody.blockExit(fd, null) == BE.fallthru) 1138 stf = CompoundStatement.create(Loc.initial, sbody, sf); 1139 else 1140 stf = TryFinallyStatement.create(Loc.initial, sbody, sf); 1141 sbody = CompoundStatement.create(Loc.initial, sp, stf); 1142 } 1143 1144 if (fd.interfaceVirtual) 1145 { 1146 // Adjust the 'this' pointer instead of using a thunk 1147 assert(irs.sthis); 1148 elem *ethis = el_var(irs.sthis); 1149 ethis = fixEthis2(ethis, fd); 1150 elem *e = el_bin(OPminass, TYnptr, ethis, el_long(TYsize_t, fd.interfaceVirtual.offset)); 1151 block_appendexp(irs.blx.curblock, e); 1152 } 1153 1154 buildClosure(fd, irs); 1155 buildAlignSection(fd, irs); // must be after buildClosure 1156 1157 if (config.ehmethod == EHmethod.EH_WIN32 && fd.isSynchronized() && cd && 1158 !fd.isStatic() && !sbody.usesEH() && !global.params.trace) 1159 { 1160 /* The "jmonitor" hack uses an optimized exception handling frame 1161 * which is a little shorter than the more general EH frame. 1162 */ 1163 s.Sfunc.Fflags3 |= Fjmonitor; 1164 } 1165 1166 Statement_toIR(sbody, irs); 1167 1168 if (global.errors) 1169 { 1170 // Restore symbol table 1171 cstate.CSpsymtab = symtabsave; 1172 return; 1173 } 1174 1175 bx.curblock.BC = BCret; 1176 1177 f.Fstartblock = bx.startblock; 1178 // einit = el_combine(einit,bx.init); 1179 1180 if (fd.isCtorDeclaration()) 1181 { 1182 assert(sthis); 1183 foreach (b; BlockRange(f.Fstartblock)) 1184 { 1185 if (b.BC == BCret) 1186 { 1187 elem *ethis = el_var(sthis); 1188 ethis = fixEthis2(ethis, fd); 1189 b.BC = BCretexp; 1190 b.Belem = el_combine(b.Belem, ethis); 1191 } 1192 } 1193 } 1194 if (config.ehmethod == EHmethod.EH_NONE || f.Fflags3 & Feh_none) 1195 insertFinallyBlockGotos(f.Fstartblock); 1196 else if (config.ehmethod == EHmethod.EH_DWARF) 1197 insertFinallyBlockCalls(f.Fstartblock); 1198 1199 // If static constructor 1200 if (fd.isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration 1201 { 1202 glue.ssharedctors.push(s); 1203 } 1204 else if (fd.isStaticCtorDeclaration()) 1205 { 1206 glue.sctors.push(s); 1207 } 1208 1209 // If static destructor 1210 if (fd.isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration 1211 { 1212 SharedStaticDtorDeclaration fs = fd.isSharedStaticDtorDeclaration(); 1213 assert(fs); 1214 if (fs.vgate) 1215 { 1216 /* Increment destructor's vgate at construction time 1217 */ 1218 glue.esharedctorgates.push(fs); 1219 } 1220 1221 glue.sshareddtors.shift(s); 1222 } 1223 else if (fd.isStaticDtorDeclaration()) 1224 { 1225 StaticDtorDeclaration fs = fd.isStaticDtorDeclaration(); 1226 assert(fs); 1227 if (fs.vgate) 1228 { 1229 /* Increment destructor's vgate at construction time 1230 */ 1231 glue.ectorgates.push(fs); 1232 } 1233 1234 glue.sdtors.shift(s); 1235 } 1236 1237 // If unit test 1238 if (ud) 1239 { 1240 glue.stests.push(s); 1241 } 1242 1243 if (global.errors) 1244 { 1245 // Restore symbol table 1246 cstate.CSpsymtab = symtabsave; 1247 return; 1248 } 1249 1250 writefunc(s); // hand off to backend 1251 1252 buildCapture(fd); 1253 1254 // Restore symbol table 1255 cstate.CSpsymtab = symtabsave; 1256 1257 if (fd.isExport()) 1258 objmod.export_symbol(s, cast(uint)Para.offset); 1259 1260 if (fd.isCrtCtor) 1261 objmod.setModuleCtorDtor(s, true); 1262 1263 if (fd.isCrtDtor) 1264 { 1265 //See TargetC.initialize 1266 if(target.c.crtDestructorsSupported) 1267 { 1268 objmod.setModuleCtorDtor(s, false); 1269 } else 1270 { 1271 /* 1272 https://issues.dlang.org/show_bug.cgi?id=22520 1273 1274 Apple radar: https://openradar.appspot.com/FB9733712 1275 1276 Apple deprecated the mechanism used to implement `crt_destructor` 1277 on MacOS Monterey. This works around that by generating a new function 1278 (crt_destructor_thunk_NNN, run as a constructor) which registers 1279 the destructor-to-be using __cxa_atexit() 1280 1281 This workaround may need a further look at when it comes to 1282 shared library support, however there is no bridge for 1283 that spilt milk to flow under yet. 1284 1285 This relies on the Itanium ABI so is portable to any 1286 platform it, if needed. 1287 */ 1288 __gshared uint nthDestructor = 0; 1289 char* buf = cast(char*) Mem.check(calloc(50, 1)); 1290 const ret = snprintf(buf, 100, "_dmd_crt_destructor_thunk.%u", nthDestructor++); 1291 assert(ret >= 0 && ret < 100, "snprintf either failed or overran buffer"); 1292 //Function symbol 1293 auto newConstructor = symbol_calloc(buf[0 .. strlen(buf)]); 1294 //Build type 1295 newConstructor.Stype = type_function(TYnfunc, [], false, type_alloc(TYvoid)); 1296 //Tell it it's supposed to be a C function. Does it do anything? Not sure. 1297 type_setmangle(&newConstructor.Stype, mTYman_c); 1298 symbol_func(newConstructor); 1299 //Global SC for now. 1300 newConstructor.Sclass = SC.static_; 1301 func_t* funcState = newConstructor.Sfunc; 1302 //Init start block 1303 funcState.Fstartblock = block_calloc(); 1304 block* startBlk = funcState.Fstartblock; 1305 //Make that block run __cxa_atexit(&func); 1306 auto atexitSym = getRtlsym(RTLSYM.CXA_ATEXIT); 1307 Symbol* dso_handle = symbol_calloc("__dso_handle"); 1308 dso_handle.Stype = type_fake(TYint); 1309 //Try to get MacOS _ prefix-ism right. 1310 type_setmangle(&dso_handle.Stype, mTYman_c); 1311 dso_handle.Sfl = FLextern; 1312 dso_handle.Sclass = SC.extern_; 1313 dso_handle.Stype.Tcount++; 1314 auto handlePtr = el_ptr(dso_handle); 1315 //Build parameter pack - __cxa_atexit(&func, null, null) 1316 auto paramPack = el_params(handlePtr, el_long(TYnptr, 0), el_ptr(s), null); 1317 auto exec = el_bin(OPcall, TYvoid, el_var(atexitSym), paramPack); 1318 block_appendexp(startBlk, exec); //payload 1319 startBlk.BC = BCgoto; 1320 auto next = block_calloc(); 1321 startBlk.appendSucc(next); 1322 startBlk.Bnext = next; 1323 next.BC = BCret; 1324 //Emit in binary 1325 writefunc(newConstructor); 1326 //Mark as a CONSTRUCTOR because our thunk implements the destructor 1327 objmod.setModuleCtorDtor(newConstructor, true); 1328 } 1329 } 1330 1331 foreach (sd; *irs.deferToObj) 1332 { 1333 toObjFile(sd, false); 1334 } 1335 1336 if (ud) 1337 { 1338 foreach (fdn; ud.deferredNested) 1339 { 1340 toObjFile(fdn, false); 1341 } 1342 } 1343 1344 if (irs.startaddress) 1345 { 1346 //printf("Setting start address\n"); 1347 objmod.startaddress(irs.startaddress); 1348 } 1349 } 1350 1351 1352 /******************************************* 1353 * Detect entry points like `main()`. 1354 * Entry points trigger special handling like referencing the 1355 * default library, setting up sections, etc. 1356 * 1357 * Params: 1358 * objmod = object module to write hooks to 1359 * fd = function symbol 1360 * Returns: 1361 * true if entry point 1362 */ 1363 private bool entryPointFunctions(Obj objmod, FuncDeclaration fd) 1364 { 1365 // D main() 1366 if (fd.isMain() && onlyOneMain(fd)) 1367 { 1368 /* Reference the C main() to pull it in to the executable 1369 */ 1370 final switch (target.objectFormat()) 1371 { 1372 case Target.ObjectFormat.elf: 1373 case Target.ObjectFormat.macho: 1374 objmod.external_def("_main"); 1375 break; 1376 case Target.ObjectFormat.coff: 1377 objmod.external_def("main"); 1378 break; 1379 case Target.ObjectFormat.omf: 1380 objmod.external_def("_main"); 1381 break; 1382 } 1383 if (const libname = finalDefaultlibname()) 1384 obj_includelib(libname); 1385 return true; 1386 } 1387 1388 // D runtime library 1389 if (fd.isRtInit()) 1390 { 1391 final switch (target.objectFormat()) 1392 { 1393 case Target.ObjectFormat.elf: 1394 case Target.ObjectFormat.macho: 1395 case Target.ObjectFormat.coff: 1396 objmod.ehsections(); // initialize exception handling sections 1397 break; 1398 case Target.ObjectFormat.omf: 1399 break; 1400 } 1401 return true; 1402 } 1403 1404 // C main() 1405 if (fd.isCMain()) 1406 { 1407 switch (target.objectFormat()) 1408 { 1409 case Target.ObjectFormat.coff: 1410 if (driverParams.mscrtlib.length && driverParams.mscrtlib[0]) 1411 obj_includelib(driverParams.mscrtlib); 1412 objmod.includelib("OLDNAMES"); 1413 break; 1414 1415 case Target.ObjectFormat.omf: 1416 objmod.external_def("__acrtused_con"); // bring in C console startup code 1417 objmod.includelib("snn.lib"); // bring in C runtime library 1418 break; 1419 1420 default: 1421 break; 1422 } 1423 return true; 1424 } 1425 1426 // Windows WinMain() or DllMain() 1427 if (target.os == Target.OS.Windows && 1428 (fd.isWinMain() || fd.isDllMain()) && 1429 onlyOneMain(fd)) 1430 { 1431 switch (target.objectFormat()) 1432 { 1433 case Target.ObjectFormat.coff: 1434 objmod.includelib("uuid"); 1435 if (driverParams.mscrtlib.length && driverParams.mscrtlib[0]) 1436 obj_includelib(driverParams.mscrtlib); 1437 objmod.includelib("OLDNAMES"); 1438 break; 1439 1440 case Target.ObjectFormat.omf: 1441 objmod.external_def(fd.isWinMain() ? "__acrtused" : "__acrtused_dll"); 1442 break; 1443 1444 default: 1445 assert(0); 1446 } 1447 1448 if (const libname = finalDefaultlibname()) 1449 obj_includelib(libname); 1450 return true; 1451 } 1452 1453 return false; 1454 } 1455 1456 /**************************************** 1457 * Only one entry point function is allowed. Print error if more than one. 1458 * Params: 1459 * fd = a "main" function 1460 * Returns: 1461 * true if haven't seen "main" before 1462 */ 1463 private bool onlyOneMain(FuncDeclaration fd) 1464 { 1465 __gshared FuncDeclaration lastMain; 1466 if (lastMain) 1467 { 1468 const format = (target.os == Target.OS.Windows) 1469 ? "only one entry point `main`, `WinMain` or `DllMain` is allowed" 1470 : "only one entry point `main` is allowed"; 1471 error(fd.loc, format.ptr); 1472 errorSupplemental(lastMain.loc, "previously found `%s` here", lastMain.toFullSignature()); 1473 return false; 1474 } 1475 lastMain = fd; 1476 return true; 1477 } 1478 1479 /* ================================================================== */ 1480 1481 /***************************** 1482 * Return back end type corresponding to D front end type. 1483 */ 1484 public tym_t totym(Type tx) 1485 { 1486 tym_t t; 1487 switch (tx.ty) 1488 { 1489 case Tvoid: t = TYvoid; break; 1490 case Tint8: t = TYschar; break; 1491 case Tuns8: t = TYuchar; break; 1492 case Tint16: t = TYshort; break; 1493 case Tuns16: t = TYushort; break; 1494 case Tint32: t = TYint; break; 1495 case Tuns32: t = TYuint; break; 1496 case Tint64: t = TYllong; break; 1497 case Tuns64: t = TYullong; break; 1498 case Tfloat32: t = TYfloat; break; 1499 case Tfloat64: t = TYdouble; break; 1500 case Tfloat80: t = TYldouble; break; 1501 case Timaginary32: t = TYifloat; break; 1502 case Timaginary64: t = TYidouble; break; 1503 case Timaginary80: t = TYildouble; break; 1504 case Tcomplex32: t = TYcfloat; break; 1505 case Tcomplex64: t = TYcdouble; break; 1506 case Tcomplex80: t = TYcldouble; break; 1507 case Tbool: t = TYbool; break; 1508 case Tchar: t = TYchar; break; 1509 case Twchar: t = TYwchar_t; break; 1510 case Tdchar: 1511 t = (driverParams.symdebug == 1 || target.os & Target.OS.Posix) ? TYdchar : TYulong; 1512 break; 1513 1514 case Taarray: t = TYaarray; break; 1515 case Tclass: 1516 case Treference: 1517 case Tpointer: t = TYnptr; break; 1518 case Tdelegate: t = TYdelegate; break; 1519 case Tarray: t = TYdarray; break; 1520 case Tsarray: t = TYstruct; break; 1521 case Tnoreturn: t = TYnoreturn; break; 1522 1523 case Tstruct: 1524 t = TYstruct; 1525 break; 1526 1527 case Tenum: 1528 { 1529 Type tb = tx.toBasetype(); 1530 const id = tx.toDsymbol(null).ident; 1531 if (id == Id.__c_long) 1532 t = tb.ty == Tint32 ? TYlong : TYllong; 1533 else if (id == Id.__c_ulong) 1534 t = tb.ty == Tuns32 ? TYulong : TYullong; 1535 else if (id == Id.__c_long_double) 1536 t = tb.size() == 8 ? TYdouble : TYldouble; 1537 else if (id == Id.__c_complex_float) 1538 t = TYcfloat; 1539 else if (id == Id.__c_complex_double) 1540 t = TYcdouble; 1541 else if (id == Id.__c_complex_real) 1542 t = tb.size() == 16 ? TYcdouble : TYcldouble; 1543 else 1544 t = totym(tb); 1545 break; 1546 } 1547 1548 case Tident: 1549 case Ttypeof: 1550 case Tmixin: 1551 //printf("ty = %d, '%s'\n", tx.ty, tx.toChars()); 1552 error(Loc.initial, "forward reference of `%s`", tx.toChars()); 1553 t = TYint; 1554 break; 1555 1556 case Tnull: 1557 t = TYnptr; 1558 break; 1559 1560 case Tvector: 1561 { 1562 auto tv = cast(TypeVector)tx; 1563 const tb = tv.elementType(); 1564 const s32 = tv.alignsize() == 32; // if 32 byte, 256 bit vector 1565 switch (tb.ty) 1566 { 1567 case Tvoid: 1568 case Tint8: t = s32 ? TYschar32 : TYschar16; break; 1569 case Tuns8: t = s32 ? TYuchar32 : TYuchar16; break; 1570 case Tint16: t = s32 ? TYshort16 : TYshort8; break; 1571 case Tuns16: t = s32 ? TYushort16 : TYushort8; break; 1572 case Tint32: t = s32 ? TYlong8 : TYlong4; break; 1573 case Tuns32: t = s32 ? TYulong8 : TYulong4; break; 1574 case Tint64: t = s32 ? TYllong4 : TYllong2; break; 1575 case Tuns64: t = s32 ? TYullong4 : TYullong2; break; 1576 case Tfloat32: t = s32 ? TYfloat8 : TYfloat4; break; 1577 case Tfloat64: t = s32 ? TYdouble4 : TYdouble2; break; 1578 default: 1579 assert(0); 1580 } 1581 break; 1582 } 1583 1584 case Tfunction: 1585 { 1586 auto tf = cast(TypeFunction)tx; 1587 final switch (tf.linkage) 1588 { 1589 case LINK.windows: 1590 if (target.isX86_64) 1591 goto case LINK.c; 1592 t = (tf.parameterList.varargs == VarArg.variadic || 1593 tf.parameterList.varargs == VarArg.KRvariadic) ? TYnfunc : TYnsfunc; 1594 break; 1595 1596 case LINK.c: 1597 case LINK.cpp: 1598 case LINK.objc: 1599 t = TYnfunc; 1600 if (target.os == Target.OS.Windows) 1601 { 1602 } 1603 else if (!target.isX86_64 && retStyle(tf, false) == RET.stack) 1604 t = TYhfunc; 1605 break; 1606 1607 case LINK.d: 1608 t = (tf.parameterList.varargs == VarArg.variadic) ? TYnfunc : TYjfunc; 1609 break; 1610 1611 case LINK.default_: 1612 case LINK.system: 1613 printf("linkage = %d\n", tf.linkage); 1614 assert(0); 1615 } 1616 if (tf.isnothrow) 1617 t |= mTYnothrow; 1618 return t; 1619 } 1620 default: 1621 //printf("ty = %d, '%s'\n", tx.ty, tx.toChars()); 1622 assert(0); 1623 } 1624 1625 t |= modToTym(tx.mod); // Add modifiers 1626 1627 return t; 1628 } 1629 1630 /******************************************* 1631 * Generate readonly symbol that consists of a bunch of zeros. 1632 * Immutable Symbol instances can be mapped over it. 1633 * Only one is generated per object file. 1634 * Returns: 1635 * bzero symbol 1636 */ 1637 public Symbol* getBzeroSymbol() 1638 { 1639 Symbol* s = bzeroSymbol; 1640 if (s) 1641 return s; 1642 1643 s = symbol_calloc("__bzeroBytes"); 1644 s.Stype = type_static_array(128, type_fake(TYuchar)); 1645 s.Stype.Tmangle = mTYman_c; 1646 s.Stype.Tcount++; 1647 s.Sclass = SC.global; 1648 s.Sfl = FLdata; 1649 s.Sflags |= SFLnodebug; 1650 s.Salignment = 16; 1651 1652 auto dtb = DtBuilder(0); 1653 dtb.nzeros(128); 1654 s.Sdt = dtb.finish(); 1655 dt2common(&s.Sdt); 1656 1657 outdata(s); 1658 1659 bzeroSymbol = s; 1660 return s; 1661 } 1662 1663 1664 1665 /************************************** 1666 * Generate elem that is a dynamic array slice of the module file name. 1667 */ 1668 1669 private elem *toEfilename(Module m) 1670 { 1671 //printf("toEfilename(%s)\n", m.toChars()); 1672 const(char)* id = m.srcfile.toChars(); 1673 size_t len = strlen(id); 1674 1675 if (!m.sfilename) 1676 { 1677 // Put out as a static array 1678 m.sfilename = toStringSymbol(id, len, 1); 1679 } 1680 1681 // Turn static array into dynamic array 1682 return el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(m.sfilename)); 1683 } 1684 1685 // Used in e2ir.d 1686 public elem *toEfilenamePtr(Module m) 1687 { 1688 //printf("toEfilenamePtr(%s)\n", m.toChars()); 1689 const(char)* id = m.srcfile.toChars(); 1690 size_t len = strlen(id); 1691 Symbol* s = toStringSymbol(id, len, 1); 1692 return el_ptr(s); 1693 }