narrowed down the problem area [naked asm]
Don
nospam at nospam.com.au
Wed Oct 29 02:34:39 PDT 2008
Tomas Lindquist Olsen wrote:
> Don wrote:
>> bearophile wrote:
>>>
>>> The LDC docs say:
>>>
>>>> One thing the D spec isn't clear about at all is how asm blocks
>>>> mixed with normal D code (for example code between two asm blocks)
>>>> interacts.<
>>>> Currently 'naked' in D is treated as a compile time error in LDC.
>>>> Reason for this is that LLVM does not support directly controlling
>>>> prologue/epilogue generation. Also the documentation from the D spec
>>>> on this topic is extremely limited and doesn't mention anything
>>>> about how normal D code in a naked function works. In particular
>>>> local (stack) variables are unclear, also accessing named parameters
>>>> etc.<
>>
>> I can answer this.
>
> Thank you very much. This will help me a lot implementing 'naked' in LDC :)
>
>>
>> 'naked' in DMD is quite simple: almost nothing works.
>
> :P
>
>>
>> Stack variables with 'naked' don't work. Parameters don't work,
>> either. Nor do contracts. Here's why:
>>
>> Regardless of whether 'naked' is specified or not, the compiler
>> creates code exactly as if the function began with 'push EBP; mov EBP,
>> ESP; ' and ended with 'pop EBP; '
>> If 'naked' is specified, it just doesn't put that prologue and
>> epilogue in.
>> So the only way to use 'naked' is to manually keep track of where
>> everything is on the stack, and index it off the stack pointer.
>>
>
> This actually makes things quite simple, LLVM does frame pointer
> elimination by default (we force it to emit one when normal inline asm
> is used though), so this condition should just be changed to 'if
> (asmIsUsed && !isNaked) doEBP();'
> There's a few other technical issues, mostly related to LLVM using an
> SSA form and function arguments being l-values in D, but that's not
> really important here...
>
>> Why use 'naked' at all, then?
>> (1) so that you can use the EBP register;
>> (2) because non-naked asm doesn't work properly, either. If you pass
>> an array into an asm function, you can't get the ".ptr" part of it,
>> because the "ptr" conflicts with the asm "ptr" keyword. This is a big
>> problem, since almost all asm functions that I write work on arrays.
>>
>
> Could we work around this somehow ? Actually I'm not sure we even handle
> this kind of thing properly yet (accessing aggregate fields in asm). I
> should test that :)
>
>> I don't think that this is how naked asm _should_ work, though. It
>> should allow you to reference parameters without adjusting the offsets
>> assuming you're using EBP. So the following should work:
>>
>> void nakedfunc(uint [] dest, uint [] src)
>> {
>> asm {
>> naked;
>> mov ECX, dest.ptr[ESP];
>> ret 4*4;
>> }
>> }
>
> So this should work since you've not modified ESP right?
Yes, it's your responsibility to make sure that ESP points to first
parameter on the stack.
I'm not sure
> what facilities LLVM currently has to get stack offsets of parameters
> before the actual native codegen, probably none.. So this might be a bit
> difficult to implement in LDC, but again, I'm not really aware of all
> that LLVM's inline asm can really do, since there is basically no
> documentation, and we've only read so much of their source code :P
If it is only mov ECX, [ESP]param, then you can translate it to mov ECX,
param.
In fact, it would be even better if you could write mov ECX, param.
If DMD would keep track of the number of pushes and pops that occured,
it could do this too.
Here's the kind of nonsense I'm doing at the moment. I create a constant
'LASTPARAM' which is the offset to the last parameter.
The compiler should really be helping with this. But at least it works...
void foo(uint [] dest, uint[] left, uint [] right)
{
enum { LASTPARAM = 6*4 } // 4* pushes + local + return address.
asm {
naked;
push ESI;
push EDI;
push EBX;
push EBP;
push EAX; // local variable M
mov EDI, [ESP + LASTPARAM + 4*5]; // dest.ptr
mov EBX, [ESP + LASTPARAM + 4*2]; // left.length
mov ESI, [ESP + LASTPARAM + 4*3]; // left.ptr
...
mul int ptr [ESP]; // M
...
pop EAX; // get rid of M
pop EBP;
pop EBX;
pop EDI;
pop ESI;
ret 6*4;
}
}
>
>>
>> Since the spec says:
>> "If the [EBP] is omitted, it is assumed for local variables. If naked
>> is used, this no longer holds."
>> True, it doesn't put in an [EBP], but it adjusts the offset assuming
>> that a stack frame has been set up. And ".ptr" doesn't work.
>>
>
> This .ptr issue certainly seems like something that should be fixed
> somehow :)
>
>>
>> Curious fact:
>> Whenever I'm naked, my body disappears!
>>
>> void fkk()
>> {
>> asm { naked; }
>> }
>>
>> void main() { fkk(); }
>>
>> --> generates a linker error. Fair enough, really. But kind of
>> interesting.
>
> This will not happen in LDC, it will just produce what it does without
> the naked:
>
> _D3bar3fooFZv:
> ret
>
> Again thanx for these explanations.
> Maybe we'll have 'naked' soon in LDC after all :)
>
> -Tomas
More information about the Digitalmars-d
mailing list