#Call in inline ASM?

1 messages · Page 1 of 1 (latest)

haughty ferry
#

I'm trying to directly call into memory, but can't quite figure it out.
I think I've setup allocating the stack space for the function correctly, but am not quite sure how a call is supposed to work

I'm trying this way:

const rsp2 = asm volatile (
    \\ callq *%[addr]
    : [ret] "={rsp}" (-> u64),
    : [addr] "r" (addr),
    : "rax rbx rcx rdx rsi rdi rsp rbp r8 r9 r10 r11 r12 r13 r14 15" // TODO: Add FP & Vector registers here
);

And I think this should be fine?
I'm not sure whether rsp/rbp should be in the clobbers list, but it doesn't really change anything about my problem.

I'm using this callq *%[addr], but I'm not sure this is right? addr is the absolute memory address, and I'm not sure if I'm correctly telling the compiler to emit a call to the right location. From what I know calls are typically relative, but I provide an absolute address?
This might be what the * does, but I'm not sure.

I am however getting a seg fault at 0x4800000 which is also where the page that contains the function starts in is at, so maybe the call is fine?

Not sure - any advice would be appreciated...

dire finch
#

callq label is relative, callq *reg calls the absolute address in reg (as if reg contained a function pointer), callq *mem calls the absolute address stored in memory

#

so you can just use "g" and callq *%[addr] will handle both cases, but you are probably calling a non-executable address

#

it also doesn't look like you aligned the stack pointer

#

also that clobber syntax is wrong

#

I would recommend not using inline asm for this

#

like, if a call clobbers rsp you have much bigger problems to worry about

haughty ferry
dire finch
#

clobber means it has a different value afterwards than before, save and restore doesn't count

#

I mean you haven't really explained how it isn't just a call...

haughty ferry
#

Well there's more asm I'm writing now around it - sorry just figuring out how this works myself.

I'm basically making a trampoline (? I think that's a standard way to name this) for a sort of compiler I'm writing for fun.
For now I'm just putting all args & results on the stack, and sort of say that all registers are caller saved. That's the easiest thing for me to do.

I have this now:

noinline fn trampoline(func_info: FuncInfo, args: [*]const u8, result: [*]u8) void {
    const arg_bytes: u64 = @intCast(func_info.arg_byte_size + func_info.res_byte_size);
    const res_bytes: u64 = @intCast(func_info.res_byte_size);
    const addr: u64 = @intCast(func_info.jump_address);

    asm volatile (
        \\ mov %[arg_bytes], %[temp_data]
        \\ sub %[temp_data], %%rsp
        \\ mov %[temp_data], %[counter]
        \\ mov %[res_bytes], %[temp_data]
        \\ sub %[temp_data], %%rsp
        \\ shrq $2, %[counter]
        \\ xor %[index], %[index]
        \\ arg_loop:
        \\ mov 0(%[args],%[index],8), %[temp_data]
        \\ mov %[temp_data], 0(%%rsp,%[index],8)
        \\ inc %[index]
        \\ dec %[counter]
        \\ jnz arg_loop
        \\ call *%[addr]
        \\ mov %[res_bytes], %[counter]
        \\ shrq $2, %[counter]
        \\ xor %[index], %[index]
        \\ res_loop:
        \\ mov 0(%%rsp,%[index],8), %[temp_data]
        \\ mov %[temp_data], 0(%[result],%[index],8)
        \\ inc %[index]
        \\ dec %[counter]
        \\ jnz res_loop
        \\ mov %[res_bytes], %[temp_data]
        \\ add %[temp_data], %%rsp
        :
        : [res_bytes] "m" (res_bytes),
            [arg_bytes] "m" (arg_bytes),
            [addr] "r" (addr),
            [args] "r" (args),
            [result] "r" (result),
            [counter] "r" (0),
            [index] "r" (0),
            [temp_data] "r" (0),
        : "memory", "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" // TODO: Add FP & Vector registers here
    );
}

Which I think should be correct in general (of course not super sure about the ASM, I'm new to it, especially the stupid AT&T syntax...)
I just haven't really figured out the clobbers part - I think it shuold be correct declaring it like this (-> these are the registers I might allocate internally), and the memory clobber is right too I think?
Problem is that of course there are no registers left for llvm to assign to my inputs - it just error: inline assembly requires more registers than available.
Not sure how I can allow inputs to also be clobbers.

Is this the right way to achieve what I'm trying to? Or is there some other way I could do this?

#

(Also I'm very aware this is not at all efficient, but it should work for now - later I will try to also pump the trampoline through my internal ASM generation, and then in turn just have a JMP addr here. Something like that at least...)

dire finch
#

clobbers can not alias inputs or outputs

#

you can use dummy outputs instead of clobbers in that case

haughty ferry
#

that makes sense. I just manually assigned registers to the inputs and then removed those from the clobber list.