gitee.com/quant1x/num@v0.3.2/asm/asm2plan9/asm2plan9s_amd64.go (about) 1 /* 2 * Minio Cloud Storage, (C) 2016-2017 Minio, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "encoding/hex" 21 "errors" 22 "fmt" 23 "io/ioutil" 24 "os" 25 "os/exec" 26 "regexp" 27 "strconv" 28 "strings" 29 ) 30 31 // as: assemble instruction by either invoking yasm or gas 32 func as(instructions []Instruction) error { 33 34 // First to yasm (will return error when not installed) 35 e := yasm(instructions) 36 if e == nil { 37 return e 38 } 39 // Try gas if yasm not installed 40 return gas(instructions) 41 } 42 43 // See below for YASM support (older, no AVX512) 44 45 /////////////////////////////////////////////////////////////////////////////// 46 // 47 // G A S S U P P O R T 48 // 49 /////////////////////////////////////////////////////////////////////////////// 50 51 // 52 // frank@hemelmeer: asm2plan9s$ more example.s 53 // .intel_syntax noprefix 54 // 55 // VPANDQ ZMM0, ZMM1, ZMM2 56 // 57 // frank@hemelmeer: asm2plan9s$ as -o example.o -al=example.lis example.s 58 // frank@hemelmeer: asm2plan9s$ more example.lis 59 // GAS LISTING example.s page 1 60 // 1 .intel_syntax noprefix 61 // 2 62 // 3 0000 62F1F548 VPANDQ ZMM0, ZMM1, ZMM2 63 // 3 DBC2 64 // 65 66 func gas(instructions []Instruction) error { 67 68 tmpfile, err := ioutil.TempFile("", "asm2plan9s") 69 if err != nil { 70 return err 71 } 72 if _, err := tmpfile.Write([]byte(fmt.Sprintf(".intel_syntax noprefix\n"))); err != nil { 73 return err 74 } 75 76 for _, instr := range instructions { 77 instrFields := strings.Split(instr.instruction, "/*") 78 if len(instrFields) == 1 { 79 instrFields = strings.Split(instr.instruction, ";") // try again with ; separator 80 } 81 content := []byte(instrFields[0] + "\n") 82 83 if _, err := tmpfile.Write([]byte(content)); err != nil { 84 return err 85 } 86 } 87 88 if err := tmpfile.Close(); err != nil { 89 return err 90 } 91 92 asmFile := tmpfile.Name() + ".asm" 93 lisFile := tmpfile.Name() + ".lis" 94 objFile := tmpfile.Name() + ".obj" 95 os.Rename(tmpfile.Name(), asmFile) 96 97 defer os.Remove(asmFile) // clean up 98 defer os.Remove(lisFile) // clean up 99 defer os.Remove(objFile) // clean up 100 101 // as -o example.o -al=example.lis example.s 102 app := "as" 103 104 arg0 := "-o" 105 arg1 := objFile 106 arg2 := fmt.Sprintf("-aln=%s", lisFile) 107 arg3 := asmFile 108 109 cmd := exec.Command(app, arg0, arg1, arg2, arg3) 110 cmb, err := cmd.CombinedOutput() 111 if err != nil { 112 asmErrs := strings.Split(string(cmb)[len(asmFile)+1:], ":") 113 asmErr := strings.Join(asmErrs[1:], ":") 114 // TODO: Fix proper error reporting 115 lineno := -1 116 instr := "TODO: fix" 117 return errors.New(fmt.Sprintf("GAS error (line %d for '%s'):", lineno+1, strings.TrimSpace(instr)) + asmErr) 118 } 119 120 opcodes, err := toPlan9sGas(lisFile) 121 if err != nil { 122 return err 123 } 124 125 if len(instructions) != len(opcodes) { 126 panic("Unequal length between instructions to be assembled and opcodes returned") 127 } 128 129 for i, opcode := range opcodes { 130 assembled, err := toPlan9s(opcode, instructions[i].instruction, instructions[i].commentPos, instructions[i].inDefine) 131 if err != nil { 132 return err 133 } 134 instructions[i].assembled = assembled 135 instructions[i].opcodes = make([]byte, len(opcode)) 136 copy(instructions[i].opcodes, opcode) 137 } 138 139 return nil 140 } 141 142 func toPlan9sGas(listFile string) ([][]byte, error) { 143 144 opcodes := make([][]byte, 0, 10) 145 146 outputLines, err := readLines(listFile, nil) 147 if err != nil { 148 return opcodes, err 149 } 150 151 var regexpHeader = regexp.MustCompile(`^\s+(\d+)\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)`) 152 var regexpSequel = regexp.MustCompile(`^\s+(\d+)\s+([0-9a-fA-F]+)`) 153 154 lineno, opcode := -1, make([]byte, 0, 10) 155 156 for _, line := range outputLines { 157 158 if match := regexpHeader.FindStringSubmatch(line); len(match) > 2 { 159 l, e := strconv.Atoi(match[1]) 160 if e != nil { 161 panic(e) 162 } 163 if lineno != -1 { 164 opcodes = append(opcodes, opcode) 165 } 166 lineno = l 167 opcode = make([]byte, 0, 10) 168 b, e := hex.DecodeString(match[2]) 169 if e != nil { 170 panic(e) 171 } 172 opcode = append(opcode, b...) 173 } else if match := regexpSequel.FindStringSubmatch(line); len(match) > 2 { 174 l, e := strconv.Atoi(match[1]) 175 if e != nil { 176 panic(e) 177 } 178 if l != lineno { 179 panic("bad line number)") 180 } 181 b, e := hex.DecodeString(match[2]) 182 if e != nil { 183 panic(e) 184 } 185 opcode = append(opcode, b...) 186 } 187 } 188 189 opcodes = append(opcodes, opcode) 190 191 return opcodes, nil 192 }