forked from minio/asm2plan9s
-
Notifications
You must be signed in to change notification settings - Fork 0
/
asm2plan9s_arm64.go
123 lines (100 loc) · 3.22 KB
/
asm2plan9s_arm64.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
* Minio Cloud Storage, (C) 2016-2017 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"regexp"
"strings"
)
func as(instructions []Instruction) error {
// First to yasm (will return error when not installed)
e := yasm(instructions)
if e == nil {
return e
}
// Try gas if yasm not installed
return gas(instructions)
}
func gas(instructions []Instruction) error {
for i, ins := range instructions {
assembled, opcodes, err := asSingle(ins.instruction, ins.lineno, ins.commentPos, ins.inDefine)
if err != nil {
return err
}
instructions[i].assembled = assembled
instructions[i].opcodes = make([]byte, len(opcodes))
copy(instructions[i].opcodes[:], opcodes)
}
return nil
}
func asSingle(instr string, lineno, commentPos int, inDefine bool) (string, []byte, error) {
instrFields := strings.Split(instr, "/*")
content := []byte(instrFields[0] + "\n")
tmpfile, err := ioutil.TempFile("", "asm2plan9s")
if err != nil {
return "", nil, err
}
if _, err := tmpfile.Write(content); err != nil {
return "", nil, err
}
if err := tmpfile.Close(); err != nil {
return "", nil, err
}
asmFile := tmpfile.Name() + ".asm"
lisFile := tmpfile.Name() + ".lis"
objFile := tmpfile.Name() + ".obj"
os.Rename(tmpfile.Name(), asmFile)
defer os.Remove(asmFile) // clean up
defer os.Remove(lisFile) // clean up
defer os.Remove(objFile) // clean up
// as -march=armv8-a+crypto -o first.out -al=first.lis first.s
app := "as"
arg0 := "-march=armv8.2-a+sve" // See https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/ARM-Options.html
arg1 := "-o"
arg2 := objFile
arg3 := fmt.Sprintf("-al=%s", lisFile)
arg4 := asmFile
cmd := exec.Command(app, arg0, arg1, arg2, arg3, arg4)
fmt.Printf("cmd: %v\n", cmd)
cmb, err := cmd.CombinedOutput()
if err != nil {
asmErrs := strings.Split(string(cmb)[len(asmFile)+1:], ":")
asmErr := strings.Join(asmErrs[1:], ":")
return "", nil, errors.New(fmt.Sprintf("GAS error (line %d for '%s'):", lineno+1, strings.TrimSpace(instr)) + asmErr)
}
return toPlan9sArm(lisFile, instr)
}
func toPlan9sArm(listFile, instr string) (string, []byte, error) {
var r = regexp.MustCompile(`^\s+\d+\s+\d+\s+([0-9a-fA-F]+)`)
outputLines, err := readLines(listFile, nil)
if err != nil {
return "", nil, err
}
lastLine := outputLines[len(outputLines)-1]
sline := " "
if match := r.FindStringSubmatch(lastLine); len(match) > 1 {
sline += fmt.Sprintf("WORD $0x%s%s%s%s", strings.ToLower(match[1][6:8]), strings.ToLower(match[1][4:6]), strings.ToLower(match[1][2:4]), strings.ToLower(match[1][0:2]))
} else {
return "", nil, errors.New("regexp failed")
}
sline += " //" + instr
// fmt.Println(sline)
return sline, nil, nil
}