2015-01-22 10:48:33 -08:00
|
|
|
// Copyright 2014 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2016-04-08 19:30:41 +10:00
|
|
|
"bufio"
|
2015-01-22 10:48:33 -08:00
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
2021-04-15 23:05:49 -04:00
|
|
|
"internal/buildcfg"
|
2015-01-22 10:48:33 -08:00
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
|
|
|
|
|
"cmd/asm/internal/arch"
|
|
|
|
|
"cmd/asm/internal/asm"
|
|
|
|
|
"cmd/asm/internal/flags"
|
|
|
|
|
"cmd/asm/internal/lex"
|
|
|
|
|
|
2016-04-06 21:45:29 -07:00
|
|
|
"cmd/internal/bio"
|
2015-01-22 10:48:33 -08:00
|
|
|
"cmd/internal/obj"
|
2021-04-20 14:08:58 -04:00
|
|
|
"cmd/internal/objabi"
|
2024-06-21 14:35:14 -04:00
|
|
|
"cmd/internal/telemetry/counter"
|
2015-01-22 10:48:33 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
log.SetFlags(0)
|
|
|
|
|
log.SetPrefix("asm: ")
|
2024-06-21 14:35:14 -04:00
|
|
|
counter.Open()
|
2015-01-22 10:48:33 -08:00
|
|
|
|
2021-04-15 23:05:49 -04:00
|
|
|
buildcfg.Check()
|
|
|
|
|
GOARCH := buildcfg.GOARCH
|
2015-01-22 10:48:33 -08:00
|
|
|
|
2021-09-26 19:21:29 +10:00
|
|
|
flags.Parse()
|
2024-06-21 14:35:14 -04:00
|
|
|
counter.Inc("asm/invocations")
|
|
|
|
|
counter.CountFlags("asm/flag:", *flag.CommandLine)
|
2021-09-26 19:21:29 +10:00
|
|
|
|
|
|
|
|
architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink)
|
2015-01-22 10:48:33 -08:00
|
|
|
if architecture == nil {
|
2016-02-19 16:02:54 -08:00
|
|
|
log.Fatalf("unrecognized architecture %s", GOARCH)
|
2015-01-22 10:48:33 -08:00
|
|
|
}
|
|
|
|
|
ctxt := obj.Linknew(architecture.LinkArch)
|
2020-09-17 15:31:07 -04:00
|
|
|
ctxt.Debugasm = flags.PrintOut
|
cmd/asm, cmd/link, runtime: introduce FuncInfo flag bits
The runtime traceback code has its own definition of which functions
mark the top frame of a stack, separate from the TOPFRAME bits that
exist in the assembly and are passed along in DWARF information.
It's error-prone and redundant to have two different sources of truth.
This CL provides the actual TOPFRAME bits to the runtime, so that
the runtime can use those bits instead of reinventing its own category.
This CL also adds a new bit, SPWRITE, which marks functions that
write directly to SP (anything but adding and subtracting constants).
Such functions must stop a traceback, because the traceback has no
way to rederive the SP on entry. Again, the runtime has its own definition
which is mostly correct, but also missing some functions. During ordinary
goroutine context switches, such functions do not appear on the stack,
so the incompleteness in the runtime usually doesn't matter.
But profiling signals can arrive at any moment, and the runtime may
crash during traceback if it attempts to unwind an SP-writing frame
and gets out-of-sync with the actual stack. The runtime contains code
to try to detect likely candidates but again it is incomplete.
Deriving the SPWRITE bit automatically from the actual assembly code
provides the complete truth, and passing it to the runtime lets the
runtime use it.
This CL is part of a stack adding windows/arm64
support (#36439), intended to land in the Go 1.17 cycle.
This CL is, however, not windows/arm64-specific.
It is cleanup meant to make the port (and future ports) easier.
Change-Id: I227f53b23ac5b3dabfcc5e8ee3f00df4e113cf58
Reviewed-on: https://go-review.googlesource.com/c/go/+/288800
Trust: Russ Cox <rsc@golang.org>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-01-28 15:21:33 -05:00
|
|
|
ctxt.Debugvlog = flags.DebugV
|
2015-03-30 00:49:25 +00:00
|
|
|
ctxt.Flag_dynlink = *flags.Dynlink
|
2020-12-10 08:44:44 -05:00
|
|
|
ctxt.Flag_linkshared = *flags.Linkshared
|
2016-04-13 18:41:59 -07:00
|
|
|
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
|
2019-08-20 17:39:09 -04:00
|
|
|
ctxt.Flag_maymorestack = flags.DebugFlags.MayMoreStack
|
2022-02-24 23:44:05 -05:00
|
|
|
ctxt.Debugpcln = flags.DebugFlags.PCTab
|
2020-04-23 19:52:31 -04:00
|
|
|
ctxt.IsAsm = true
|
2020-07-15 23:14:50 -04:00
|
|
|
ctxt.Pkgpath = *flags.Importpath
|
2020-01-17 13:54:30 -05:00
|
|
|
switch *flags.Spectre {
|
|
|
|
|
default:
|
|
|
|
|
log.Printf("unknown setting -spectre=%s", *flags.Spectre)
|
|
|
|
|
os.Exit(2)
|
|
|
|
|
case "":
|
|
|
|
|
// nothing
|
|
|
|
|
case "index":
|
|
|
|
|
// known to compiler; ignore here so people can use
|
|
|
|
|
// the same list with -gcflags=-spectre=LIST and -asmflags=-spectrre=LIST
|
|
|
|
|
case "all", "ret":
|
|
|
|
|
ctxt.Retpoline = true
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 19:30:41 +10:00
|
|
|
ctxt.Bso = bufio.NewWriter(os.Stdout)
|
2015-05-01 11:51:47 +10:00
|
|
|
defer ctxt.Bso.Flush()
|
2016-04-08 19:30:41 +10:00
|
|
|
|
2017-04-06 13:42:31 -07:00
|
|
|
architecture.Init(ctxt)
|
|
|
|
|
|
2016-04-08 19:30:41 +10:00
|
|
|
// Create object file, write header.
|
2019-09-11 16:11:31 -04:00
|
|
|
buf, err := bio.Create(*flags.OutputFile)
|
2016-04-08 19:30:41 +10:00
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
2019-09-11 16:11:31 -04:00
|
|
|
defer buf.Close()
|
2016-04-12 17:58:46 -07:00
|
|
|
|
2018-10-19 16:24:59 -04:00
|
|
|
if !*flags.SymABIs {
|
2021-04-20 14:08:58 -04:00
|
|
|
buf.WriteString(objabi.HeaderString())
|
2018-10-19 16:24:59 -04:00
|
|
|
fmt.Fprintf(buf, "!\n")
|
|
|
|
|
}
|
2015-01-22 10:48:33 -08:00
|
|
|
|
2023-08-26 19:06:33 -07:00
|
|
|
// Set macros for GOEXPERIMENTs so we can easily switch
|
|
|
|
|
// runtime assembly code based on them.
|
|
|
|
|
if objabi.LookupPkgSpecial(ctxt.Pkgpath).AllowAsmABI {
|
|
|
|
|
for _, exp := range buildcfg.Experiment.Enabled() {
|
|
|
|
|
flags.D = append(flags.D, "GOEXPERIMENT_"+exp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-18 13:27:11 -07:00
|
|
|
var ok, diag bool
|
|
|
|
|
var failedFile string
|
|
|
|
|
for _, f := range flag.Args() {
|
2023-08-26 19:06:33 -07:00
|
|
|
lexer := lex.NewLexer(f)
|
|
|
|
|
parser := asm.NewParser(ctxt, architecture, lexer)
|
2016-05-18 13:27:11 -07:00
|
|
|
ctxt.DiagFunc = func(format string, args ...interface{}) {
|
|
|
|
|
diag = true
|
|
|
|
|
log.Printf(format, args...)
|
|
|
|
|
}
|
2018-10-19 16:24:59 -04:00
|
|
|
if *flags.SymABIs {
|
|
|
|
|
ok = parser.ParseSymABIs(buf)
|
|
|
|
|
} else {
|
|
|
|
|
pList := new(obj.Plist)
|
|
|
|
|
pList.Firstpc, ok = parser.Parse()
|
|
|
|
|
// reports errors to parser.Errorf
|
|
|
|
|
if ok {
|
2023-08-26 19:06:33 -07:00
|
|
|
obj.Flushplist(ctxt, pList, nil)
|
2018-10-19 16:24:59 -04:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-18 13:27:11 -07:00
|
|
|
if !ok {
|
|
|
|
|
failedFile = f
|
|
|
|
|
break
|
|
|
|
|
}
|
2016-01-21 22:48:29 -05:00
|
|
|
}
|
2018-10-19 16:24:59 -04:00
|
|
|
if ok && !*flags.SymABIs {
|
2020-05-18 18:47:17 -04:00
|
|
|
ctxt.NumberSyms()
|
2020-07-15 23:14:50 -04:00
|
|
|
obj.WriteObjFile(ctxt, buf)
|
2016-01-21 22:48:29 -05:00
|
|
|
}
|
|
|
|
|
if !ok || diag {
|
2016-05-18 13:27:11 -07:00
|
|
|
if failedFile != "" {
|
|
|
|
|
log.Printf("assembly of %s failed", failedFile)
|
|
|
|
|
} else {
|
|
|
|
|
log.Print("assembly failed")
|
|
|
|
|
}
|
2019-09-11 16:11:31 -04:00
|
|
|
buf.Close()
|
2015-04-08 11:24:48 -07:00
|
|
|
os.Remove(*flags.OutputFile)
|
2015-01-22 10:48:33 -08:00
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
}
|