github.com/cloudwego/iasm@v0.2.0/cmd/iasm/main.go (about)

     1  //
     2  // Copyright 2024 CloudWeGo Authors
     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      `os`
    21  
    22      `github.com/cloudwego/iasm/obj`
    23      `github.com/cloudwego/iasm/repl`
    24      `github.com/cloudwego/iasm/x86_64`
    25      `nullprogram.com/x/optparse`
    26  )
    27  
    28  type _FileFormat int
    29  
    30  const (
    31      _F_bin _FileFormat = iota + 1
    32      _F_macho
    33      _F_elf
    34  )
    35  
    36  var formatTab = map[string]_FileFormat {
    37      "bin"   : _F_bin,
    38      "macho" : _F_macho,
    39      "elf"   : _F_elf,
    40  }
    41  
    42  func usage() {
    43      println("usage: iasm [OPTIONS] <source>")
    44      println("       iasm -h | --help")
    45      println()
    46      println("General Options:")
    47      println(`    -D DEF, --define=DEF        Passing the defination to preprocessor`)
    48      println("    -f FMT, --format=FMT        Select output format")
    49      println("       bin                          Flat raw binary (default)")
    50      println("       macho                        Mach-O executable")
    51      println("       elf                          ELF executable")
    52      println()
    53      println("    -h, --help                  This help message")
    54      println("    -o FILE, --output=FILE      Output file name")
    55      println("    -s, --gas-compat            GAS compatible mode")
    56      println()
    57      println("Environment Variables:")
    58      println("    CPP                         The C Preprocessor")
    59      println()
    60  }
    61  
    62  func compile() {
    63      var err error
    64      var src string
    65      var rem []string
    66      var asm x86_64.Assembler
    67      var ret []optparse.Result
    68  
    69      /* options list */
    70      opts := []optparse.Option {
    71          { "help"       , 'h', optparse.KindNone     },
    72          { "define"     , 'D', optparse.KindRequired },
    73          { "format"     , 'f', optparse.KindRequired },
    74          { "output"     , 'o', optparse.KindRequired },
    75          { "gas-compat" , 's', optparse.KindNone     },
    76      }
    77  
    78      /* parse the options */
    79      if ret, rem, err = optparse.Parse(opts, os.Args); err != nil {
    80          println("iasm: error: " + err.Error())
    81          usage()
    82      }
    83  
    84      /* default values */
    85      help := false
    86      mgas := false
    87      ffmt := "bin"
    88      fout := "a.out"
    89      defs := []string(nil)
    90  
    91      /* check the result */
    92      for _, vv := range ret {
    93          switch vv.Short {
    94              case 'h': help = true
    95              case 's': mgas = true
    96              case 'f': ffmt = vv.Optarg
    97              case 'o': fout = vv.Optarg
    98              case 'D': defs = append(defs, vv.Optarg)
    99          }
   100      }
   101  
   102      /* check file format */
   103      if _, ok := formatTab[ffmt]; !ok {
   104          println("iasm: error: unknown file format: " + ffmt)
   105          os.Exit(1)
   106      }
   107  
   108      /* check for help */
   109      if help {
   110          usage()
   111      }
   112  
   113      /* must have source files */
   114      if len(rem) == 0 {
   115          println("iasm: error: missing input file.")
   116          os.Exit(1)
   117      }
   118  
   119      /* must have exactly 1 source file */
   120      if len(rem) != 1 {
   121          println("iasm: error: too many input files.")
   122          os.Exit(1)
   123      }
   124  
   125      /* preprocess the source file */
   126      if src, err = preprocess(rem[0], defs); err != nil {
   127          println("iasm: error: failed to run preprocessor: " + err.Error())
   128          os.Exit(1)
   129      }
   130  
   131      /* check for GAS compatible mode */
   132      if mgas {
   133          asm.Options().InstructionAliasing = true
   134          asm.Options().IgnoreUnknownDirectives = true
   135      }
   136  
   137      /* assemble the source */
   138      if err = asm.Assemble(src); err != nil {
   139          println("iasm: error: " + err.Error())
   140          os.Exit(1)
   141      }
   142  
   143      /* check for format */
   144      switch formatTab[ffmt] {
   145          case _F_bin   : err = os.WriteFile(fout, asm.Code(), 0755)
   146          case _F_elf   : err = obj.ELF.Generate(fout, asm.Code(), uint64(asm.Base()), uint64(asm.Entry()))
   147          case _F_macho : err = obj.MachO.Generate(fout, asm.Code(), uint64(asm.Base()), uint64(asm.Entry()))
   148          default       : panic("invalid format: " + ffmt)
   149      }
   150  
   151      /* check for errors */
   152      if err != nil {
   153          println("iasm: error: " + err.Error())
   154          os.Exit(1)
   155      }
   156  }
   157  
   158  func main() {
   159      if len(os.Args) != 1 {
   160          compile()
   161      } else {
   162          new(repl.IASM).Start()
   163      }
   164  }