gitee.com/quant1x/num@v0.3.2/asm/asm2plan9/yasm.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "strings" 10 "unicode" 11 ) 12 13 /////////////////////////////////////////////////////////////////////////////// 14 // 15 // Y A S M S U P P O R T 16 // 17 /////////////////////////////////////////////////////////////////////////////// 18 19 // 20 // yasm-assemble-disassemble-roundtrip-sse.txt 21 // 22 // franks-mbp:sse frankw$ more assembly.asm 23 // [bits 64] 24 // 25 // VPXOR YMM4, YMM2, YMM3 ; X4: Result 26 // franks-mbp:sse frankw$ yasm assembly.asm 27 // franks-mbp:sse frankw$ hexdump -C assembly 28 // 00000000 c5 ed ef e3 |....| 29 // 00000004 30 // franks-mbp:sse frankw$ echo 'lbl: db 0xc5, 0xed, 0xef, 0xe3' | yasm -f elf - -o assembly.o 31 // franks-mbp:sse frankw$ gobjdump -d -M intel assembly.o 32 // 33 // assembly.o: file format elf32-i386 34 // 35 // 36 // Disassembly of section .text: 37 // 38 // 00000000 <.text>: 39 // 0: c5 ed ef e3 vpxor ymm4,ymm2,ymm3 40 41 func yasm(instructions []Instruction) error { 42 for i, ins := range instructions { 43 assembled, opcodes, err := yasmSingle(ins.instruction, ins.lineno, ins.commentPos, ins.inDefine) 44 if err != nil { 45 return err 46 } 47 instructions[i].assembled = assembled 48 instructions[i].opcodes = make([]byte, len(opcodes)) 49 copy(instructions[i].opcodes[:], opcodes) 50 } 51 return nil 52 } 53 54 func yasmSingle(instr string, lineno, commentPos int, inDefine bool) (string, []byte, error) { 55 56 instrFields := strings.Split(instr, "/*") 57 content := []byte("[bits 64]\n" + instrFields[0]) 58 tmpfile, err := ioutil.TempFile("", "asm2plan9s") 59 if err != nil { 60 return "", nil, err 61 } 62 63 if _, err := tmpfile.Write(content); err != nil { 64 return "", nil, err 65 } 66 if err := tmpfile.Close(); err != nil { 67 return "", nil, err 68 } 69 70 asmFile := tmpfile.Name() + ".asm" 71 objFile := tmpfile.Name() + ".obj" 72 os.Rename(tmpfile.Name(), asmFile) 73 74 defer os.Remove(asmFile) // clean up 75 defer os.Remove(objFile) // clean up 76 77 app := "yasm" 78 79 arg0 := "-o" 80 arg1 := objFile 81 arg2 := asmFile 82 83 cmd := exec.Command(app, arg0, arg1, arg2) 84 cmb, err := cmd.CombinedOutput() 85 if err != nil { 86 if len(string(cmb)) == 0 { // command invocation failed 87 return "", nil, errors.New("exec error: YASM not installed?") 88 } 89 yasmErrs := strings.Split(string(cmb)[len(asmFile)+1:], ":") 90 yasmErr := strings.Join(yasmErrs[1:], ":") 91 return "", nil, errors.New(fmt.Sprintf("YASM error (line %d for '%s'):", lineno+1, strings.TrimSpace(instr)) + yasmErr) 92 } 93 94 return toPlan9sYasm(objFile, instr, commentPos, inDefine) 95 } 96 97 func toPlan9sYasm(objFile, instr string, commentPos int, inDefine bool) (string, []byte, error) { 98 opcodes, err := ioutil.ReadFile(objFile) 99 if err != nil { 100 return "", nil, err 101 } 102 103 s, err := toPlan9s(opcodes, instr, commentPos, inDefine) 104 return s, opcodes, err 105 } 106 107 func toPlan9s(opcodes []byte, instr string, commentPos int, inDefine bool) (string, error) { 108 sline := " " 109 i := 0 110 // First do QUADs (as many as needed) 111 for ; len(opcodes) >= 8; i++ { 112 if i != 0 { 113 sline += "; " 114 } 115 sline += fmt.Sprintf("QUAD $0x%02x%02x%02x%02x%02x%02x%02x%02x", opcodes[7], opcodes[6], opcodes[5], opcodes[4], opcodes[3], opcodes[2], opcodes[1], opcodes[0]) 116 117 opcodes = opcodes[8:] 118 } 119 // Then do LONGs (as many as needed) 120 for ; len(opcodes) >= 4; i++ { 121 if i != 0 { 122 sline += "; " 123 } 124 sline += fmt.Sprintf("LONG $0x%02x%02x%02x%02x", opcodes[3], opcodes[2], opcodes[1], opcodes[0]) 125 126 opcodes = opcodes[4:] 127 } 128 129 // Then do a WORD (if needed) 130 if len(opcodes) >= 2 { 131 132 if i != 0 { 133 sline += "; " 134 } 135 sline += fmt.Sprintf("WORD $0x%02x%02x", opcodes[1], opcodes[0]) 136 137 i++ 138 opcodes = opcodes[2:] 139 } 140 141 // And close with a BYTE (if needed) 142 if len(opcodes) == 1 { 143 if i != 0 { 144 sline += "; " 145 } 146 sline += fmt.Sprintf("BYTE $0x%02x", opcodes[0]) 147 148 i++ 149 opcodes = opcodes[1:] 150 } 151 152 if inDefine { 153 if commentPos > commentPos-2-len(sline) { 154 if commentPos-2-len(sline) > 0 { 155 sline += strings.Repeat(" ", commentPos-2-len(sline)) 156 } 157 } else { 158 sline += " " 159 } 160 sline += `\ ` 161 } else { 162 if commentPos > len(sline) { 163 if commentPos-len(sline) > 0 { 164 sline += strings.Repeat(" ", commentPos-len(sline)) 165 } 166 } else { 167 sline += " " 168 } 169 } 170 171 if instr != "" { 172 sline += "//" + instr 173 } 174 175 return strings.TrimRightFunc(sline, unicode.IsSpace), nil 176 }