github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/lift/x86/gep.go (about) 1 package x86 2 3 import ( 4 "fmt" 5 6 "github.com/llir/llvm/ir" 7 "github.com/llir/llvm/ir/constant" 8 "github.com/llir/llvm/ir/types" 9 "github.com/llir/llvm/ir/value" 10 ) 11 12 // getElementPtr returns a pointer to the LLVM IR value located at the specified 13 // offset from the source value. 14 func (f *Func) getElementPtr(src value.Value, offset uint64) *ir.InstGetElementPtr { 15 dbg.Println("offset:", offset) 16 srcType, ok := src.Type().(*types.PointerType) 17 if !ok { 18 panic(fmt.Errorf("invalid source address type; expected *types.PointerType, got %T", src.Type())) 19 } 20 elem := srcType.ElemType 21 e := elem 22 total := uint64(0) 23 var indices []value.Value 24 // n specifies a byte offset into an integer element. 25 var n uint64 26 loop: 27 for i := int64(0); ; i++ { 28 if total > offset { 29 panic("unreachable; or at least should be :)") 30 } 31 dbg.Println(" total:", total) 32 dbg.Println(" e:", e) 33 if i == 0 { 34 // Ignore checking the 0th index as it simply follows the pointer of 35 // src. 36 // 37 // ref: http://llvm.org/docs/GetElementPtr.html#why-is-the-extra-0-index-required 38 index := constant.NewInt(types.I64, 0) 39 indices = append(indices, index) 40 continue 41 } 42 switch t := e.(type) { 43 case *types.PointerType: 44 if total == offset { 45 break loop 46 } 47 // ref: http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep 48 panic("unable to index into element of pointer type; for more information, see http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep") 49 case *types.ArrayType: 50 elemSize := f.l.sizeOfType(t.ElemType) 51 j := int64(0) 52 for ; j < int64(t.Len); j++ { 53 if total+elemSize > offset { 54 break 55 } 56 total += elemSize 57 } 58 index := constant.NewInt(types.I64, j) 59 indices = append(indices, index) 60 e = t.ElemType 61 case *types.StructType: 62 j := int64(0) 63 for ; j < int64(len(t.Fields)); j++ { 64 fieldSize := f.l.sizeOfType(t.Fields[j]) 65 if total+fieldSize > offset { 66 break 67 } 68 total += fieldSize 69 } 70 index := constant.NewInt(types.I64, j) 71 indices = append(indices, index) 72 e = t.Fields[j] 73 case *types.IntType: 74 if total == offset { 75 break loop 76 } 77 warn.Printf("indexing into the middle of an integer element at offset %d in type %v", total, src.Type()) 78 n = t.BitSize / 8 79 if total+n < offset { 80 panic(fmt.Errorf("unable to locate offset %d in type %v; indexing into integer type of byte size %d when at total offset %d", offset, src.Type(), n, total)) 81 } 82 break loop 83 default: 84 panic(fmt.Errorf("support for indexing element type %T not yet implemented", e)) 85 } 86 } 87 v := f.cur.NewGetElementPtr(src, indices...) 88 if n > 0 { 89 src := f.cur.NewLoad(v) 90 typ := types.NewPointer(types.NewArray(uint64(n), types.I8)) 91 tmp1 := f.cur.NewBitCast(src, typ) 92 indices := []value.Value{ 93 constant.NewInt(types.I64, 0), 94 constant.NewInt(types.I64, int64(offset)-int64(total)), 95 } 96 tmp2 := f.cur.NewGetElementPtr(tmp1, indices...) 97 return tmp2 98 } 99 return v 100 }