github.com/notti/go-dynamic@v0.0.0-20190619201224-fc443047424c/internal/ffi/call_386.go (about) 1 package ffi 2 3 import ( 4 "unsafe" 5 ) 6 7 // 386 cdecl calling conventions: http://www.sco.com/developers/devspecs/abi386-4.pdf 8 // Pass everything on the stack in right to left order 9 // Return is in AX (and DX for 64 bit) or F0 for floats 10 // according to libffi clang might require the caller to properly (sign)extend stuff - so we do that 11 // structs are not supported for now (neither as argument nor as return value) - but this is not hard to do 12 13 type argtype uint16 14 15 const ( 16 type32 argtype = 0 // movl 64 bit 17 type16 argtype = 1 // movw 16 bit 18 type8 argtype = 2 // movb 8 bit 19 typeDouble argtype = 3 // fld 64 bit (only return) 20 typeFloat argtype = 4 // movss 32 bit (only return) 21 type64 argtype = 5 // 2x movl (only return) 22 typeUnused argtype = 0xFFFF 23 ) 24 25 type argument struct { 26 offset uint16 27 t argtype 28 } 29 30 // spec a wrapper specifcation with instructions on how to place arguments into registers/stack 31 type spec struct { 32 wrapper uintptr // pointer to callWrapper() 33 fn uintptr // pointer to the C-function 34 stack []argument 35 ret argument 36 } 37 38 func callWrapper() 39 40 // MakeSpec builds a call specification for the given arguments 41 func MakeSpec(fn uintptr, fun interface{}) error { 42 fptr, arguments, ret, err := stackFields(fun) 43 if err != nil { 44 return err 45 } 46 47 spec := new(spec) 48 spec.wrapper = funcPC(callWrapper) 49 spec.fn = fn 50 spec.ret.t = typeUnused 51 52 // on 386 we can't directly pass the arguments to the function :( 53 // -> go aligns arguments like a struct and 386 aligns every argument to 4 byte boundaries 54 for _, arg := range arguments { 55 switch arg.size { 56 case 8: 57 spec.stack = append(spec.stack, argument{uint16(arg.offset), type32}) 58 spec.stack = append(spec.stack, argument{uint16(arg.offset + 4), type32}) 59 case 4: 60 spec.stack = append(spec.stack, argument{uint16(arg.offset), type32}) 61 case 2: 62 spec.stack = append(spec.stack, argument{uint16(arg.offset), type16}) 63 case 1: 64 spec.stack = append(spec.stack, argument{uint16(arg.offset), type8}) 65 } 66 } 67 68 if ret.c != classVoid { 69 var t argtype 70 switch ret.c { 71 case classInt, classUint: 72 switch ret.size { 73 case 8: 74 t = type64 75 case 4: 76 t = type32 77 case 2: 78 t = type16 79 case 1: 80 t = type8 81 } 82 case classFloat: 83 switch ret.size { 84 case 8: 85 t = typeDouble 86 case 4: 87 t = typeFloat 88 } 89 } 90 91 spec.ret.t = t 92 spec.ret.offset = uint16(ret.offset) 93 } 94 95 *(*unsafe.Pointer)(fptr) = unsafe.Pointer(spec) 96 97 return nil 98 }