github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/cmd/gllgo/gllgo.go (about)

     1  //===- gllgo.go - gccgo-like driver for llgo ------------------------------===//
     2  //
     3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
     4  // See https://llvm.org/LICENSE.txt for license information.
     5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     6  //
     7  //===----------------------------------------------------------------------===//
     8  //
     9  // This is llgo's driver. It has a gccgo-like interface in order to easily
    10  // interoperate with the "go" command and the libgo build system.
    11  //
    12  //===----------------------------------------------------------------------===//
    13  
    14  package main
    15  
    16  /*
    17  #include "config.h"
    18  */
    19  import "C"
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"go/scanner"
    25  	"go/token"
    26  	"io/ioutil"
    27  	"log"
    28  	"os"
    29  	"os/exec"
    30  	"path/filepath"
    31  	"strings"
    32  
    33  	"llvm.org/llgo/debug"
    34  	"llvm.org/llgo/driver"
    35  	"llvm.org/llgo/irgen"
    36  	"llvm.org/llvm/bindings/go/llvm"
    37  )
    38  
    39  const LibDirSuffix = C.LLVM_LIBDIR_SUFFIX
    40  
    41  func report(err error) {
    42  	if list, ok := err.(scanner.ErrorList); ok {
    43  		for _, e := range list {
    44  			fmt.Fprintf(os.Stderr, "%s\n", e)
    45  		}
    46  	} else if err != nil {
    47  		fmt.Fprintf(os.Stderr, "gllgo: error: %s\n", err)
    48  	}
    49  }
    50  
    51  func llvmVersion() string {
    52  	return strings.Replace(llvm.Version, "svn", "", 1)
    53  }
    54  
    55  func displayVersion() {
    56  	fmt.Printf("llgo version %s (%s)\n\n", llvmVersion(), irgen.GoVersion())
    57  	os.Exit(0)
    58  }
    59  
    60  func initCompiler(opts *driverOptions) (*irgen.Compiler, error) {
    61  	importPaths := make([]string, len(opts.importPaths)+len(opts.libPaths))
    62  	copy(importPaths, opts.importPaths)
    63  	copy(importPaths[len(opts.importPaths):], opts.libPaths)
    64  	if opts.prefix != "" {
    65  		importPaths = append(importPaths, filepath.Join(opts.prefix, "lib"+LibDirSuffix, "go", "llgo-"+llvmVersion()))
    66  	}
    67  	copts := irgen.CompilerOptions{
    68  		TargetTriple:       opts.triple,
    69  		GenerateDebug:      opts.generateDebug,
    70  		DebugPrefixMaps:    opts.debugPrefixMaps,
    71  		DumpSSA:            opts.dumpSSA,
    72  		GccgoPath:          opts.gccgoPath,
    73  		GccgoABI:           opts.gccgoPath != "",
    74  		ImportPaths:        importPaths,
    75  		SanitizerAttribute: opts.sanitizer.getAttribute(),
    76  	}
    77  	if opts.dumpTrace {
    78  		copts.Logger = log.New(os.Stderr, "", 0)
    79  	}
    80  	return irgen.NewCompiler(copts)
    81  }
    82  
    83  type actionKind int
    84  
    85  const (
    86  	actionAssemble = actionKind(iota)
    87  	actionCompile
    88  	actionLink
    89  	actionPrint
    90  )
    91  
    92  type action struct {
    93  	kind   actionKind
    94  	inputs []string
    95  }
    96  
    97  type sanitizerOptions struct {
    98  	blacklist string
    99  	crtPrefix string
   100  
   101  	address, thread, memory, dataflow bool
   102  }
   103  
   104  func (san *sanitizerOptions) resourcePath() string {
   105  	return filepath.Join(san.crtPrefix, "lib"+LibDirSuffix, "clang", llvmVersion())
   106  }
   107  
   108  func (san *sanitizerOptions) isPIEDefault() bool {
   109  	return san.thread || san.memory || san.dataflow
   110  }
   111  
   112  func (san *sanitizerOptions) addPasses(mpm, fpm llvm.PassManager) {
   113  	switch {
   114  	case san.address:
   115  		mpm.AddAddressSanitizerModulePass()
   116  		fpm.AddAddressSanitizerFunctionPass()
   117  	case san.thread:
   118  		mpm.AddThreadSanitizerPass()
   119  	case san.memory:
   120  		mpm.AddMemorySanitizerLegacyPassPass()
   121  	case san.dataflow:
   122  		blacklist := san.blacklist
   123  		if blacklist == "" {
   124  			blacklist = filepath.Join(san.resourcePath(), "dfsan_abilist.txt")
   125  		}
   126  		mpm.AddDataFlowSanitizerPass([]string{blacklist})
   127  	}
   128  }
   129  
   130  func (san *sanitizerOptions) libPath(triple, sanitizerName string) string {
   131  	s := strings.Split(triple, "-")
   132  	return filepath.Join(san.resourcePath(), "lib", s[2], "libclang_rt."+sanitizerName+"-"+s[0]+".a")
   133  }
   134  
   135  func (san *sanitizerOptions) addLibsForSanitizer(flags []string, triple, sanitizerName string) []string {
   136  	return append(flags, san.libPath(triple, sanitizerName),
   137  		"-Wl,--no-as-needed", "-lpthread", "-lrt", "-lm", "-ldl")
   138  }
   139  
   140  func (san *sanitizerOptions) addLibs(triple string, flags []string) []string {
   141  	switch {
   142  	case san.address:
   143  		flags = san.addLibsForSanitizer(flags, triple, "asan")
   144  	case san.thread:
   145  		flags = san.addLibsForSanitizer(flags, triple, "tsan")
   146  	case san.memory:
   147  		flags = san.addLibsForSanitizer(flags, triple, "msan")
   148  	case san.dataflow:
   149  		flags = san.addLibsForSanitizer(flags, triple, "dfsan")
   150  	}
   151  
   152  	return flags
   153  }
   154  
   155  func (san *sanitizerOptions) getAttribute() llvm.Attribute {
   156  	var attrKind uint
   157  
   158  	switch {
   159  	case san.address:
   160  		attrKind = llvm.AttributeKindID("sanitize_address")
   161  	case san.thread:
   162  		attrKind = llvm.AttributeKindID("sanitize_thread")
   163  	case san.memory:
   164  		attrKind = llvm.AttributeKindID("sanitize_memory")
   165  	default:
   166  		attrKind = 0
   167  	}
   168  
   169  	ctx := llvm.GlobalContext()
   170  	return ctx.CreateEnumAttribute(attrKind, 0)
   171  }
   172  
   173  type driverOptions struct {
   174  	actions []action
   175  	output  string
   176  
   177  	bprefix         string
   178  	debugPrefixMaps []debug.PrefixMap
   179  	dumpSSA         bool
   180  	dumpTrace       bool
   181  	emitIR          bool
   182  	gccgoPath       string
   183  	generateDebug   bool
   184  	importPaths     []string
   185  	libPaths        []string
   186  	llvmArgs        []string
   187  	lto             bool
   188  	optLevel        int
   189  	pic             bool
   190  	pieLink         bool
   191  	pkgpath         string
   192  	plugins         []string
   193  	prefix          string
   194  	sanitizer       sanitizerOptions
   195  	sizeLevel       int
   196  	staticLibgcc    bool
   197  	staticLibgo     bool
   198  	staticLink      bool
   199  	triple          string
   200  }
   201  
   202  func getInstPrefix() (string, error) {
   203  	path, err := exec.LookPath(os.Args[0])
   204  	if err != nil {
   205  		return "", err
   206  	}
   207  
   208  	path, err = filepath.EvalSymlinks(path)
   209  	if err != nil {
   210  		return "", err
   211  	}
   212  
   213  	prefix := filepath.Join(path, "..", "..")
   214  	return prefix, nil
   215  }
   216  
   217  func parseArguments(args []string) (opts driverOptions, err error) {
   218  	var goInputs, otherInputs []string
   219  	hasOtherNonFlagInputs := false
   220  	noPrefix := false
   221  	actionKind := actionLink
   222  	opts.triple = llvm.DefaultTargetTriple()
   223  
   224  	for len(args) > 0 {
   225  		consumedArgs := 1
   226  
   227  		switch {
   228  		case !strings.HasPrefix(args[0], "-"):
   229  			if strings.HasSuffix(args[0], ".go") {
   230  				goInputs = append(goInputs, args[0])
   231  			} else {
   232  				hasOtherNonFlagInputs = true
   233  				otherInputs = append(otherInputs, args[0])
   234  			}
   235  
   236  		case strings.HasPrefix(args[0], "-Wl,"), strings.HasPrefix(args[0], "-l"), strings.HasPrefix(args[0], "--sysroot="):
   237  			// TODO(pcc): Handle these correctly.
   238  			otherInputs = append(otherInputs, args[0])
   239  
   240  		case args[0] == "-B":
   241  			if len(args) == 1 {
   242  				return opts, errors.New("missing argument after '-B'")
   243  			}
   244  			opts.bprefix = args[1]
   245  			consumedArgs = 2
   246  
   247  		case args[0] == "-D":
   248  			if len(args) == 1 {
   249  				return opts, errors.New("missing argument after '-D'")
   250  			}
   251  			otherInputs = append(otherInputs, args[0], args[1])
   252  			consumedArgs = 2
   253  
   254  		case strings.HasPrefix(args[0], "-D"):
   255  			otherInputs = append(otherInputs, args[0])
   256  
   257  		case args[0] == "-I":
   258  			if len(args) == 1 {
   259  				return opts, errors.New("missing argument after '-I'")
   260  			}
   261  			opts.importPaths = append(opts.importPaths, args[1])
   262  			consumedArgs = 2
   263  
   264  		case strings.HasPrefix(args[0], "-I"):
   265  			opts.importPaths = append(opts.importPaths, args[0][2:])
   266  
   267  		case args[0] == "-isystem":
   268  			if len(args) == 1 {
   269  				return opts, errors.New("missing argument after '-isystem'")
   270  			}
   271  			otherInputs = append(otherInputs, args[0], args[1])
   272  			consumedArgs = 2
   273  
   274  		case args[0] == "-L":
   275  			if len(args) == 1 {
   276  				return opts, errors.New("missing argument after '-L'")
   277  			}
   278  			opts.libPaths = append(opts.libPaths, args[1])
   279  			consumedArgs = 2
   280  
   281  		case strings.HasPrefix(args[0], "-L"):
   282  			opts.libPaths = append(opts.libPaths, args[0][2:])
   283  
   284  		case args[0] == "-O0":
   285  			opts.optLevel = 0
   286  
   287  		case args[0] == "-O1", args[0] == "-O":
   288  			opts.optLevel = 1
   289  
   290  		case args[0] == "-O2":
   291  			opts.optLevel = 2
   292  
   293  		case args[0] == "-Os":
   294  			opts.optLevel = 2
   295  			opts.sizeLevel = 1
   296  
   297  		case args[0] == "-O3":
   298  			opts.optLevel = 3
   299  
   300  		case args[0] == "-S":
   301  			actionKind = actionAssemble
   302  
   303  		case args[0] == "-c":
   304  			actionKind = actionCompile
   305  
   306  		case strings.HasPrefix(args[0], "-fcompilerrt-prefix="):
   307  			opts.sanitizer.crtPrefix = args[0][20:]
   308  
   309  		case strings.HasPrefix(args[0], "-fdebug-prefix-map="):
   310  			split := strings.SplitN(args[0][19:], "=", 2)
   311  			if len(split) < 2 {
   312  				return opts, fmt.Errorf("argument '%s' must be of form '-fdebug-prefix-map=SOURCE=REPLACEMENT'", args[0])
   313  			}
   314  			opts.debugPrefixMaps = append(opts.debugPrefixMaps, debug.PrefixMap{split[0], split[1]})
   315  
   316  		case args[0] == "-fdump-ssa":
   317  			opts.dumpSSA = true
   318  
   319  		case args[0] == "-fdump-trace":
   320  			opts.dumpTrace = true
   321  
   322  		case strings.HasPrefix(args[0], "-fgccgo-path="):
   323  			opts.gccgoPath = args[0][13:]
   324  
   325  		case strings.HasPrefix(args[0], "-fgo-pkgpath="):
   326  			opts.pkgpath = args[0][13:]
   327  
   328  		case strings.HasPrefix(args[0], "-fgo-relative-import-path="):
   329  			// TODO(pcc): Handle this.
   330  
   331  		case strings.HasPrefix(args[0], "-fstack-protector"):
   332  			// TODO(axw) set ssp function attributes. This can be useful
   333  			// even for Go, if it interfaces with code written in a non-
   334  			// memory safe language (e.g. via cgo).
   335  
   336  		case strings.HasPrefix(args[0], "-W"):
   337  			// Go doesn't do warnings. Ignore.
   338  
   339  		case args[0] == "-fload-plugin":
   340  			if len(args) == 1 {
   341  				return opts, errors.New("missing argument after '-fload-plugin'")
   342  			}
   343  			opts.plugins = append(opts.plugins, args[1])
   344  			consumedArgs = 2
   345  
   346  		case args[0] == "-fno-toplevel-reorder":
   347  			// This is a GCC-specific code generation option. Ignore.
   348  
   349  		case args[0] == "-emit-llvm":
   350  			opts.emitIR = true
   351  
   352  		case args[0] == "-flto":
   353  			opts.lto = true
   354  
   355  		case args[0] == "-fPIC":
   356  			opts.pic = true
   357  
   358  		case strings.HasPrefix(args[0], "-fsanitize-blacklist="):
   359  			opts.sanitizer.blacklist = args[0][21:]
   360  
   361  		// TODO(pcc): Enforce mutual exclusion between sanitizers.
   362  
   363  		case args[0] == "-fsanitize=address":
   364  			opts.sanitizer.address = true
   365  
   366  		case args[0] == "-fsanitize=thread":
   367  			opts.sanitizer.thread = true
   368  
   369  		case args[0] == "-fsanitize=memory":
   370  			opts.sanitizer.memory = true
   371  
   372  		case args[0] == "-fsanitize=dataflow":
   373  			opts.sanitizer.dataflow = true
   374  
   375  		case args[0] == "-g":
   376  			opts.generateDebug = true
   377  
   378  		case args[0] == "-mllvm":
   379  			if len(args) == 1 {
   380  				return opts, errors.New("missing argument after '-mllvm'")
   381  			}
   382  			opts.llvmArgs = append(opts.llvmArgs, args[1])
   383  			consumedArgs = 2
   384  
   385  		case strings.HasPrefix(args[0], "-m"), args[0] == "-funsafe-math-optimizations", args[0] == "-ffp-contract=off":
   386  			// TODO(pcc): Handle code generation options.
   387  
   388  		case args[0] == "-no-prefix":
   389  			noPrefix = true
   390  
   391  		case args[0] == "-o":
   392  			if len(args) == 1 {
   393  				return opts, errors.New("missing argument after '-o'")
   394  			}
   395  			opts.output = args[1]
   396  			consumedArgs = 2
   397  
   398  		case args[0] == "-pie":
   399  			opts.pieLink = true
   400  
   401  		case args[0] == "-dumpversion",
   402  			args[0] == "-print-libgcc-file-name",
   403  			args[0] == "-print-multi-os-directory",
   404  			args[0] == "--version":
   405  			actionKind = actionPrint
   406  			opts.output = args[0]
   407  
   408  		case args[0] == "-static":
   409  			opts.staticLink = true
   410  
   411  		case args[0] == "-static-libgcc":
   412  			opts.staticLibgcc = true
   413  
   414  		case args[0] == "-static-libgo":
   415  			opts.staticLibgo = true
   416  
   417  		default:
   418  			return opts, fmt.Errorf("unrecognized command line option '%s'", args[0])
   419  		}
   420  
   421  		args = args[consumedArgs:]
   422  	}
   423  
   424  	if actionKind != actionPrint && len(goInputs) == 0 && !hasOtherNonFlagInputs {
   425  		return opts, errors.New("no input files")
   426  	}
   427  
   428  	if !noPrefix {
   429  		opts.prefix, err = getInstPrefix()
   430  		if err != nil {
   431  			return opts, err
   432  		}
   433  	}
   434  
   435  	if opts.sanitizer.crtPrefix == "" {
   436  		opts.sanitizer.crtPrefix = opts.prefix
   437  	}
   438  
   439  	if opts.sanitizer.isPIEDefault() {
   440  		// This should really only be turning on -fPIE, but this isn't
   441  		// easy to do from Go, and -fPIC is a superset of it anyway.
   442  		opts.pic = true
   443  		opts.pieLink = true
   444  	}
   445  
   446  	switch actionKind {
   447  	case actionLink:
   448  		if len(goInputs) != 0 {
   449  			opts.actions = []action{action{actionCompile, goInputs}}
   450  		}
   451  		opts.actions = append(opts.actions, action{actionLink, otherInputs})
   452  
   453  	case actionCompile, actionAssemble:
   454  		if len(goInputs) != 0 {
   455  			opts.actions = []action{action{actionKind, goInputs}}
   456  		}
   457  
   458  	case actionPrint:
   459  		opts.actions = []action{action{actionKind, nil}}
   460  	}
   461  
   462  	if opts.output == "" && len(opts.actions) != 0 {
   463  		switch actionKind {
   464  		case actionCompile, actionAssemble:
   465  			base := filepath.Base(goInputs[0])
   466  			base = base[0 : len(base)-3]
   467  			if actionKind == actionCompile {
   468  				opts.output = base + ".o"
   469  			} else {
   470  				opts.output = base + ".s"
   471  			}
   472  
   473  		case actionLink:
   474  			opts.output = "a.out"
   475  		}
   476  	}
   477  
   478  	return opts, nil
   479  }
   480  
   481  func runPasses(opts *driverOptions, tm llvm.TargetMachine, m llvm.Module) {
   482  	fpm := llvm.NewFunctionPassManagerForModule(m)
   483  	defer fpm.Dispose()
   484  
   485  	mpm := llvm.NewPassManager()
   486  	defer mpm.Dispose()
   487  
   488  	pmb := llvm.NewPassManagerBuilder()
   489  	defer pmb.Dispose()
   490  
   491  	pmb.SetOptLevel(opts.optLevel)
   492  	pmb.SetSizeLevel(opts.sizeLevel)
   493  
   494  	tm.AddAnalysisPasses(mpm)
   495  	tm.AddAnalysisPasses(fpm)
   496  
   497  	mpm.AddVerifierPass()
   498  	fpm.AddVerifierPass()
   499  
   500  	pmb.Populate(mpm)
   501  	pmb.PopulateFunc(fpm)
   502  
   503  	if opts.optLevel == 0 {
   504  		// Remove references (via the descriptor) to dead functions,
   505  		// for compatibility with other compilers.
   506  		mpm.AddGlobalDCEPass()
   507  	}
   508  
   509  	opts.sanitizer.addPasses(mpm, fpm)
   510  
   511  	fpm.InitializeFunc()
   512  	for fn := m.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
   513  		fpm.RunFunc(fn)
   514  	}
   515  	fpm.FinalizeFunc()
   516  
   517  	mpm.Run(m)
   518  }
   519  
   520  func getMetadataSectionInlineAsm(name string) string {
   521  	// ELF: creates a non-allocated excluded section.
   522  	return ".section \"" + name + "\", \"e\"\n"
   523  }
   524  
   525  func getDataInlineAsm(data []byte) string {
   526  	edata := make([]byte, 0, len(data)*4+10)
   527  
   528  	edata = append(edata, ".ascii \""...)
   529  	for i := range data {
   530  		switch data[i] {
   531  		case '\000':
   532  			edata = append(edata, "\\000"...)
   533  			continue
   534  		case '\n':
   535  			edata = append(edata, "\\n"...)
   536  			continue
   537  		case '"', '\\':
   538  			edata = append(edata, '\\')
   539  		}
   540  		edata = append(edata, data[i])
   541  	}
   542  	edata = append(edata, "\"\n"...)
   543  	return string(edata)
   544  }
   545  
   546  // Get the lib path to the standard libraries for the given driver options.
   547  // This is normally 'lib' but can vary for cross compilation, LTO, sanitizers
   548  // etc.
   549  func getLibDir(opts *driverOptions) string {
   550  	lib := "lib" + LibDirSuffix
   551  	switch {
   552  	case opts.lto:
   553  		return filepath.Join(lib, "llvm-lto.0")
   554  	case opts.sanitizer.address:
   555  		return filepath.Join(lib, "llvm-asan.0")
   556  	case opts.sanitizer.thread:
   557  		return filepath.Join(lib, "llvm-tsan.0")
   558  	case opts.sanitizer.memory:
   559  		return filepath.Join(lib, "llvm-msan.0")
   560  	case opts.sanitizer.dataflow:
   561  		return filepath.Join(lib, "llvm-dfsan.0")
   562  	default:
   563  		return lib
   564  	}
   565  }
   566  
   567  func performAction(opts *driverOptions, kind actionKind, inputs []string, output string) error {
   568  	switch kind {
   569  	case actionPrint:
   570  		switch opts.output {
   571  		case "-dumpversion":
   572  			fmt.Println("llgo-" + llvmVersion())
   573  			return nil
   574  		case "-print-libgcc-file-name":
   575  			cmd := exec.Command(opts.bprefix+"gcc", "-print-libgcc-file-name")
   576  			out, err := cmd.CombinedOutput()
   577  			os.Stdout.Write(out)
   578  			return err
   579  		case "-print-multi-os-directory":
   580  			fmt.Println(filepath.Join("..", getLibDir(opts)))
   581  			return nil
   582  		case "--version":
   583  			displayVersion()
   584  			return nil
   585  		default:
   586  			panic("unexpected print command")
   587  		}
   588  
   589  	case actionCompile, actionAssemble:
   590  		compiler, err := initCompiler(opts)
   591  		if err != nil {
   592  			return err
   593  		}
   594  
   595  		fset := token.NewFileSet()
   596  		files, err := driver.ParseFiles(fset, inputs)
   597  		if err != nil {
   598  			return err
   599  		}
   600  
   601  		module, err := compiler.Compile(fset, files, opts.pkgpath)
   602  		if err != nil {
   603  			return err
   604  		}
   605  
   606  		defer module.Dispose()
   607  
   608  		target, err := llvm.GetTargetFromTriple(opts.triple)
   609  		if err != nil {
   610  			return err
   611  		}
   612  
   613  		optLevel := [...]llvm.CodeGenOptLevel{
   614  			llvm.CodeGenLevelNone,
   615  			llvm.CodeGenLevelLess,
   616  			llvm.CodeGenLevelDefault,
   617  			llvm.CodeGenLevelAggressive,
   618  		}[opts.optLevel]
   619  
   620  		relocMode := llvm.RelocStatic
   621  		if opts.pic {
   622  			relocMode = llvm.RelocPIC
   623  		}
   624  
   625  		tm := target.CreateTargetMachine(opts.triple, "", "", optLevel,
   626  			relocMode, llvm.CodeModelDefault)
   627  		defer tm.Dispose()
   628  
   629  		runPasses(opts, tm, module.Module)
   630  
   631  		var file *os.File
   632  		if output == "-" {
   633  			file = os.Stdout
   634  		} else {
   635  			file, err = os.Create(output)
   636  			if err != nil {
   637  				return err
   638  			}
   639  			defer file.Close()
   640  		}
   641  
   642  		switch {
   643  		case !opts.lto && !opts.emitIR:
   644  			if module.ExportData != nil {
   645  				asm := getMetadataSectionInlineAsm(".go_export")
   646  				asm += getDataInlineAsm(module.ExportData)
   647  				module.Module.SetInlineAsm(asm)
   648  			}
   649  
   650  			fileType := llvm.AssemblyFile
   651  			if kind == actionCompile {
   652  				fileType = llvm.ObjectFile
   653  			}
   654  			mb, err := tm.EmitToMemoryBuffer(module.Module, fileType)
   655  			if err != nil {
   656  				return err
   657  			}
   658  			defer mb.Dispose()
   659  
   660  			bytes := mb.Bytes()
   661  			_, err = file.Write(bytes)
   662  			return err
   663  
   664  		case opts.lto:
   665  			bcmb := llvm.WriteBitcodeToMemoryBuffer(module.Module)
   666  			defer bcmb.Dispose()
   667  
   668  			// This is a bit of a hack. We just want an object file
   669  			// containing some metadata sections. This might be simpler
   670  			// if we had bindings for the MC library, but for now we create
   671  			// a fresh module containing only inline asm that creates the
   672  			// sections.
   673  			outmodule := llvm.NewModule("")
   674  			defer outmodule.Dispose()
   675  			asm := getMetadataSectionInlineAsm(".llvmbc")
   676  			asm += getDataInlineAsm(bcmb.Bytes())
   677  			if module.ExportData != nil {
   678  				asm += getMetadataSectionInlineAsm(".go_export")
   679  				asm += getDataInlineAsm(module.ExportData)
   680  			}
   681  			outmodule.SetInlineAsm(asm)
   682  
   683  			fileType := llvm.AssemblyFile
   684  			if kind == actionCompile {
   685  				fileType = llvm.ObjectFile
   686  			}
   687  			mb, err := tm.EmitToMemoryBuffer(outmodule, fileType)
   688  			if err != nil {
   689  				return err
   690  			}
   691  			defer mb.Dispose()
   692  
   693  			bytes := mb.Bytes()
   694  			_, err = file.Write(bytes)
   695  			return err
   696  
   697  		case kind == actionCompile:
   698  			err := llvm.WriteBitcodeToFile(module.Module, file)
   699  			return err
   700  
   701  		case kind == actionAssemble:
   702  			_, err := file.WriteString(module.Module.String())
   703  			return err
   704  
   705  		default:
   706  			panic("unexpected action kind")
   707  		}
   708  
   709  	case actionLink:
   710  		// TODO(pcc): Teach this to do LTO.
   711  		args := []string{"-o", output}
   712  		if opts.pic {
   713  			args = append(args, "-fPIC")
   714  		}
   715  		if opts.pieLink {
   716  			args = append(args, "-pie")
   717  		}
   718  		if opts.staticLink {
   719  			args = append(args, "-static")
   720  		}
   721  		if opts.staticLibgcc {
   722  			args = append(args, "-static-libgcc")
   723  		}
   724  		for _, p := range opts.libPaths {
   725  			args = append(args, "-L", p)
   726  		}
   727  		for _, p := range opts.importPaths {
   728  			args = append(args, "-I", p)
   729  		}
   730  		args = append(args, inputs...)
   731  		var linkerPath string
   732  		if opts.gccgoPath == "" {
   733  			// TODO(pcc): See if we can avoid calling gcc here.
   734  			// We currently rely on it to find crt*.o and compile
   735  			// any C source files passed as arguments.
   736  			linkerPath = opts.bprefix + "gcc"
   737  
   738  			if opts.prefix != "" {
   739  				libdir := filepath.Join(opts.prefix, getLibDir(opts))
   740  				args = append(args, "-L", libdir)
   741  				if !opts.staticLibgo {
   742  					args = append(args, "-Wl,-rpath,"+libdir)
   743  				}
   744  			}
   745  
   746  			args = append(args, "-lgobegin-llgo")
   747  			if opts.staticLibgo {
   748  				args = append(args, "-Wl,-Bstatic", "-lgo-llgo", "-Wl,-Bdynamic", "-lpthread", "-lm")
   749  			} else {
   750  				args = append(args, "-lgo-llgo", "-lm")
   751  			}
   752  		} else {
   753  			linkerPath = opts.gccgoPath
   754  			if opts.staticLibgo {
   755  				args = append(args, "-static-libgo")
   756  			}
   757  		}
   758  
   759  		args = opts.sanitizer.addLibs(opts.triple, args)
   760  
   761  		cmd := exec.Command(linkerPath, args...)
   762  		out, err := cmd.CombinedOutput()
   763  		if err != nil {
   764  			os.Stderr.Write(out)
   765  		}
   766  		return err
   767  
   768  	default:
   769  		panic("unexpected action kind")
   770  	}
   771  }
   772  
   773  func performActions(opts *driverOptions) error {
   774  	var extraInput string
   775  
   776  	for _, plugin := range opts.plugins {
   777  		err := llvm.LoadLibraryPermanently(plugin)
   778  		if err != nil {
   779  			return err
   780  		}
   781  	}
   782  
   783  	llvm.ParseCommandLineOptions(append([]string{"llgo"}, opts.llvmArgs...), "llgo (LLVM option parsing)\n")
   784  
   785  	for i, action := range opts.actions {
   786  		var output string
   787  		if i == len(opts.actions)-1 {
   788  			output = opts.output
   789  		} else {
   790  			tmpfile, err := ioutil.TempFile("", "llgo")
   791  			if err != nil {
   792  				return err
   793  			}
   794  			output = tmpfile.Name() + ".o"
   795  			tmpfile.Close()
   796  			err = os.Remove(tmpfile.Name())
   797  			if err != nil {
   798  				return err
   799  			}
   800  			defer os.Remove(output)
   801  		}
   802  
   803  		inputs := action.inputs
   804  		if extraInput != "" {
   805  			inputs = append([]string{extraInput}, inputs...)
   806  		}
   807  
   808  		err := performAction(opts, action.kind, inputs, output)
   809  		if err != nil {
   810  			return err
   811  		}
   812  
   813  		extraInput = output
   814  	}
   815  
   816  	return nil
   817  }
   818  
   819  func main() {
   820  	llvm.InitializeAllTargets()
   821  	llvm.InitializeAllTargetMCs()
   822  	llvm.InitializeAllTargetInfos()
   823  	llvm.InitializeAllAsmParsers()
   824  	llvm.InitializeAllAsmPrinters()
   825  
   826  	opts, err := parseArguments(os.Args[1:])
   827  	if err != nil {
   828  		report(err)
   829  		os.Exit(1)
   830  	}
   831  
   832  	err = performActions(&opts)
   833  	if err != nil {
   834  		report(err)
   835  		os.Exit(1)
   836  	}
   837  }