#Call Function from Global ASM

1 messages · Page 1 of 1 (latest)

glass flicker
#

I have some custom global assembly and need to call a function.
Usually I'd just pass it as an input w/ the X constraint, but seems like that's not possible in global asm?

I've found the ${:private}, but trying to use that just leads to the compiler crashing.
Would appreciate any help!

(Of course the function I'm trying to call is Callconv(.Naked))

hardy geode
#

Did you try asm volatile ("callq %[func:P]": : [func] "X" (&func));? And what would the callee being naked have to do with anything?

glass flicker
#

It's global asm so no inputs allowed.

#

Well the callee has to be naked for a raw asm call to make sense

hardy geode
#

Why do you have code in global asm?

glass flicker
#

Well the whole function is in asm, and I'm calling that

#

Eventually I want to move it to an .s file, but that's pretty much the same

hardy geode
#

naked functions are for functions that are entirely written in asm

glass flicker
#

So you're saying I should rather do a naked function and then an asm block inside?

hardy geode
#

yeah, I won't put code in global asm

glass flicker
#

Hmm, I'll try. I'm a bit worried the compiler will put some kind of code around my ASM and it'll break...

hardy geode
#

Naked is what tells the compiler not to do that

#

since that's the expected use case for Naked, if it doesn't work I can look into fixing it

glass flicker
#

Makes sense. Could I then also split the ASM and put a normal function call in the middle? Or will cause the compiler to start doing things all over the place?

hardy geode
#

yes, I made sure it was possible to have different asm statements so that you could put them inside different comptime if statements

glass flicker
#

Ah, that also solves the difficulty of doing this cross-platform. I can probably just use a comptime switch

hardy geode
#

and I've started disallowing various things in naked functions that could subtly break, so let me know if you do manage to break it, there may be other things to prevent

glass flicker
#

Yeah I already saw the runtime safety thing. Good thing the compiler catched that now.

#

Is there a good way to do "naked but also sysv"? My extern fn was Callconv(SysV), and then the inner was naked

#

now I'd have to make the combined function naked, but I'd like calls to it to be treated as sysv

#

of course I can do a function pointer (I'm assuming casts work there), but not sure if the compiler will elide function -> function pointer -> cast callconv -> call into a "normal" call

hardy geode
#

you can't call naked functions, so it doesn't make sense to have a calling convention

glass flicker
#

Not sure I understand that? I can implement my own calling convention, so why not?

hardy geode
#

the calling convention only affects calls of the function which are not allowed

glass flicker
#

Right, but can I somehow explain to the compiler that I have manually implemented sysv on the inside? And in turn call the function somehow?

hardy geode
#

I mean that's what an extern function is

glass flicker
#

Right, that works for the global asm blob, but not for the naked function, or can I use extern function somehow in combination with naked?

#

I guess I can make a separate fn trampoline() Callconv(.SysV) void { return asm("callq %[func:P]"::[func] "X" (&naked)); } but I'm not sure that would ever be inlined, and naked would not be inlined for sure, so not really a good solution either IMO

hardy geode
#

the compiler is under no obligation to make that code work

glass flicker
#

yeah I would've expected that to easily break

hardy geode
#

oh, unless you actually don't have any parameters

glass flicker
#

Then it's required to work?

hardy geode
#

no, but there's certainly nothing preventing it from being inlined

glass flicker
#

kinda seems like once I go into ASM function territory I have to stay there for all the downstream functions, going back to zig seems hard?
Or at least I don't really get how to without a kinda big performance hit

hardy geode
#

the only issue I see is the stack alignment at the asm call, but we handle that by just not assuming the stack alignment inside the asm function

glass flicker
#

I would think that it might kinda work, but it's pretty ugly and will introduce a useless call for sure

hardy geode
#

what useless call?

glass flicker
#

the asm callq is pretty pointless

#

the naked function isn't so big so I'd think is inlined, but I suppose that might never be inlined regardless

hardy geode
#

I'm not following at all

#

a call to trampoline() is inlined by llvm to a call instruction

#

you can't inline more unless you don't use naked

glass flicker
#

right, but the call instruction will never be inlined, even though it could if it was visible to the compiler / LLVM as a "normal" function

hardy geode
#

yes, if you use a non-naked function containing assembly it can be inlined

glass flicker
#

The extern fn + global asm does this, I think, but then I don't have a way to call a downstream "normal" function. (either via a naked function or otherwise)

hardy geode
#

if an argument needs to be in a certain register, you should use a register constraint, if it doesn't, you should make the assembly use whatever register it happens to be in

glass flicker
#

Well, that's kind what I'm doing with the SysV calling convention. LLVM knows what registers it can freely use and which it can't

hardy geode
#

so why not just use inline asm

#

inline asm also says what registers can be used and what can't, and it isn't restricted to a predetermined calling convention

glass flicker
#

I need to restrict the number of registers LLVM uses, and also things like control registers

#

SysV does that quite effectively

#

afaik LLVM will spill any registers it doesn't otherwise have space for, and will setup any vector / FP related control bits the way it needs to

hardy geode
#

I don't understand any of those sentences

glass flicker
#

sorry 😅 Callconv(.SysV), from what I know, will make LLVM only assume rbx, rbp, r12-r15 and two control registers to be saved.

#

If it needs anything beyond that it'll spill it to stack, or do some other magic, doesn't really matter

#

So all I have to do is handle those handful of registers, and everything will work.

#

If I define explicit cobbles LLVM is free to assume that ie some 256 bit AVX register is untouched, although it might not

#

and I don't want to list all the possible registers (as that seems very brittle)

hardy geode
#

sysv also defines caller and callee saved avx registers

glass flicker
#

maybe, I haven't seen that at least, but I might've missed it

hardy geode
#

you may have been reading a version written before they existed

glass flicker
#

AVX512 was at least proposed in 2013, but might've just not found it's way into that document by 2014

hardy geode
#

weird, maybe I'm thinking of a different calling convention, that says they are all clobbered by a call