ORC JIT - Issue with variadic functions (OS X - M1)

I use LLVM 11 for native compilation of Lisp code in my project (https://github.com/shikantaza/pLisp).

The LLVM JIT functionality is encapsulated in jit_llvm.cpp (https://github.com/shikantaza/pLisblob/master/src/jit_llvm.cpp).

The generated C code consists of variadic functions; I look up these functions, get the corresponding function pointers, and invoke them without any issues (in Linux, earlier versions of OS X, and Windows).

However, I have run into an issue on OS X Monterey (M1 architecture; LLVM installed via Homebrew) - the fixed arguments of the functions get passed correctly, whereas the vararg arguments get passed as junk values.

A test program demonstrating this behaviour is reproduced below (this is linked with a library that contains jit_llvm.cpp):

#include <string.h>
#include <stdio.h>

typedef int (*nativefn)(int, int, int, ...);

extern void *compile_functions_from_string(const char *);
extern nativefn get_function(void *, const char *);
extern void cleanupJIT(void *);

int main(int argc, char **argv)
{
  char buf[1000];
  unsigned int len = 0;
  void *jit_state;
  nativefn nf;

  memset(buf, '\0', 1000);

  len += sprintf(buf+len, "#include <stdint.h>\n");
  len += sprintf(buf+len, "#include <stdio.h>\n");

  len += sprintf(buf+len, "int f(int p1, int p2, int p3, int p4)\n");
  len += sprintf(buf+len, "{\n");
  len += sprintf(buf+len, "printf(\"%%d %%d %%d %%d\\n\", p1, p2, p3, p4);\n");
  len += sprintf(buf+len, "return 42;\n");
  len += sprintf(buf+len, "}\n");

  jit_state = compile_functions_from_string(buf);

  nf = get_function(jit_state, "f");

  int ret = nf(100, 200, 300, 400);

  printf("%d\n", ret);

  cleanupJIT(jit_state);

  return 0;
}

Expected output:
100 200 300 400
42

Actual output:
100 200 300 -1896635844
42

I am not sure whether the issue is related to LLVM per se, to the LLVM port (Hoembrew/M1), or if I am doing something non-kosher, although the same mechanism has worked (and works) fine in other platforms, as I mentioned earlier.

One option is to port to LLVM 12, but I understand that this involves a move from ORC v1 to ORC v2, and I would like to avoid this if possible.

Any help wpuld be appreciated.

Thanks,
Rajesh

The issue is that variadic functions genuinely pass arguments differently from ones with all arguments declared on ARM64 MacOS (and iOS etc). On MacOS anonymous arguments always go on the stack, instead of using up remaining arg-passing registers.

So you need to make sure the prototypes match between where you define the functions and where you call them.

Thanks, TNorthover. This is a bummer for me because the functions are user-created (pLisp) functions, so their arity, etc. is known only at runtime.