[Bug 268] Implement thunk generation in frontend

via D.gnu d.gnu at puremagic.com
Tue Aug 1 12:37:21 PDT 2017


https://bugzilla.gdcproject.org/show_bug.cgi?id=268

--- Comment #1 from Johannes Pfau <johannespfau at gmail.com> ---
After some investigation I don't think we can implement thunks for variadic
functions in a portable way.

AFAICS the FUNCTION_DECL tree in GCC does not contain any information that this
function can be called with varargs so all functions in theory are vararg
capable. The build_call functions determine whether vararg ABI should be used
simply by comparing the number of specified parameters to the number of
declared parameters.

Because all this is 'implicit', there's no generic way to 'pass on' variadic
arguments to another function. There's no 'pass all args' implementation in GCC
and a manual va_start/va_arg/... can't work either, as there's no information
about the number of arguments in general.

Now (this-adjusting) thunks are pretty simple functions so 'pass-on' for
varargs can work for these functions. The key is not messing with any registers
or stack space in the thunk. However, as GCC does not even have a portable
naked attribute, there's no generic way to implement this. This leads to some
interesting effects:

------------------------------------------------------------------------------
import core.vararg;
extern(C) int someFunctionI1_Thunk(void* v, int a, ...);
void main()
{ someFunctionI1_Thunk(cast(void*)0, 10, 1, 2, 3, 4, 5, 6,7, 8, 9, 10); }
------------------------------------------------------------------------------
import std.stdio;
import core.vararg;

extern(C) int someFunctionI1(void* v, int a, ...)
{
    va_list va;
    va_start(va, a);
    int param;
    for (int i = 0; i < a; i++)
    {
        va_arg!int(va, param);
        writeln(param);
    }
    va_end(va);
    return 0;
}
------------------------------------------------------------------------------
extern(C) int someFunctionI1(void* v, int a, ...);

extern(C) int someFunctionI1_Thunk(void* v, int a)
{
    return someFunctionI1(v+10, a);
}
------------------------------------------------------------------------------

When compiled with optimizations, this works perfectly as tail call
optimization removes the prologue/epilogue of someFunctionI1_Thunk and the add
is directly performed on the register. But without optimization, this breaks.

So portable thunks for variadic function may be possible, as long as these
thunks only add to the register containing the this pointer and then directly
jump to the target, but I'm not aware of portably representing this in GCC.


I'll probably still implement thunks for non-variadic functions in the frontend
for GCC <= 4.9. This is trivial to implement and all cases except for variadic
functions should work. With optimizations, the resulting code is equivalent to
the GCC thunk code. Without optimizations there's obviously some performance
impact, but backporting 'force_gimple_thunk' for GCC <= 4.9 is probably not
worth the effort.

BTW @ Iain: Why do GCC thunks generate aliases to the target function? Is this
an optimization, a workaround for assembler / linker bugs or something entirely
different?

-- 
You are receiving this mail because:
You are watching all bug changes.


More information about the D.gnu mailing list