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  }