Repository navigation
Swapped Arguments in Generated Code for extern-C func on x64 #41375
Description
Activity
You might also need
-lpthread -ldlto useclang++with the Ruststaticlib.Looks like we use
%UsizeArg9* byval noalias nocapture dereferenceable(8)(which would pass 8 bytes on the stack) while clang emitsi64for that same argument -at that point they should both go on the stack but I'm not sure what's happening, maybe LLVM really doesn't like what we're doing.EDIT: adding one more
usizeafter the 8th argument fixes it, so I think we're just placing the last register argument on the stack explicitly, whereas clang relies on LLVM making that decision.Arg9 should be passed in r9. Since we expect it as %UsizeArg9* that's not happening.
EDIT: adding one more usize after the 8th argument fixes it, so I think we're just placing the last register argument on the stack explicitly, whereas clang relies on LLVM making that decision.
That matches my conclusion.
Looks like we're treating stack arguments as using up registers (not just the return pointer).
EDIT: it was wrong since it was added in #27017.Minimal reproduction of the provided testcase (6 stack arguments, 1 register argument):
#![crate_type="staticlib"] #[repr(C)] pub struct Big { data: [u8; 64] } #[repr(C)] pub struct Small { data: u8 } #[no_mangle] pub extern "C" fn test(_: Big, _: Big, _: Big, _: Big, _: Big, _: Big, s: Small) { println!("{}", s.data); }
typedef struct { unsigned char data[64]; } Big; typedef struct { unsigned char data; } Small; void test(Big, Big, Big, Big, Big, Big, Small); int main() { Big big; Small small = { 42 }; test(big, big, big, big, big, big, small); }
Testcase for Rust -> C call (roughly what will end up in
run-make/extern-fn-struct-passing-abi):#[repr(C)] #[derive(Copy, Clone)] struct Big { data: [i32; 5] } #[repr(C)] struct Small { data: i32 } extern "C" { fn test(a: Big, b: Big, c: Big, d: Big, e: Big, f: Big, g: Small); } fn main() { let big = Big { data: [0; 5] }; unsafe { test(big, big, big, big, big, big, Small { data: 42 }); } }
#include <assert.h> #include <stdint.h> typedef struct { int32_t data[5]; } Big; typedef struct { int32_t data; } Small; void test(Big a, Big b, Big c, Big d, Big e, Big f, Small g) { assert(g.data == 42); }
- added 7 commits that reference this issue
on Apr 18, 2017
The following program has arg9 and arg10 swapped on the Rust side (C++ is passing the args correctly, as far as the AMD64 ABI is concerned).
Test Platform: macos x64
Reproduced On:
Reproduction Steps: