gitee.com/quant1x/num@v0.3.2/asm/c2goasm/constants.go (about) 1 /* 2 * Minio Cloud Storage, (C) 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 "fmt" 21 "regexp" 22 "strconv" 23 "strings" 24 ) 25 26 type Table struct { 27 Name string 28 Constants string 29 Labels []Label 30 } 31 32 func (t *Table) isPresent() bool { 33 return len(t.Name) > 0 34 } 35 36 type Label struct { 37 Name string 38 Offset uint 39 } 40 41 func getSingleNumber(line string) int64 { 42 43 if len(strings.Fields(line)) > 2 { 44 panic(fmt.Sprintf("Too many fields found: %d", len(strings.Fields(line)))) 45 } 46 field := strings.Fields(line)[1] 47 if len(strings.Split(field, ",")) > 1 { 48 panic(fmt.Sprintf("Unexpected comma found in field: %s", field)) 49 } 50 v, err := strconv.ParseInt(field, 10, 64) 51 if err != nil { 52 panic(fmt.Sprintf("Number parsing error: %v", err)) 53 } 54 return v 55 } 56 57 func getDualNumbers(line string) (int64, int64) { 58 59 if len(strings.Fields(line)) > 2 { 60 panic(fmt.Sprintf("Too many fields found: %d", len(strings.Fields(line)))) 61 } 62 field := strings.Fields(line)[1] 63 args := strings.Split(field, ",") 64 if len(args) > 2 { 65 panic(fmt.Sprintf("Too many commas found in field: %s", field)) 66 } 67 r1, err := strconv.ParseInt(args[0], 10, 64) 68 if err != nil { 69 panic(fmt.Sprintf("Number parsing error: %v", err)) 70 } 71 r2 := int64(0) 72 if len(args) > 1 { 73 r2, err = strconv.ParseInt(args[1], 10, 64) 74 if err != nil { 75 panic(fmt.Sprintf("Number parsing error: %v", err)) 76 } 77 } 78 79 return r1, r2 80 } 81 82 // Sanify check to detect labels with identical offsets 83 func sanityCheckLabels(labels []Label) { 84 85 for i := 0; i < len(labels)-1; i++ { 86 if labels[i].Offset == labels[i+1].Offset { 87 panic(fmt.Sprintf("Detected two labels with identical offsets: %v and %v", labels[i], labels[i+1])) 88 } 89 } 90 } 91 92 func defineTable(constants []string, tableName string) Table { 93 94 labels := []Label{} 95 bytes := make([]byte, 0, 1000) 96 97 for _, line := range constants { 98 99 line, _ = stripComments(line) 100 101 if strings.HasSuffix(line, ":") { 102 labels = append(labels, Label{Name: line[:len(line)-1], Offset: uint(len(bytes))}) 103 } else if strings.Contains(line, ".byte") { 104 v := getSingleNumber(line) 105 bytes = append(bytes, byte(v)) 106 } else if strings.Contains(line, ".short") { 107 v := getSingleNumber(line) 108 bytes = append(bytes, byte(v)) 109 bytes = append(bytes, byte(v>>8)) 110 } else if strings.Contains(line, ".long") { 111 v := getSingleNumber(line) 112 bytes = append(bytes, byte(v)) 113 bytes = append(bytes, byte(v>>8)) 114 bytes = append(bytes, byte(v>>16)) 115 bytes = append(bytes, byte(v>>24)) 116 } else if strings.Contains(line, ".quad") { 117 v, err := strconv.ParseInt(strings.Fields(line)[1], 10, 64) 118 if err != nil { 119 panic(fmt.Sprintf("Atoi error for .quad: %v", err)) 120 } 121 bytes = append(bytes, byte(v)) 122 bytes = append(bytes, byte(v>>8)) 123 bytes = append(bytes, byte(v>>16)) 124 bytes = append(bytes, byte(v>>24)) 125 bytes = append(bytes, byte(v>>32)) 126 bytes = append(bytes, byte(v>>40)) 127 bytes = append(bytes, byte(v>>48)) 128 bytes = append(bytes, byte(v>>56)) 129 } else if strings.Contains(line, ".align") || strings.Contains(line, ".p2align") { 130 fields := strings.FieldsFunc(line, func(c rune) bool { return c == ',' || c == ' ' || c == '\t' }) 131 if len(fields) <= 1 || 4 <= len(fields) { 132 panic(fmt.Sprintf(".p2align must have 2 or 3 arguments; got %v", fields)) 133 } 134 bits, err := strconv.ParseInt(fields[1], 10, 64) 135 if err != nil { 136 panic(err) 137 } 138 padVal := int64(0) 139 if len(fields) > 2 { 140 padVal, err = strconv.ParseInt(fields[2], 0, 64) 141 if err != nil { 142 panic(err) 143 } 144 } 145 align := 1 << uint(bits) 146 if strings.Contains(line, ".align") && 147 (strings.Contains(strings.ToLower(*targetFlag), "x86") || 148 strings.Contains(strings.ToLower(*targetFlag), "amd64")) { 149 // For historic reasons, the behavior of .align differs between 150 // architectures. The llvm for x86 alignment is in bytes. 151 // https://reviews.llvm.org/D16549 152 // http://lists.llvm.org/pipermail/llvm-dev/2009-June/022771.html 153 // https://users.elis.ugent.be/~jvcleemp/LLVM-2.4-doxygen/TargetAsmInfo_8h_source.html#l00261 154 align = int(bits) 155 } 156 for len(bytes)%align != 0 { 157 bytes = append(bytes, byte(padVal)) 158 } 159 } else if strings.Contains(line, ".space") || strings.Contains(line, ".zero") { 160 length, b := getDualNumbers(line) 161 for i := int64(0); i < length; i++ { 162 bytes = append(bytes, byte(b)) 163 } 164 } else if strings.Contains(line, ".section") { 165 // ignore 166 } else if strings.Contains(line, ".text") { 167 // ignore 168 } else { 169 panic(fmt.Sprintf("Unknown line for table: %s", line)) 170 } 171 } 172 173 // Pad onto a multiple of 8 bytes for aligned outputting 174 for len(bytes)%8 != 0 { 175 bytes = append(bytes, 0) 176 } 177 178 table := []string{} 179 180 for i := 0; i < len(bytes); i += 8 { 181 offset := fmt.Sprintf("%03x", i) 182 hex := "" 183 for j := i; j < i+8 && j < len(bytes); j++ { 184 hex = fmt.Sprintf("%02x", bytes[j]) + hex 185 } 186 table = append(table, fmt.Sprintf("DATA %s<>+0x%s(SB)/8, $0x%s", tableName, offset, hex)) 187 } 188 table = append(table, fmt.Sprintf("GLOBL %s<>(SB), 8, $%d", tableName, len(bytes))) 189 190 sanityCheckLabels(labels) 191 192 return Table{Name: tableName, Constants: strings.Join(table, "\n"), Labels: labels} 193 } 194 195 var regexpLabelConstant = regexp.MustCompile(`^\.?LCPI[0-9]+_0:`) 196 197 func getFirstLabelConstants(lines []string) int { 198 199 for iline, line := range lines { 200 if match := regexpLabelConstant.FindStringSubmatch(line); len(match) > 0 { 201 return iline 202 } 203 } 204 205 return -1 206 } 207 208 type Const struct { 209 name string 210 start, end int 211 } 212 213 func segmentConstTables(lines []string) []Table { 214 215 consts := []Const{} 216 217 globals := splitOnGlobals(lines) 218 219 if len(globals) == 0 { 220 return []Table{} 221 } 222 223 splitBegin := 0 224 for _, global := range globals { 225 start := getFirstLabelConstants(lines[splitBegin:global.dotGlobalLine]) 226 if start != -1 { 227 // Add set of lines when a constant table has been found 228 consts = append(consts, Const{name: fmt.Sprintf("LCDATA%d", len(consts)+1), start: splitBegin + start, end: global.dotGlobalLine}) 229 } 230 splitBegin = global.dotGlobalLine + 1 231 } 232 233 tables := []Table{} 234 235 for _, c := range consts { 236 237 tables = append(tables, defineTable(lines[c.start:c.end], c.name)) 238 } 239 240 return tables 241 } 242 243 func getCorrespondingTable(lines []string, tables []Table) Table { 244 245 concat := strings.Join(lines, "\n") 246 247 for _, t := range tables { 248 // Easy test -- we assume that if we find one label, we would find the others as well... 249 if strings.Contains(concat, t.Labels[0].Name) { 250 return t 251 } 252 } 253 254 return Table{} 255 }