Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # This program takes a string as a command line argument and produces an executable
- # that prints that string. It uses llvmlite to create an object file and gcc to perform
- # the linking.
- import llvmlite.binding as llvm
- import llvmlite.ir as ll
- import sys
- import subprocess
- # int main()
- main_type = ll.FunctionType(ll.IntType(32), [])
- # int puts(char*);
- puts_type = ll.FunctionType(ll.IntType(32), [ll.PointerType(ll.IntType(8))])
- module = ll.Module()
- # This will be a declaration because we never add a body. We'll need to link against
- # libc to get access to the puts function (gcc will do this automatically)
- puts = ll.Function(module, puts_type, name='puts')
- main = ll.Function(module, main_type, name='main')
- bb_entry = main.append_basic_block()
- builder = ll.IRBuilder()
- builder.position_at_end(bb_entry)
- string = sys.argv[1]
- char_array_type = ll.ArrayType(ll.IntType(8), len(string) + 1)
- str_constant = ll.GlobalVariable(module, char_array_type, name = "str")
- str_constant.global_constant = True
- # Initialize the global char array with a 0-terminated bytearray created from the command line argument
- str_constant.initializer = ll.Constant(char_array_type, bytearray(string + "\0", encoding = "utf-8"))
- zero = ll.Constant(ll.IntType(32), 0)
- # Get a pointer to the first element of the char array because puts wants a pointer, not an array.
- # In C this happens automatically (array decay), but in LLVM we need to do this manually with GEP (get element pointer).
- char_pointer = builder.gep(str_constant, [zero, zero])
- builder.call(puts, [char_pointer])
- builder.ret(zero)
- llvm.initialize()
- llvm.initialize_native_asmprinter()
- llvm.initialize_native_target()
- target = llvm.Target.from_default_triple()
- target_machine = target.create_target_machine()
- with open("output.o", "wb") as o:
- # The only way I could find to turn an llvmlite.ir.Module into a llvmlite.bindings.ModuleRef
- # is by creating an LLVM-assembly string and parsing it. There might be a better way, but I don't know.
- o.write(target_machine.emit_object(llvm.parse_assembly(str(module))))
- # Invoke gcc to do the linking
- subprocess.call(["gcc", "output.o", "-o", "output"])
Add Comment
Please, Sign In to add comment