@@ -21,6 +21,7 @@ import dmd.root.ctfloat;
2121import dmd.root.rmem;
2222import dmd.rootobject;
2323import dmd.root.stringtable;
24+ import dmd.common.outbuffer;
2425
2526import dmd.glue;
2627import dmd.glue.objc;
@@ -56,6 +57,8 @@ import dmd.id;
5657import dmd.init;
5758import dmd.location;
5859import dmd.mtype;
60+ import dmd.mangle : mangleToBuffer;
61+ import dmd.opover : search_function;
5962import dmd.printast;
6063import dmd.sideeffect;
6164import dmd.statement;
@@ -5408,7 +5411,7 @@ elem* callfunc(Loc loc,
54085411 version (none )
54095412 {
54105413 printf(" callfunc(directcall = %d, tret = '%s', ec = %p, fd = %p, op = %d)\n " ,
5411- directcall, tret.toChars(), ec, fd);
5414+ directcall, tret.toChars(), ec, fd, op );
54125415 printf(" ec: " ); elem_print(ec);
54135416 if (fd)
54145417 printf(" fd = '%s', vtblIndex = %d, isVirtual() = %d\n " , fd.toChars(), fd.vtblIndex, fd.isVirtual());
@@ -5521,7 +5524,7 @@ elem* callfunc(Loc loc,
55215524
55225525 /* Convert arguments[] to elems[] in left-to-right order
55235526 */
5524- const n = arguments.length;
5527+ const n = arguments.length + (fd ! is null && fd.ident is Id.linkerlistApply) ;
55255528 debug
55265529 elem* [2 ] elems_array = void ;
55275530 else
@@ -5538,8 +5541,64 @@ elem* callfunc(Loc loc,
55385541 const int j = tf.isDstyleVariadic();
55395542 const osx_aapcs64 = irs.target.isAArch64 && irs.target.os == Target.OS .OSX ;
55405543
5544+ void linkerlistArg (Expression arg)
5545+ {
5546+ // We are swapping a __linkerlist!T global variable with its respective start+stop symbols as arguments.
5547+ // The transformation takes place at offset 1 of the elems array, and will result in three arguments total.
5548+
5549+ VarExp ve = arg.isVarExp;
5550+ assert (ve ! is null );
5551+ VarDeclaration vd = ve.var.isVarDeclaration;
5552+ assert (vd ! is null );
5553+ const canBeReadOnly = ! vd.type.isMutable;
5554+
5555+ elem* genStartEndExtern (string name, bool noUnderscore = false )
5556+ {
5557+ OutBuffer nameOB;
5558+ mangleToBuffer(vd, nameOB);
5559+ nameOB.writestring(name);
5560+
5561+ Symbol* s = symbol_calloc(nameOB.extractSlice);
5562+ s.Sclass = SC .extern_;
5563+ s.Sfl = FL .extern_;
5564+ s.Stype = type_fake(TYnptr); // always a pointer in size, regardless of linker list type.
5565+
5566+ if (noUnderscore)
5567+ s.Sflags |= SFLnounderscore;
5568+
5569+ return el_ptr (s);
5570+ }
5571+
5572+ switch (config.objfmt)
5573+ {
5574+ case OBJ_MACH :
5575+ elems[1 ] = genStartEndExtern(canBeReadOnly ? " section$start$__TEXT$" : " section$start$__DATA$" , true );
5576+ elems[2 ] = genStartEndExtern(canBeReadOnly ? " section$end$__TEXT$" : " section$end$__DATA$" , true );
5577+ break ;
5578+
5579+ case OBJ_ELF :
5580+ elems[1 ] = genStartEndExtern(" __start_" );
5581+ elems[2 ] = genStartEndExtern(" __stop_" );
5582+ break ;
5583+ case OBJ_MSCOFF :
5584+ elems[1 ] = genStartEndExtern(" _start" );
5585+ elems[2 ] = genStartEndExtern(" _end" );
5586+ break ;
5587+
5588+ default :
5589+ assert (0 );
5590+ }
5591+ }
5592+
55415593 foreach (const i, arg; * arguments)
55425594 {
5595+ if (i == 1 && fd ! is null && fd.ident is Id.linkerlistApply)
5596+ {
5597+ // do not generate symbol for the linker list global
5598+ linkerlistArg(arg);
5599+ break ; // This completes the argument list.
5600+ }
5601+
55435602 elem* ea = toElem(arg, irs);
55445603 Parameter param = null ;
55455604
@@ -6555,8 +6614,10 @@ elem* toElemCall(CallExp ce, ref IRState irs, elem* ehidden = null)
65556614 if (ce.e1.op == EXP .dotVariable && t1.ty != Tdelegate)
65566615 {
65576616 DotVarExp dve = cast (DotVarExp)ce.e1;
6617+ FuncDeclaration linkerListApply;
65586618
65596619 fd = dve.var.isFuncDeclaration();
6620+ ectype = dve.e1.type.toBasetype();
65606621
65616622 if (auto sle = dve.e1.isStructLiteralExp())
65626623 {
@@ -6565,6 +6626,17 @@ elem* toElemCall(CallExp ce, ref IRState irs, elem* ehidden = null)
65656626 sle.type.size() <= 8 ) // more efficient than fPIC
65666627 sle.useStaticInit = false ; // don't modify initializer, so make copy
65676628 }
6629+ else if (fd.ident is Id.apply)
6630+ {
6631+ if (auto ts = ectype.isTypeStruct)
6632+ {
6633+ if (ts.sym.ident is Id.__linkerlist)
6634+ {
6635+ Dsymbol applyImpl = search_function(ts.sym, Id.linkerlistApply);
6636+ linkerListApply = applyImpl ! is null ? applyImpl.isFuncDeclaration : null ;
6637+ }
6638+ }
6639+ }
65686640
65696641 // Special cases for constructor RVO
65706642 if (ehidden && fd && fd.isCtorDeclaration())
@@ -6584,11 +6656,22 @@ elem* toElemCall(CallExp ce, ref IRState irs, elem* ehidden = null)
65846656
65856657 ehidden = null ;
65866658 }
6659+ else if (linkerListApply ! is null )
6660+ {
6661+ // Point ec to the implementation function and update the function/type to match.
6662+ // Append to the arguments list the global variable that contains the linker list.
6663+
6664+ ec = el_ptr(toSymbol(linkerListApply));
6665+ ectype = linkerListApply.type;
6666+ t1 = linkerListApply.type;
6667+ fd = linkerListApply;
6668+
6669+ assert (ce.arguments ! is null && ce.arguments.length == 1 );
6670+ ce.arguments.push(dve.e1);
6671+ }
65876672 else
65886673 ec = toElem(dve.e1, irs);
65896674
6590- ectype = dve.e1.type.toBasetype();
6591-
65926675 /* Recognize:
65936676 * [1] ce: ((S __ctmp = initializer),__ctmp).ctor(args)
65946677 * where the left of the . was turned into [2] or [3] for EH_DWARF:
0 commit comments