Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

using C bindings, calling LLVMSetGC("shadow-stack") fails with an unsupported error #23094

Open Quuxplusone opened 9 years ago

Quuxplusone commented 9 years ago
Bugzilla Link PR23095
Status NEW
Importance P normal
Reported by Hayden Livingston (halivingston@gmail.com)
Reported on 2015-03-31 19:56:13 -0700
Last modified on 2015-04-01 17:41:30 -0700
Version 3.6
Hardware PC Windows NT
CC llvm-bugs@lists.llvm.org
Fixed by commit(s)
Attachments linkShadowStackGC.diff (1109 bytes, text/plain)
Blocks
Blocked by
See also
I'm using LLVMSharp, which require .NET or Mono. I suspect it'll reproduce in
LLVM-C bindings as well.

I've attached the C# program I used on Windows.

Step 1:
Open Visual Studio
Create Solution
Install-Package LLVMSharp (it comes with a shared library inside)

Put the following program and notice the console output which says unsupported
error:

namespace ConsoleApplication2
{
    using System;
    using System.Runtime.InteropServices;
    using LLVMSharp;

    class Program
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate int Add();

        static void Main(string[] args)
        {
            LLVMBool False = new LLVMBool(0);
            LLVMModuleRef mod = LLVM.ModuleCreateWithName("LLVMSharpIntro");

            LLVMTypeRef param_types = new LLVMTypeRef();
            LLVMTypeRef ret_type = LLVM.FunctionType(LLVM.Int32Type(), out param_types, 0, False);
            LLVMValueRef sum = LLVM.AddFunction(mod, "sum", ret_type);
            LLVM.SetGC(sum, "erlang");

            LLVMBasicBlockRef entry = LLVM.AppendBasicBlock(sum, "entry");

            LLVMBuilderRef builder = LLVM.CreateBuilder();

            LLVM.PositionBuilderAtEnd(builder, entry);
            var p = LLVM.BuildAlloca(builder, LLVM.Int32Type(), "p");
            LLVM.BuildStore(builder, LLVM.ConstInt(LLVM.Int32Type(), 10, False), p);
            var x = LLVM.BuildLoad(builder, p, "foo");
            LLVM.BuildRet(builder, x);

            IntPtr error;
            LLVM.VerifyModule(mod, LLVMVerifierFailureAction.LLVMAbortProcessAction, out error);
            LLVM.DisposeMessage(error);

            LLVMExecutionEngineRef engine;

            LLVM.LinkInMCJIT();
            LLVM.InitializeX86Target();
            LLVM.InitializeX86TargetInfo();
            LLVM.InitializeX86TargetMC();
            LLVM.InitializeX86AsmPrinter();

            var platform = Environment.OSVersion.Platform;
            if (platform == PlatformID.Win32NT) // On Windows, LLVM currently (3.6) does not support PE/COFF
            {
                LLVM.SetTarget(mod, Marshal.PtrToStringAnsi(LLVM.GetDefaultTargetTriple()) + "-elf");
            }

            var options = new LLVMMCJITCompilerOptions();
            var optionsSize = (4 * sizeof(int)) + IntPtr.Size; // LLVMMCJITCompilerOptions has 4 ints and a pointer

            LLVM.DumpModule(mod);

            LLVM.InitializeMCJITCompilerOptions(out options, optionsSize);
            LLVM.CreateMCJITCompilerForModule(out engine, mod, out options, optionsSize, out error);

            var addMethod = (Add)Marshal.GetDelegateForFunctionPointer(LLVM.GetPointerToGlobal(engine, sum), typeof(Add));
            int result = addMethod();

            Console.WriteLine("Result of sum is: " + result);

            if (LLVM.WriteBitcodeToFile(mod, "sum.bc") != 0)
            {
                Console.WriteLine("error writing bitcode to file, skipping");
            }

            LLVM.DumpModule(mod);

            LLVM.DisposeBuilder(builder);
            LLVM.DisposeExecutionEngine(engine);
            Console.ReadKey();
        }
    }
}
Quuxplusone commented 9 years ago
Here is a C program, which does fail with the error:

LLVM ERROR: unsupported GC: shadow-stack

#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/BitWriter.h>

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
  LLVMModuleRef mod = LLVMModuleCreateWithName("my_module");

  LLVMTypeRef param_types[] = { LLVMInt32Type(), LLVMInt32Type() };
  LLVMTypeRef ret_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, 0);
  LLVMValueRef sum = LLVMAddFunction(mod, "sum", ret_type);

  LLVMBasicBlockRef entry = LLVMAppendBasicBlock(sum, "entry");

  LLVMBuilderRef builder = LLVMCreateBuilder();
  LLVMPositionBuilderAtEnd(builder, entry);
  LLVMValueRef tmp = LLVMBuildAdd(builder, LLVMGetParam(sum, 0), LLVMGetParam(sum, 1), "tmp");
  LLVMBuildRet(builder, tmp);

  char *error = NULL;
  LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
  LLVMDisposeMessage(error);

  LLVMExecutionEngineRef engine;
  error = NULL;

  LLVMLinkInMCJIT();
  LLVMInitializeX86Target();
  LLVMInitializeX86TargetInfo();
  LLVMInitializeX86TargetMC();
  LLVMInitializeX86AsmPrinter();

  LLVMSetGC(sum, "shadow-stack");

  if (LLVMCreateExecutionEngineForModule(&engine, mod, &error) != 0) {
    fprintf(stderr, "failed to create execution engine\n");
    abort();
  }
  if (error) {
    fprintf(stderr, "error: %s\n", error);
    LLVMDisposeMessage(error);
    exit(EXIT_FAILURE);
  }

  if (argc < 3) {
    fprintf(stderr, "usage: %s x y\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  long long x = strtoll(argv[1], NULL, 10);
  long long y = strtoll(argv[2], NULL, 10);

  LLVMGenericValueRef args[] = {
    LLVMCreateGenericValueOfInt(LLVMInt32Type(), x, 0),
    LLVMCreateGenericValueOfInt(LLVMInt32Type(), y, 0)
  };
  LLVMGenericValueRef res = LLVMRunFunction(engine, sum, 2, args);
  printf("%d\n", (int)LLVMGenericValueToInt(res, 0));

  // Write out bitcode to file
  if (LLVMWriteBitcodeToFile(mod, "sum.bc") != 0) {
    fprintf(stderr, "error writing bitcode to file, skipping\n");
  }

  LLVMDisposeBuilder(builder);
  LLVMDisposeExecutionEngine(engine);
}
Quuxplusone commented 9 years ago
Here is a C++ version, with a little bit of C bindings mixed, but I don't think
it has anything to do with the binding. The dictionary that has gc strategies
seems to be empty.

// Generated by llvm2cpp - DO NOT MODIFY!

#include <llvm/Pass.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/CallingConv.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/IRPrintingPasses.h>
#include <llvm/IR/InlineAsm.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/MathExtras.h>
#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/BitWriter.h>
#include <algorithm>
using namespace llvm;

Module* makeLLVMModule();

int main(int argc, char**argv) {
  Module* Mod = makeLLVMModule();

  LLVMDumpModule(wrap(Mod));

  LLVMLinkInMCJIT();
  LLVMInitializeX86Target();
  LLVMInitializeX86TargetInfo();
  LLVMInitializeX86TargetMC();
  LLVMInitializeX86AsmPrinter();

  LLVMExecutionEngineRef engine;

  LLVMMCJITCompilerOptions options;
  int optionsSize = (4 * sizeof(int)) + sizeof(int *); // LLVMMCJITCompilerOptions has 4 ints and a pointer

  LLVMInitializeMCJITCompilerOptions(&options, optionsSize);
  char** error;
  LLVMCreateMCJITCompilerForModule(&engine, wrap(Mod), &options, optionsSize, error);

  LLVMGetPointerToGlobal(engine, wrap(Mod->getFunction("sum")));

  return 0;
}

Module* makeLLVMModule() {
  // Module Construction
  Module* mod = new Module("C:/abc.bc", getGlobalContext());
  mod->setDataLayout("");
  mod->setTargetTriple("x86_64-ellcc-linux");

  // Type Definitions
  std::vector<Type*>FuncTy_0_args;
  FuncTy_0_args.push_back(IntegerType::get(mod->getContext(), 32));
  FuncTy_0_args.push_back(IntegerType::get(mod->getContext(), 32));
  FunctionType* FuncTy_0 = FunctionType::get(
    /*Result=*/IntegerType::get(mod->getContext(), 32),
    /*Params=*/FuncTy_0_args,
    /*isVarArg=*/false);

  // Function Declarations

  Function* func_sum = mod->getFunction("sum");
  if (!func_sum) {
    func_sum = Function::Create(
      /*Type=*/FuncTy_0,
      /*Linkage=*/GlobalValue::ExternalLinkage,
      /*Name=*/"sum", mod);
    func_sum->setCallingConv(CallingConv::C);
    func_sum->setGC("shadow-stack");
  }
  AttributeSet func_sum_PAL;
  {
    SmallVector<AttributeSet, 4> Attrs;
    AttributeSet PAS;
    {
      AttrBuilder B;
      B.addAttribute(Attribute::NoUnwind);
      B.addAttribute(Attribute::ReadNone);
      PAS = AttributeSet::get(mod->getContext(), ~0U, B);
    }

    Attrs.push_back(PAS);
    func_sum_PAL = AttributeSet::get(mod->getContext(), Attrs);

  }
  func_sum->setAttributes(func_sum_PAL);

  // Global Variable Declarations

  // Constant Definitions

  // Global Variable Definitions

  // Function Definitions

  // Function: sum (func_sum)
  {
    Function::arg_iterator args = func_sum->arg_begin();
    Value* int32_a = args++;
    int32_a->setName("a");
    Value* int32_b = args++;
    int32_b->setName("b");

    BasicBlock* label_entry = BasicBlock::Create(mod->getContext(), "entry", func_sum, 0);

    // Block entry (label_entry)
    BinaryOperator* int32_add = BinaryOperator::Create(Instruction::Add, int32_b, int32_a, "add", label_entry);
    ReturnInst::Create(mod->getContext(), int32_add, label_entry);

  }

  return mod;
}
Quuxplusone commented 9 years ago

Attached linkShadowStackGC.diff (1109 bytes, text/plain): Patch for exposing llvm::linkShadowStackGC()