@@ -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,65 @@ 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 namePrefix, string nameSuffix, bool noUnderscore = false )
5556+ {
5557+ OutBuffer nameOB;
5558+ nameOB.writestring(namePrefix);
5559+ mangleToBuffer(vd, nameOB);
5560+ nameOB.writestring(nameSuffix);
5561+
5562+ Symbol* s = symbol_calloc(nameOB.extractSlice);
5563+ s.Sclass = SC .extern_;
5564+ s.Sfl = FL .extern_;
5565+ s.Stype = type_fake(TYnptr); // always a pointer in size, regardless of linker list type.
5566+
5567+ if (noUnderscore)
5568+ s.Sflags |= SFLnounderscore;
5569+
5570+ return el_ptr (s);
5571+ }
5572+
5573+ switch (config.objfmt)
5574+ {
5575+ case OBJ_MACH :
5576+ elems[1 ] = genStartEndExtern(canBeReadOnly ? " section$start$__TEXT$" : " section$start$__DATA$" , " " , true );
5577+ elems[2 ] = genStartEndExtern(canBeReadOnly ? " section$end$__TEXT$" : " section$end$__DATA$" , " " , true );
5578+ break ;
5579+
5580+ case OBJ_ELF :
5581+ elems[1 ] = genStartEndExtern(" __start_" , " " );
5582+ elems[2 ] = genStartEndExtern(" __stop_" , " " );
5583+ break ;
5584+ case OBJ_MSCOFF :
5585+ elems[1 ] = genStartEndExtern(" " , " _start" );
5586+ elems[2 ] = genStartEndExtern(" " , " _end" );
5587+ break ;
5588+
5589+ default :
5590+ assert (0 );
5591+ }
5592+ }
5593+
55415594 foreach (const i, arg; * arguments)
55425595 {
5596+ if (i == 1 && fd ! is null && fd.ident is Id.linkerlistApply)
5597+ {
5598+ // do not generate symbol for the linker list global
5599+ linkerlistArg(arg);
5600+ break ; // This completes the argument list.
5601+ }
5602+
55435603 elem* ea = toElem(arg, irs);
55445604 Parameter param = null ;
55455605
@@ -6555,8 +6615,10 @@ elem* toElemCall(CallExp ce, ref IRState irs, elem* ehidden = null)
65556615 if (ce.e1.op == EXP .dotVariable && t1.ty != Tdelegate)
65566616 {
65576617 DotVarExp dve = cast (DotVarExp)ce.e1;
6618+ FuncDeclaration linkerListApply;
65586619
65596620 fd = dve.var.isFuncDeclaration();
6621+ ectype = dve.e1.type.toBasetype();
65606622
65616623 if (auto sle = dve.e1.isStructLiteralExp())
65626624 {
@@ -6565,6 +6627,17 @@ elem* toElemCall(CallExp ce, ref IRState irs, elem* ehidden = null)
65656627 sle.type.size() <= 8 ) // more efficient than fPIC
65666628 sle.useStaticInit = false ; // don't modify initializer, so make copy
65676629 }
6630+ else if (fd.ident is Id.apply)
6631+ {
6632+ if (auto ts = ectype.isTypeStruct)
6633+ {
6634+ if (ts.sym.ident is Id.__linkerlist)
6635+ {
6636+ Dsymbol applyImpl = search_function(ts.sym, Id.linkerlistApply);
6637+ linkerListApply = applyImpl ! is null ? applyImpl.isFuncDeclaration : null ;
6638+ }
6639+ }
6640+ }
65686641
65696642 // Special cases for constructor RVO
65706643 if (ehidden && fd && fd.isCtorDeclaration())
@@ -6584,11 +6657,22 @@ elem* toElemCall(CallExp ce, ref IRState irs, elem* ehidden = null)
65846657
65856658 ehidden = null ;
65866659 }
6660+ else if (linkerListApply ! is null )
6661+ {
6662+ // Point ec to the implementation function and update the function/type to match.
6663+ // Append to the arguments list the global variable that contains the linker list.
6664+
6665+ ec = el_ptr(toSymbol(linkerListApply));
6666+ ectype = linkerListApply.type;
6667+ t1 = linkerListApply.type;
6668+ fd = linkerListApply;
6669+
6670+ assert (ce.arguments ! is null && ce.arguments.length == 1 );
6671+ ce.arguments.push(dve.e1);
6672+ }
65876673 else
65886674 ec = toElem(dve.e1, irs);
65896675
6590- ectype = dve.e1.type.toBasetype();
6591-
65926676 /* Recognize:
65936677 * [1] ce: ((S __ctmp = initializer),__ctmp).ctor(args)
65946678 * where the left of the . was turned into [2] or [3] for EH_DWARF:
0 commit comments