github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/builder.go (about) 1 package assembler 2 3 import ( 4 "fmt" 5 "runtime" 6 7 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 8 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/asm/arch" 9 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/obj" 10 ) 11 12 var a, ctxt = func() (*arch.Arch, *obj.Link) { 13 a := arch.Set(runtime.GOARCH, false) 14 ctxt := obj.Linknew(a.LinkArch) 15 ctxt.DiagFunc = func(in string, args ...interface{}) { 16 panic(fmt.Sprintf(in, args...)) 17 } 18 a.Init(ctxt) 19 return a, ctxt 20 }() 21 22 23 type Builder struct { 24 arch *arch.Arch 25 26 first *Instruction 27 last *Instruction 28 29 30 labels map[string]*Instruction 31 } 32 33 type Instruction struct { 34 *obj.Prog 35 label string 36 jumpDestLabel string 37 link *Instruction 38 placeholderFor []byte 39 } 40 41 42 func (b *Builder) NewInstruction() *Instruction { 43 return &Instruction{Prog: ctxt.NewProg()} 44 } 45 46 func (b *Builder) insertInstruction(inst *Instruction) { 47 if b.first == nil { 48 b.first = inst 49 b.last = inst 50 } else { 51 b.last.link = inst 52 b.last = inst 53 } 54 } 55 56 57 58 func (b *Builder) AddInstructions(p *Instruction, instructions ...*Instruction) rookoutErrors.RookoutError { 59 insts := []*Instruction{p} 60 insts = append(insts, instructions...) 61 62 for _, inst := range insts { 63 if inst.label != "" { 64 if _, ok := b.labels[inst.label]; ok { 65 return rookoutErrors.NewLabelAlreadyExists(inst.label) 66 } 67 68 b.labels[inst.label] = inst 69 } 70 71 b.insertInstruction(inst) 72 } 73 74 return nil 75 } 76 77 func (b *Builder) fixup() rookoutErrors.RookoutError { 78 for inst := b.first; inst != nil; inst = inst.link { 79 if inst.link != nil { 80 inst.Prog.Link = inst.link.Prog 81 } 82 83 if inst.placeholderFor != nil { 84 if b.arch.Arch.Name == "arm64" && len(inst.placeholderFor)%4 != 0 { 85 return rookoutErrors.NewInvalidBytes(inst.placeholderFor) 86 } 87 88 progAfterPlaceholder := inst.Prog.Link 89 curProg := inst.Prog 90 91 for i := 0; i < len(inst.placeholderFor)-placeholderLen; i += placeholderLen { 92 curProg.Link = b.placeholderProg() 93 curProg = curProg.Link 94 } 95 curProg.Link = progAfterPlaceholder 96 continue 97 } 98 99 if inst.jumpDestLabel != "" { 100 dest, ok := b.labels[inst.jumpDestLabel] 101 if !ok { 102 return rookoutErrors.NewInvalidJumpDest(inst.jumpDestLabel) 103 } 104 105 inst.To.Val = dest.Prog 106 } 107 } 108 109 return nil 110 } 111 112 func (b *Builder) replacePlaceholders(assembled []byte) { 113 for inst := b.first; inst != nil; inst = inst.link { 114 if inst.placeholderFor != nil { 115 copy(assembled[inst.Pc:], inst.placeholderFor) 116 } 117 } 118 } 119 120 121 func (b *Builder) Assemble() ([]byte, rookoutErrors.RookoutError) { 122 err := b.fixup() 123 if err != nil { 124 return nil, err 125 } 126 127 var funcInfo interface{} = &obj.FuncInfo{ 128 Text: b.first.Prog, 129 } 130 s := &obj.LSym{ 131 Extra: &funcInfo, 132 } 133 134 err = func() (err rookoutErrors.RookoutError) { 135 defer func() { 136 if r := recover(); r != nil { 137 err = rookoutErrors.NewFailedToAssemble(r) 138 } 139 }() 140 141 b.arch.Assemble(ctxt, s, ctxt.NewProg) 142 return nil 143 }() 144 if err != nil { 145 return nil, err 146 } 147 148 assembled := s.P 149 150 151 if b.arch.Arch.Name == "arm64" { 152 for string(assembled[len(assembled)-4:]) == "\x00\x00\x00\x00" { 153 assembled = assembled[:len(assembled)-4] 154 } 155 } 156 157 b.replacePlaceholders(assembled) 158 return assembled, nil 159 } 160 161 162 func NewBuilder() *Builder { 163 builder := &Builder{ 164 arch: a, 165 labels: make(map[string]*Instruction), 166 } 167 168 169 if runtime.GOARCH == "arm64" { 170 builder.AddInstructions( 171 builder.PsuedoNop(), 172 ) 173 } 174 return builder 175 } 176 177 func (b *Builder) placeholderProg() *obj.Prog { 178 return b.Inst(placeholderOp, NoArg, NoArg).Prog 179 } 180 181 func (i *Instruction) String() string { 182 if i.label != "" { 183 return i.label + ":" 184 } 185 s := i.Prog.String() 186 if i.jumpDestLabel != "" { 187 return s + " " + i.jumpDestLabel 188 } 189 return s 190 }