Closed gingerBill closed 4 years ago
Just want to add a repro example to this issue. Right now it doesn't seem possible to interop with C when using any struct that is larger than 8 bytes.
foo.c
#include <stdint.h>
#include <stdio.h>
typedef struct CXString {
void* data;
uint32_t flags;
} CXString;
const char *hellostr() {
return "hello world";
}
CXString get_cxstring() {
return (CXString){
.data = (void*)"foo bar baz",
.flags = 0xDEADBEEF,
};
}
const char* get_cstr_from_cxstring(const char *val, CXString c) {
printf("val: %s\n", val);
printf("C: %s\n", (const char*)c.data);
return (const char*)c.data;
}
main.odin
package repro
foreign import "foo.so"
import "core:c";
import "core:fmt";
CXString :: struct {
data: rawptr,
flags: u32,
}
foreign foo {
@(link_name = "hellostr") hellostr :: proc "c" () -> cstring ---;
@(link_name = "get_cxstring") get_cxstring :: proc "c" () -> CXString ---;
@(link_name = "get_cstr_from_cxstring") get_cstr :: proc "c" (test: cstring, cx: CXString) -> cstring ---;
}
main :: proc() {
fmt.println(hellostr());
cxstr := get_cxstring();
fmt.println(cast(cstring)cxstr.data, get_cstr("i am a str", cxstr));
}
Hi, I have a same issue with my programming language using LLVM backend, my first idea to fix this was use LLVM's 'byval' attribute and pass all structures by pointers (inspiration to do so came from clang C generated IR with same expected functionality), but it still does not work. What about to use implicit wrapper function for this (change generation of external calls seems to be quite hard since it requires lot of changes to IR generation pass); idea is not to call externals with struct passed by value as an argument directly, but create IR function taking struct by value as normal, do the split into register-friendly representation inside this function and then call original external.
This is now correctly supported on System V AMD64 ABI.
Correctly implement ABI for all supported platforms.
This may require a huge change to how the IR is generated as certain ABIs, such as System V, will separate a value across multiple registers and the current LLVM IR generation only supports to a single register/stack value per passed value.
Example:
Would be passed to LLVM IR as the following parameters: