This is an archive of the discontinued LLVM Phabricator instance.

ARM: Do not tail-call to an externally-defined function with weak linkage
ClosedPublic

Authored by olista01 on Aug 14 2014, 8:44 AM.

Details

Reviewers
t.p.northover
Summary

Externally-defined functions with weak linkage should not be
tail-called on ARM or AArch64, as the AAELF spec requires normal calls
to undefined weak functions to be replaced with a NOP or jump to the
next instruction. The behaviour of branch instructions in this
situation (as used for tail calls) is implementation-defined, so we
cannot rely on the linker replacing the tail call with a return.

Diff Detail

Event Timeline

olista01 updated this revision to Diff 12509.Aug 14 2014, 8:44 AM
olista01 retitled this revision from to ARM: Do not tail-call to an externally-defined function with weak linkage.
olista01 updated this object.
olista01 edited the test plan for this revision. (Show Details)
olista01 set the repository for this revision to rL LLVM.
olista01 added a subscriber: Unknown Object (MLST).

Hi Oliver,

Is this an armlink work-around? The ABI looks suspiciously like it was written specifically to be compatible with some recalcitrant linker. It's even phrased as a platform-dependent issue (especially so on AArch32).

GNU's linker on Linux (both AArch32 & AArch64) seems to cope fine, for example. So I don't think we'd want to disable the optimisation there. Or anywhere without evidence of problems, really.

Cheers.

Tim.

olista01 updated this revision to Diff 12551.Aug 15 2014, 6:02 AM

I originally stated that "we cannot rely on the linker replacing the tail call with a return", but after further thought I now realise that it is impossible for the linker to replace a tail-call with a return, as it may need to insert a stack pointer adjustment, but it does not know how big the adjustment must be.

Both armlink and arm-none-eabi-ld replace branch instructions to undefined weak symbols with a NOP, so this is not just an armlink problem.

The AAELF spec only states this for "platforms that do not support dynamic pre-emption of symbols", so I have modified the patch to only prevent the tail call for bare-metal systems.

Hi Oliver,

I'm really sorry, I've realised I was confused yesterday. For some reason I'd convinced myself that the nop/"branch-to-next" was the correct behaviour and that's what I was checking for. I see more clearly what you mean now.

So going onto the patch itself, I think it's in the wrong place. The "tail call" instructions inserted at IR level are (usually) more of a hint than a strict requirement. The backends decide what really should and shouldn't be made a tail call, using the "isEligibleForTailCallOptimisation" in XYZISelLowering.cpp (at least in the AArch64 & ARM cases).

My confusion also affects where this is valid. It's almost certainly needed for Linux -static compilations too. Darwin platforms appear to be closest to the pre-emptable Linux situation.

Cheers.

Tim.

olista01 updated this revision to Diff 12613.Aug 18 2014, 3:16 AM

Moved this to the ARM and AArch64 backends, removed all changes to TailCallElim.

I have taken out the restriction based on target platform, as both bare-metal and Linux could need this.

t.p.northover accepted this revision.Aug 18 2014, 4:31 AM
t.p.northover added a reviewer: t.p.northover.

Hi Oliver,

This looks good to me. Thanks for updating it.

Tim.

This revision is now accepted and ready to land.Aug 18 2014, 4:31 AM
olista01 closed this revision.Aug 18 2014, 5:51 AM

Thanks, committed revision 215890.