mirror of
https://github.com/golang/go
synced 2024-09-29 12:04:28 -06:00
cmd/asm: allow def/ref of func ABI when compiling runtime
Function symbols defined and referenced by assembly source currently always default to ABI0; this patch adds preliminary support for accepting an explicit ABI selector clause for func defs/refs. This functionality is currently only enabled when compiling runtime-related packages (runtime, syscall, reflect). Examples: TEXT ·DefinedAbi0Symbol<ABI0>(SB),NOSPLIT,$0 RET TEXT ·DefinedAbi1Symbol<ABIInternal>(SB),NOSPLIT,$0 CALL ·AbiZerolSym<ABI0>(SB) ... JMP ·AbiInternalSym<ABIInternal>(SB) RET Also included is a small change to the code in the compiler that reads the symabis file emitted by the assembler. New behavior is currently gated under GOEXPERIMENT=regabi. Updates #27539, #40724. Change-Id: Ia22221fe26df0fa002191cfb13bdfaaa38d7df38 Reviewed-on: https://go-review.googlesource.com/c/go/+/260477 Run-TryBot: Than McIntosh <thanm@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> Trust: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
9499a2e108
commit
dd58239dd2
@ -31,7 +31,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
|
||||
architecture, ctxt := setArch(goarch)
|
||||
architecture.Init(ctxt)
|
||||
lexer := lex.NewLexer(input)
|
||||
parser := NewParser(ctxt, architecture, lexer)
|
||||
parser := NewParser(ctxt, architecture, lexer, false)
|
||||
pList := new(obj.Plist)
|
||||
var ok bool
|
||||
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
|
||||
@ -273,7 +273,7 @@ func testErrors(t *testing.T, goarch, file string) {
|
||||
input := filepath.Join("testdata", file+".s")
|
||||
architecture, ctxt := setArch(goarch)
|
||||
lexer := lex.NewLexer(input)
|
||||
parser := NewParser(ctxt, architecture, lexer)
|
||||
parser := NewParser(ctxt, architecture, lexer, false)
|
||||
pList := new(obj.Plist)
|
||||
var ok bool
|
||||
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
|
||||
|
@ -57,7 +57,7 @@ var exprTests = []exprTest{
|
||||
}
|
||||
|
||||
func TestExpr(t *testing.T) {
|
||||
p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
|
||||
p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
|
||||
for i, test := range exprTests {
|
||||
p.start(lex.Tokenize(test.input))
|
||||
result := int64(p.expr())
|
||||
@ -113,7 +113,7 @@ func TestBadExpr(t *testing.T) {
|
||||
}
|
||||
|
||||
func runBadTest(i int, test badExprTest, t *testing.T) (err error) {
|
||||
p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
|
||||
p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
|
||||
p.start(lex.Tokenize(test.input))
|
||||
return tryParse(t, func() {
|
||||
p.expr()
|
||||
|
@ -39,7 +39,7 @@ func testBadInstParser(t *testing.T, goarch string, tests []badInstTest) {
|
||||
for i, test := range tests {
|
||||
arch, ctxt := setArch(goarch)
|
||||
tokenizer := lex.NewTokenizer("", strings.NewReader(test.input+"\n"), nil)
|
||||
parser := NewParser(ctxt, arch, tokenizer)
|
||||
parser := NewParser(ctxt, arch, tokenizer, false)
|
||||
|
||||
err := tryParse(t, func() {
|
||||
parser.Parse()
|
||||
|
@ -28,7 +28,7 @@ func setArch(goarch string) (*arch.Arch, *obj.Link) {
|
||||
|
||||
func newParser(goarch string) *Parser {
|
||||
architecture, ctxt := setArch(goarch)
|
||||
return NewParser(ctxt, architecture, nil)
|
||||
return NewParser(ctxt, architecture, nil, false)
|
||||
}
|
||||
|
||||
// tryParse executes parse func in panicOnError=true context.
|
||||
@ -75,7 +75,12 @@ func testOperandParser(t *testing.T, parser *Parser, tests []operandTest) {
|
||||
parser.start(lex.Tokenize(test.input))
|
||||
addr := obj.Addr{}
|
||||
parser.operand(&addr)
|
||||
result := obj.Dconv(&emptyProg, &addr)
|
||||
var result string
|
||||
if parser.compilingRuntime {
|
||||
result = obj.DconvWithABIDetail(&emptyProg, &addr)
|
||||
} else {
|
||||
result = obj.Dconv(&emptyProg, &addr)
|
||||
}
|
||||
if result != test.output {
|
||||
t.Errorf("fail at %s: got %s; expected %s\n", test.input, result, test.output)
|
||||
}
|
||||
@ -86,6 +91,9 @@ func TestAMD64OperandParser(t *testing.T) {
|
||||
parser := newParser("amd64")
|
||||
testOperandParser(t, parser, amd64OperandTests)
|
||||
testBadOperandParser(t, parser, amd64BadOperandTests)
|
||||
parser.compilingRuntime = true
|
||||
testOperandParser(t, parser, amd64RuntimeOperandTests)
|
||||
testBadOperandParser(t, parser, amd64BadOperandRuntimeTests)
|
||||
}
|
||||
|
||||
func Test386OperandParser(t *testing.T) {
|
||||
@ -141,7 +149,7 @@ func TestFuncAddress(t *testing.T) {
|
||||
parser := newParser(sub.arch)
|
||||
for _, test := range sub.tests {
|
||||
parser.start(lex.Tokenize(test.input))
|
||||
name, ok := parser.funcAddress()
|
||||
name, _, ok := parser.funcAddress()
|
||||
|
||||
isFuncSym := strings.HasSuffix(test.input, "(SB)") &&
|
||||
// Ignore static symbols.
|
||||
@ -298,6 +306,11 @@ var amd64OperandTests = []operandTest{
|
||||
{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
|
||||
}
|
||||
|
||||
var amd64RuntimeOperandTests = []operandTest{
|
||||
{"$bar<ABI0>(SB)", "$bar<ABI0>(SB)"},
|
||||
{"$foo<ABIInternal>(SB)", "$foo<ABIInternal>(SB)"},
|
||||
}
|
||||
|
||||
var amd64BadOperandTests = []badOperandTest{
|
||||
{"[", "register list: expected ']', found EOF"},
|
||||
{"[4", "register list: bad low register in `[4`"},
|
||||
@ -311,6 +324,11 @@ var amd64BadOperandTests = []badOperandTest{
|
||||
{"[X0-X1-X2]", "register list: expected ']' after `[X0-X1`, found '-'"},
|
||||
{"[X0,X3]", "register list: expected '-' after `[X0`, found ','"},
|
||||
{"[X0,X1,X2,X3]", "register list: expected '-' after `[X0`, found ','"},
|
||||
{"$foo<ABI0>", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
|
||||
}
|
||||
|
||||
var amd64BadOperandRuntimeTests = []badOperandTest{
|
||||
{"$foo<bletch>", "malformed ABI selector \"bletch\" in reference to \"foo\""},
|
||||
}
|
||||
|
||||
var x86OperandTests = []operandTest{
|
||||
|
@ -25,25 +25,26 @@ import (
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
lex lex.TokenReader
|
||||
lineNum int // Line number in source file.
|
||||
errorLine int // Line number of last error.
|
||||
errorCount int // Number of errors.
|
||||
sawCode bool // saw code in this file (as opposed to comments and blank lines)
|
||||
pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
|
||||
input []lex.Token
|
||||
inputPos int
|
||||
pendingLabels []string // Labels to attach to next instruction.
|
||||
labels map[string]*obj.Prog
|
||||
toPatch []Patch
|
||||
addr []obj.Addr
|
||||
arch *arch.Arch
|
||||
ctxt *obj.Link
|
||||
firstProg *obj.Prog
|
||||
lastProg *obj.Prog
|
||||
dataAddr map[string]int64 // Most recent address for DATA for this symbol.
|
||||
isJump bool // Instruction being assembled is a jump.
|
||||
errorWriter io.Writer
|
||||
lex lex.TokenReader
|
||||
lineNum int // Line number in source file.
|
||||
errorLine int // Line number of last error.
|
||||
errorCount int // Number of errors.
|
||||
sawCode bool // saw code in this file (as opposed to comments and blank lines)
|
||||
pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
|
||||
input []lex.Token
|
||||
inputPos int
|
||||
pendingLabels []string // Labels to attach to next instruction.
|
||||
labels map[string]*obj.Prog
|
||||
toPatch []Patch
|
||||
addr []obj.Addr
|
||||
arch *arch.Arch
|
||||
ctxt *obj.Link
|
||||
firstProg *obj.Prog
|
||||
lastProg *obj.Prog
|
||||
dataAddr map[string]int64 // Most recent address for DATA for this symbol.
|
||||
isJump bool // Instruction being assembled is a jump.
|
||||
compilingRuntime bool
|
||||
errorWriter io.Writer
|
||||
}
|
||||
|
||||
type Patch struct {
|
||||
@ -51,14 +52,15 @@ type Patch struct {
|
||||
label string
|
||||
}
|
||||
|
||||
func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
|
||||
func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader, compilingRuntime bool) *Parser {
|
||||
return &Parser{
|
||||
ctxt: ctxt,
|
||||
arch: ar,
|
||||
lex: lexer,
|
||||
labels: make(map[string]*obj.Prog),
|
||||
dataAddr: make(map[string]int64),
|
||||
errorWriter: os.Stderr,
|
||||
ctxt: ctxt,
|
||||
arch: ar,
|
||||
lex: lexer,
|
||||
labels: make(map[string]*obj.Prog),
|
||||
dataAddr: make(map[string]int64),
|
||||
errorWriter: os.Stderr,
|
||||
compilingRuntime: compilingRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,8 +312,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
|
||||
// Defines text symbol in operands[0].
|
||||
if len(operands) > 0 {
|
||||
p.start(operands[0])
|
||||
if name, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "def %s ABI0\n", name)
|
||||
if name, abi, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "def %s %s\n", name, abi)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -329,8 +331,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
|
||||
// Search for symbol references.
|
||||
for _, op := range operands {
|
||||
p.start(op)
|
||||
if name, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "ref %s ABI0\n", name)
|
||||
if name, abi, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "ref %s %s\n", name, abi)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -765,20 +767,19 @@ func (p *Parser) symbolReference(a *obj.Addr, name string, prefix rune) {
|
||||
case '*':
|
||||
a.Type = obj.TYPE_INDIR
|
||||
}
|
||||
// Weirdness with statics: Might now have "<>".
|
||||
isStatic := false
|
||||
if p.peek() == '<' {
|
||||
isStatic = true
|
||||
p.next()
|
||||
p.get('>')
|
||||
}
|
||||
|
||||
// Parse optional <> (indicates a static symbol) or
|
||||
// <ABIxxx> (selecting text symbol with specific ABI).
|
||||
doIssueError := true
|
||||
isStatic, abi := p.symRefAttrs(name, doIssueError)
|
||||
|
||||
if p.peek() == '+' || p.peek() == '-' {
|
||||
a.Offset = int64(p.expr())
|
||||
}
|
||||
if isStatic {
|
||||
a.Sym = p.ctxt.LookupStatic(name)
|
||||
} else {
|
||||
a.Sym = p.ctxt.Lookup(name)
|
||||
a.Sym = p.ctxt.LookupABI(name, abi)
|
||||
}
|
||||
if p.peek() == scanner.EOF {
|
||||
if prefix == 0 && p.isJump {
|
||||
@ -823,12 +824,60 @@ func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, pr
|
||||
}
|
||||
}
|
||||
|
||||
// symRefAttrs parses an optional function symbol attribute clause for
|
||||
// the function symbol 'name', logging an error for a malformed
|
||||
// attribute clause if 'issueError' is true. The return value is a
|
||||
// (boolean, ABI) pair indicating that the named symbol is either
|
||||
// static or a particular ABI specification.
|
||||
//
|
||||
// The expected form of the attribute clause is:
|
||||
//
|
||||
// empty, yielding (false, obj.ABI0)
|
||||
// "<>", yielding (true, obj.ABI0)
|
||||
// "<ABI0>" yielding (false, obj.ABI0)
|
||||
// "<ABIInternal>" yielding (false, obj.ABIInternal)
|
||||
//
|
||||
// Anything else beginning with "<" logs an error if issueError is
|
||||
// true, otherwise returns (false, obj.ABI0).
|
||||
//
|
||||
func (p *Parser) symRefAttrs(name string, issueError bool) (bool, obj.ABI) {
|
||||
abi := obj.ABI0
|
||||
isStatic := false
|
||||
if p.peek() != '<' {
|
||||
return isStatic, abi
|
||||
}
|
||||
p.next()
|
||||
tok := p.peek()
|
||||
if tok == '>' {
|
||||
isStatic = true
|
||||
} else if tok == scanner.Ident {
|
||||
abistr := p.get(scanner.Ident).String()
|
||||
if !p.compilingRuntime {
|
||||
if issueError {
|
||||
p.errorf("ABI selector only permitted when compiling runtime, reference was to %q", name)
|
||||
}
|
||||
} else {
|
||||
theabi, valid := obj.ParseABI(abistr)
|
||||
if !valid {
|
||||
if issueError {
|
||||
p.errorf("malformed ABI selector %q in reference to %q",
|
||||
abistr, name)
|
||||
}
|
||||
} else {
|
||||
abi = theabi
|
||||
}
|
||||
}
|
||||
}
|
||||
p.get('>')
|
||||
return isStatic, abi
|
||||
}
|
||||
|
||||
// funcAddress parses an external function address. This is a
|
||||
// constrained form of the operand syntax that's always SB-based,
|
||||
// non-static, and has at most a simple integer offset:
|
||||
//
|
||||
// [$|*]sym[+Int](SB)
|
||||
func (p *Parser) funcAddress() (string, bool) {
|
||||
// [$|*]sym[<abi>][+Int](SB)
|
||||
func (p *Parser) funcAddress() (string, obj.ABI, bool) {
|
||||
switch p.peek() {
|
||||
case '$', '*':
|
||||
// Skip prefix.
|
||||
@ -838,25 +887,32 @@ func (p *Parser) funcAddress() (string, bool) {
|
||||
tok := p.next()
|
||||
name := tok.String()
|
||||
if tok.ScanToken != scanner.Ident || p.atStartOfRegister(name) {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
// Parse optional <> (indicates a static symbol) or
|
||||
// <ABIxxx> (selecting text symbol with specific ABI).
|
||||
noErrMsg := false
|
||||
isStatic, abi := p.symRefAttrs(name, noErrMsg)
|
||||
if isStatic {
|
||||
return "", obj.ABI0, false // This function rejects static symbols.
|
||||
}
|
||||
tok = p.next()
|
||||
if tok.ScanToken == '+' {
|
||||
if p.next().ScanToken != scanner.Int {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
tok = p.next()
|
||||
}
|
||||
if tok.ScanToken != '(' {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
if reg := p.next(); reg.ScanToken != scanner.Ident || reg.String() != "SB" {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
if p.next().ScanToken != ')' || p.peek() != scanner.EOF {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
return name, true
|
||||
return name, abi, true
|
||||
}
|
||||
|
||||
// registerIndirect parses the general form of a register indirection.
|
||||
|
@ -37,6 +37,7 @@ func TestErroneous(t *testing.T) {
|
||||
{"TEXT", "$0É:0, 0, $1", "expected end of operand, found É"}, // Issue #12467.
|
||||
{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
|
||||
{"TEXT", "@B(SB),0,$0", "expected '(', found B"}, // Issue 23580.
|
||||
{"TEXT", "foo<ABIInternal>(SB),0", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
|
||||
{"FUNCDATA", "", "expect two operands for FUNCDATA"},
|
||||
{"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
|
||||
{"DATA", "", "expect two operands for DATA"},
|
||||
|
@ -52,6 +52,7 @@ func main() {
|
||||
case "all", "ret":
|
||||
ctxt.Retpoline = true
|
||||
}
|
||||
compilingRuntime := objabi.IsRuntimePackagePath(*flags.Importpath)
|
||||
|
||||
ctxt.Bso = bufio.NewWriter(os.Stdout)
|
||||
defer ctxt.Bso.Flush()
|
||||
@ -74,7 +75,7 @@ func main() {
|
||||
var failedFile string
|
||||
for _, f := range flag.Args() {
|
||||
lexer := lex.NewLexer(f)
|
||||
parser := asm.NewParser(ctxt, architecture, lexer)
|
||||
parser := asm.NewParser(ctxt, architecture, lexer, compilingRuntime)
|
||||
ctxt.DiagFunc = func(format string, args ...interface{}) {
|
||||
diag = true
|
||||
log.Printf(format, args...)
|
||||
|
@ -968,9 +968,10 @@ func readSymABIs(file, myimportpath string) {
|
||||
if len(parts) != 3 {
|
||||
log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
|
||||
}
|
||||
sym, abi := parts[1], parts[2]
|
||||
if abi != "ABI0" { // Only supported external ABI right now
|
||||
log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi)
|
||||
sym, abistr := parts[1], parts[2]
|
||||
abi, valid := obj.ParseABI(abistr)
|
||||
if !valid {
|
||||
log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
|
||||
}
|
||||
|
||||
// If the symbol is already prefixed with
|
||||
@ -983,9 +984,9 @@ func readSymABIs(file, myimportpath string) {
|
||||
|
||||
// Record for later.
|
||||
if parts[0] == "def" {
|
||||
symabiDefs[sym] = obj.ABI0
|
||||
symabiDefs[sym] = abi
|
||||
} else {
|
||||
symabiRefs[sym] = obj.ABI0
|
||||
symabiRefs[sym] = abi
|
||||
}
|
||||
default:
|
||||
log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
|
||||
|
@ -502,6 +502,20 @@ const (
|
||||
ABICount
|
||||
)
|
||||
|
||||
// ParseABI converts from a string representation in 'abistr' to the
|
||||
// corresponding ABI value. Second return value is TRUE if the
|
||||
// abi string is recognized, FALSE otherwise.
|
||||
func ParseABI(abistr string) (ABI, bool) {
|
||||
switch abistr {
|
||||
default:
|
||||
return ABI0, false
|
||||
case "ABI0":
|
||||
return ABI0, true
|
||||
case "ABIInternal":
|
||||
return ABIInternal, true
|
||||
}
|
||||
}
|
||||
|
||||
// Attribute is a set of symbol attributes.
|
||||
type Attribute uint32
|
||||
|
||||
|
@ -210,13 +210,30 @@ func (ctxt *Link) CanReuseProgs() bool {
|
||||
return ctxt.Debugasm == 0
|
||||
}
|
||||
|
||||
// Dconv accepts an argument 'a' within a prog 'p' and returns a string
|
||||
// with a formatted version of the argument.
|
||||
func Dconv(p *Prog, a *Addr) string {
|
||||
buf := new(bytes.Buffer)
|
||||
WriteDconv(buf, p, a)
|
||||
writeDconv(buf, p, a, false)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// DconvDconvWithABIDetail accepts an argument 'a' within a prog 'p'
|
||||
// and returns a string with a formatted version of the argument, in
|
||||
// which text symbols are rendered with explicit ABI selectors.
|
||||
func DconvWithABIDetail(p *Prog, a *Addr) string {
|
||||
buf := new(bytes.Buffer)
|
||||
writeDconv(buf, p, a, true)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// WriteDconv accepts an argument 'a' within a prog 'p'
|
||||
// and writes a formatted version of the arg to the writer.
|
||||
func WriteDconv(w io.Writer, p *Prog, a *Addr) {
|
||||
writeDconv(w, p, a, false)
|
||||
}
|
||||
|
||||
func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
|
||||
switch a.Type {
|
||||
default:
|
||||
fmt.Fprintf(w, "type=%d", a.Type)
|
||||
@ -250,7 +267,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
|
||||
|
||||
case TYPE_BRANCH:
|
||||
if a.Sym != nil {
|
||||
fmt.Fprintf(w, "%s(SB)", a.Sym.Name)
|
||||
fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
|
||||
} else if a.Target() != nil {
|
||||
fmt.Fprint(w, a.Target().Pc)
|
||||
} else {
|
||||
@ -259,7 +276,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
|
||||
|
||||
case TYPE_INDIR:
|
||||
io.WriteString(w, "*")
|
||||
a.WriteNameTo(w)
|
||||
a.writeNameTo(w, abiDetail)
|
||||
|
||||
case TYPE_MEM:
|
||||
a.WriteNameTo(w)
|
||||
@ -299,7 +316,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
|
||||
|
||||
case TYPE_ADDR:
|
||||
io.WriteString(w, "$")
|
||||
a.WriteNameTo(w)
|
||||
a.writeNameTo(w, abiDetail)
|
||||
|
||||
case TYPE_SHIFT:
|
||||
v := int(a.Offset)
|
||||
@ -335,6 +352,11 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
|
||||
}
|
||||
|
||||
func (a *Addr) WriteNameTo(w io.Writer) {
|
||||
a.writeNameTo(w, false)
|
||||
}
|
||||
|
||||
func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
|
||||
|
||||
switch a.Name {
|
||||
default:
|
||||
fmt.Fprintf(w, "name=%d", a.Name)
|
||||
@ -356,7 +378,7 @@ func (a *Addr) WriteNameTo(w io.Writer) {
|
||||
reg = Rconv(int(a.Reg))
|
||||
}
|
||||
if a.Sym != nil {
|
||||
fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
|
||||
fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
|
||||
}
|
||||
@ -596,3 +618,10 @@ func Bool2int(b bool) int {
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func abiDecorate(a *Addr, abiDetail bool) string {
|
||||
if !abiDetail || a.Sym == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("<%s>", a.Sym.ABI())
|
||||
}
|
||||
|
@ -39,3 +39,25 @@ func PathToPrefix(s string) string {
|
||||
|
||||
return string(p)
|
||||
}
|
||||
|
||||
// IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
|
||||
// belongs to the collection of "runtime-related" packages, including
|
||||
// "runtime" itself, "reflect", "syscall", and the
|
||||
// "runtime/internal/*" packages. The compiler and/or assembler in
|
||||
// some cases need to be aware of when they are building such a
|
||||
// package, for example to enable features such as ABI selectors in
|
||||
// assembly sources.
|
||||
func IsRuntimePackagePath(pkgpath string) bool {
|
||||
rval := false
|
||||
switch pkgpath {
|
||||
case "runtime":
|
||||
rval = true
|
||||
case "reflect":
|
||||
rval = true
|
||||
case "syscall":
|
||||
rval = true
|
||||
default:
|
||||
rval = strings.HasPrefix(pkgpath, "runtime/internal")
|
||||
}
|
||||
return rval
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user