Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to call functions where args must be passed at the stack #1108

Closed
bjorn3 opened this issue Aug 20, 2019 · 6 comments · Fixed by #1559
Closed

How to call functions where args must be passed at the stack #1108

bjorn3 opened this issue Aug 20, 2019 · 6 comments · Fixed by #1559
Labels
cranelift Issues related to the Cranelift code generator

Comments

@bjorn3
Copy link
Contributor

bjorn3 commented Aug 20, 2019

For example:

#[derive(C)]
struct S {
    a: u64,
    b: u64,
    c: u64,
    d: u64,
    e: u64,
}

extern "C" {
    fn take_a(a: A);
}

When calling take_a the argument must be put in the input argument area of the stack.

cc https://github.com/bjorn3/rustc_codegen_cranelift/issues/10#issuecomment-523136265

@vitiral
Copy link

vitiral commented Sep 17, 2019

what is A here? Do you mean take_a(s: S), i.e. "get S.a"?

@undingen
Copy link
Contributor

Yes I think it should be take_a(s: S).

And I think the problem is if you call an external C function which receives a large struct by value the calling function will pass the struct by pushing it on the stack directly before calling the function (e.g. it will not explicitly put a pointer to the data into a register or so no it will just push it on the stack).
The called function will afterwards access it by fixed offset from the stack: e.g.

int take_a(S s) {
    return s.a;
}

will compile to (without frame pointers):

mov rax, QWORD PTR [rsp+8]
ret

So it's important to control whats on the stack before calling the function (e.g. spilling some values would ruin it)

@fitzgen
Copy link
Member

fitzgen commented Oct 4, 2019

Yeah, with sysv you can't transparently explode a struct into its members and pass those. There is a grouping going on: either all the members fit in registers, or the whole struct is passed on the stack. There is no partial situation where some members are passed in registers and some are passed on the stack. Cranelift isn't equipped to reason about this, since it doesn't have any concept of structs.

So for now at least, the ir producer would have to take on the responsibility of a bunch of ABI / calling convention concerns and do a funky legalization pass before even giving cranelift any ir. The division of responsibilities here is pretty murky...

@bjorn3
Copy link
Contributor Author

bjorn3 commented Oct 4, 2019

So for now at least, the ir producer would have to take on the responsibility of a bunch of ABI / calling convention concerns and do a funky legalization pass before even giving cranelift any ir. The division of responsibilities here is pretty murky...

So how do I actually pass something on the stack?

@nbp
Copy link
Contributor

nbp commented Oct 7, 2019

So how do I actually pass something on the stack?

Using stack_addr and using the returned value as argument, as a pointer to the stack which contains the structure?

@bjorn3
Copy link
Contributor Author

bjorn3 commented Oct 7, 2019

That is not what the System-V abi requires. SysV requires you to put the values at specific stack offsets. The callee then loads the args from those offsets, not from a pointer passed in a register.

@alexcrichton alexcrichton transferred this issue from bytecodealliance/cranelift Feb 28, 2020
@alexcrichton alexcrichton added the cranelift Issues related to the Cranelift code generator label Feb 28, 2020
@bjorn3 bjorn3 mentioned this issue Apr 20, 2020
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cranelift Issues related to the Cranelift code generator
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants