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  }