Long story short, I wanted to use C as a scripting language and in a portable manner so I created a register-based, JITless VM to accomplish this.
Notice that compiling C code is easy. But making an optimizing compiler is hard. See this answer.
So, you probably don't care of performance (since you want to use C for scripting purposes), and I guess that you'll focus your optimization efforts inside your VM. Then coding a C compiler is in principle easy (look into tinycc, also the TinyCC wikipedia, for a good example; and also into nwcc). But there is still the issue of what undefined behavior means in your implementation.
I believe that using C as a scripting language is a mistake (but see this). You'll better use some higher level semantics (and you might still keep a C like syntax). In particular, I believe that a scripting language should have few undefined behavior (ideally none). In practice, you don't want to crash your VM with a faulty script.
You don't need LLVM and you don't need GCC for your particular purpose (both are overkill). You do need some C standard library. Parsing C (or some reasonable subset of it) is quite simple, and writing a naïve C compiler is a simple exercise (what is difficult is making an optimizing compiler, and you probably don't need any).
You could however use libgccjit or LLVM (or asmjit or GNU lightning) in your VM implementation for JIT-ing purposes (but that is not the question you are asking).
BTW, you might simply (if your VM has the same word size, alignment constraints, and endianness than your native machine, or as some target machine supported by some existing GCC cross-compiler) prototype your C compiler as a GCC plugin working on Gimple. In practice, most of Gimple is quite stable (perhaps more stable than the internals of LLVM).