diff --git a/src/backends/llvm.c b/src/backends/llvm.c
index bf6f513392ed79b767ac58dbdb4739c8f9bcbaf2..39302c967f7e638e2d0caa3936b9de8237b25c8b 100644
--- a/src/backends/llvm.c
+++ b/src/backends/llvm.c
@@ -138,12 +138,22 @@ void h_llvm_free(HParser *parser) {
 HParseResult *h_llvm_parse(HAllocator* mm__, const HParser* parser, HInputStream *input_stream) {
   const HLLVMParser *llvm_parser = parser->backend_data;
   HArena *arena = h_new_arena(mm__, 0);
-  LLVMGenericValueRef args[] = {
-    LLVMCreateGenericValueOfPointer(input_stream),
-    LLVMCreateGenericValueOfPointer(arena)
-  };
-  LLVMGenericValueRef res = LLVMRunFunction(llvm_parser->engine, llvm_parser->func, 2, args);
-  HParseResult *ret = (HParseResult*)LLVMGenericValueToPointer(res);
+
+  // LLVMRunFunction only supports certain signatures for dumb reasons; it's this hack with
+  // memcpy and function pointers, or writing a shim in LLVM IR.
+  //
+  // LLVMGenericValueRef args[] = {
+  //   LLVMCreateGenericValueOfPointer(input_stream),
+  //   LLVMCreateGenericValueOfPointer(arena)
+  // };
+  // LLVMGenericValueRef res = LLVMRunFunction(llvm_parser->engine, llvm_parser->func, 2, args);
+  // HParseResult *ret = (HParseResult*)LLVMGenericValueToPointer(res);
+
+  void *parse_func_ptr_v;
+  HParseResult * (*parse_func_ptr)(HInputStream *input_stream, HArena *arena);
+  parse_func_ptr_v = LLVMGetPointerToGlobal(llvm_parser->engine, llvm_parser->func);
+  memcpy(&parse_func_ptr, &parse_func_ptr_v, sizeof(parse_func_ptr));
+  HParseResult *ret = parse_func_ptr(input_stream, arena);
   if (ret) {
     ret->arena = arena;
     if (!input_stream->overrun) {