Last active
August 19, 2018 17:21
-
-
Save aguinet/5d359476d77ff69a7daafa51ad005ea8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import struct | |
import pydffi | |
import llvmlite.ir as ll | |
FFI = pydffi.FFI() | |
CU = FFI.cdef(''' | |
#include <stdbool.h> | |
typedef struct { | |
bool b; | |
int i; | |
short s; | |
} A; | |
typedef struct { | |
bool b; | |
A a; | |
} B; | |
''') | |
A = CU.types.A | |
B = CU.types.B | |
I8Ty = ll.IntType(8) | |
I8PtrTy = ll.PointerType(I8Ty) | |
I32Ty = ll.IntType(32) | |
M = ll.Module() | |
# From http://code.activestate.com/recipes/577514-chek-if-a-number-is-a-power-of-two/ | |
def isPower2(num): | |
return num != 0 and ((num & (num - 1)) == 0) | |
def llvm_alloc_ty(IRB, Ty): | |
Ret = IRB.alloca(ll.ArrayType(I8Ty, Ty.size)) | |
return Ret | |
def get_memcpy(IRB): | |
return IRB.module.declare_intrinsic('llvm.memcpy', [I8PtrTy, I8PtrTy, I32Ty]) | |
def llvm_set_field(IRB, Ptr, Field, Obj): | |
Ty = Field.type | |
Ptr = IRB.bitcast(Ptr, I8PtrTy) | |
Ptr = IRB.gep(Ptr, [ll.Constant(I32Ty, Field.offset)]) | |
Size = pydffi.sizeof(Obj) | |
Data = pydffi.view_as_bytes(Obj) | |
if len(Data) != Size: | |
raise ValueError("sizeof(Obj) should be equals to sizeof(Field.type)") | |
SizesFormat = {1: "B", 2: "H", 4: "I", 8: "Q"} | |
Format = SizesFormat.get(Size, None) | |
if not Format is None: | |
# If size is a multiple of two and < 64-bit, use a scalar to store the value | |
v = struct.unpack(Format, Data)[0] | |
DataTy = ll.IntType(Size*8) | |
Ptr = IRB.bitcast(Ptr, ll.PointerType(DataTy)) | |
IRB.store(ll.Constant(DataTy, v), Ptr) | |
else: | |
# If this is not the case, store the value in a GV and copy it! | |
DataTy = ll.ArrayType(I8Ty, Size) | |
GVData = ll.GlobalVariable(IRB.module, DataTy, "dffi_cst") | |
GVData.global_constant = True | |
GVData.initializer = ll.Constant(DataTy, [int(v) for v in Data]) | |
memcpy = get_memcpy(IRB) | |
IRB.call(memcpy, [Ptr, IRB.bitcast(GVData, I8PtrTy), ll.Constant(I32Ty, Size), ll.Constant(I32Ty, Ty.align), ll.Constant(ll.IntType(1),0)]) | |
def llvm_get_field(IRB, Ptr, OutPtr, Field): | |
Ty = Field.type | |
Ptr = IRB.bitcast(Ptr, I8PtrTy) | |
Ptr = IRB.gep(Ptr, [ll.Constant(I32Ty, Field.offset)]) | |
Size = Ty.size | |
if Size <= 8 and isPower2(Size): | |
DataTy = ll.IntType(Size*8) | |
DataPtrTy = ll.PointerType(DataTy) | |
Ptr = IRB.bitcast(Ptr, DataPtrTy) | |
IRB.store(IRB.load(Ptr), IRB.bitcast(OutPtr, DataPtrTy)) | |
else: | |
DataTy = ll.ArrayType(I8Ty, Size) | |
memcpy = get_memcpy(IRB) | |
IRB.call(memcpy, [IRB.bitcast(OutPtr, I8PtrTy), Ptr, ll.Constant(I32Ty, Size), ll.Constant(I32Ty, Ty.align), ll.Constant(ll.IntType(1),0)]) | |
# Generate a function that sets "A.i" to 10 | |
FTy = ll.FunctionType(ll.VoidType(), [I8PtrTy]) | |
F = ll.Function(M, FTy, name='A_set_i_10') | |
BB = F.append_basic_block() | |
IRB = ll.IRBuilder() | |
IRB.position_at_end(BB) | |
llvm_set_field(IRB, F.args[0], A.i, FFI.Int(4)) | |
IRB.ret_void() | |
# Generate a function that gather "A.i" | |
FTy = ll.FunctionType(I32Ty, [I8PtrTy]) | |
F = ll.Function(M, FTy, name='A_get_i') | |
BB = F.append_basic_block() | |
IRB = ll.IRBuilder() | |
IRB.position_at_end(BB) | |
Ret = IRB.alloca(I32Ty) | |
llvm_get_field(IRB, F.args[0], Ret, A.i) | |
IRB.ret(IRB.load(Ret)) | |
Av = A(b=1,i=0x41414141,s=0x4242) | |
# Generate a function that sets "B.a" to Av | |
FTy = ll.FunctionType(ll.VoidType(), [I8PtrTy]) | |
F = ll.Function(M, FTy, name='B_set_a') | |
BB = F.append_basic_block() | |
IRB = ll.IRBuilder() | |
IRB.position_at_end(BB) | |
llvm_set_field(IRB, F.args[0], B.a, Av) | |
IRB.ret_void() | |
# Generate a function that gather "B.a" | |
FTy = ll.FunctionType(ll.VoidType(), [I8PtrTy, I8PtrTy]) | |
F = ll.Function(M, FTy, name='B_get_a') | |
BB = F.append_basic_block() | |
IRB = ll.IRBuilder() | |
IRB.position_at_end(BB) | |
llvm_get_field(IRB, F.args[0], F.args[1], B.a) | |
IRB.ret_void() | |
print(M) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output: