Skip to content

Commit 853cbde

Browse files
committed
assembly multiple files into a single .o with a single asm invocation
TODO: test with gccgo Cuts 10% off wall time for ‘go build -a math’. Fixes golang#15680 Change-Id: I12d2ee2c817207954961dc8f37b8f2b09f835550
1 parent 3572c64 commit 853cbde

File tree

3 files changed

+53
-34
lines changed

3 files changed

+53
-34
lines changed

src/cmd/asm/internal/flags/flags.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515

1616
var (
1717
Debug = flag.Bool("debug", false, "dump instructions as they are parsed")
18-
OutputFile = flag.String("o", "", "output file; default foo.6 for /a/b/c/foo.s on amd64")
18+
OutputFile = flag.String("o", "", "output file; default foo.o for /a/b/c/foo.s on amd64 if only one file provided")
1919
PrintOut = flag.Bool("S", false, "print assembly and machine code")
2020
TrimPath = flag.String("trimpath", "", "remove prefix from recorded source file paths")
2121
Shared = flag.Bool("shared", false, "generate code that can be linked into a shared library")
@@ -49,7 +49,7 @@ func (m *MultiFlag) Set(val string) error {
4949
}
5050

5151
func Usage() {
52-
fmt.Fprintf(os.Stderr, "usage: asm [options] file.s\n")
52+
fmt.Fprintf(os.Stderr, "usage: asm [options] file1.s file2.s ...\n")
5353
fmt.Fprintf(os.Stderr, "Flags:\n")
5454
flag.PrintDefaults()
5555
os.Exit(2)
@@ -58,12 +58,15 @@ func Usage() {
5858
func Parse() {
5959
flag.Usage = Usage
6060
flag.Parse()
61-
if flag.NArg() != 1 {
61+
if flag.NArg() == 0 {
6262
flag.Usage()
6363
}
6464

6565
// Flag refinement.
6666
if *OutputFile == "" {
67+
if flag.NArg() != 1 {
68+
flag.Usage()
69+
}
6770
input := filepath.Base(flag.Arg(0))
6871
if strings.HasSuffix(input, ".s") {
6972
input = input[:len(input)-2]

src/cmd/asm/main.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,20 @@ func main() {
5454
fmt.Fprintf(buf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
5555
fmt.Fprintf(buf, "!\n")
5656

57-
lexer := lex.NewLexer(flag.Arg(0), ctxt)
58-
parser := asm.NewParser(ctxt, architecture, lexer)
59-
diag := false
60-
ctxt.DiagFunc = func(format string, args ...interface{}) {
61-
diag = true
62-
log.Printf(format, args...)
57+
var ok, diag bool
58+
for _, f := range flag.Args() {
59+
lexer := lex.NewLexer(f, ctxt)
60+
parser := asm.NewParser(ctxt, architecture, lexer)
61+
ctxt.DiagFunc = func(format string, args ...interface{}) {
62+
diag = true
63+
log.Printf(format, args...)
64+
}
65+
pList := obj.Linknewplist(ctxt)
66+
pList.Firstpc, ok = parser.Parse()
67+
if !ok {
68+
break
69+
}
6370
}
64-
pList := obj.Linknewplist(ctxt)
65-
var ok bool
66-
pList.Firstpc, ok = parser.Parse()
6771
if ok {
6872
// reports errors to parser.Errorf
6973
obj.Writeobjdirect(ctxt, buf)

src/cmd/go/build.go

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,12 +1544,12 @@ func (b *builder) build(a *action) (err error) {
15441544
}
15451545

15461546
// Assemble .s files.
1547-
for _, file := range sfiles {
1548-
out := file[:len(file)-len(".s")] + ".o"
1549-
if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
1547+
if len(sfiles) > 0 {
1548+
ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles)
1549+
if err != nil {
15501550
return err
15511551
}
1552-
objects = append(objects, out)
1552+
objects = append(objects, ofiles...)
15531553
}
15541554

15551555
// NOTE(rsc): On Windows, it is critically important that the
@@ -2187,9 +2187,9 @@ type toolchain interface {
21872187
// cc runs the toolchain's C compiler in a directory on a C file
21882188
// to produce an output file.
21892189
cc(b *builder, p *Package, objdir, ofile, cfile string) error
2190-
// asm runs the assembler in a specific directory on a specific file
2191-
// to generate the named output file.
2192-
asm(b *builder, p *Package, obj, ofile, sfile string) error
2190+
// asm runs the assembler in a specific directory on specific files
2191+
// and returns a list of named output files.
2192+
asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error)
21932193
// pkgpath builds an appropriate path for a temporary package file.
21942194
pkgpath(basedir string, p *Package) string
21952195
// pack runs the archive packer in a specific directory to create
@@ -2226,8 +2226,8 @@ func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
22262226
return "", nil, noCompiler()
22272227
}
22282228

2229-
func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
2230-
return noCompiler()
2229+
func (noToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
2230+
return nil, noCompiler()
22312231
}
22322232

22332233
func (noToolchain) pkgpath(basedir string, p *Package) string {
@@ -2324,15 +2324,18 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
23242324
return ofile, output, err
23252325
}
23262326

2327-
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
2327+
func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
23282328
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
23292329
inc := filepath.Join(goroot, "pkg", "include")
2330-
sfile = mkAbs(p.Dir, sfile)
2331-
args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile}
2330+
ofile := obj + "asm.o"
2331+
args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
2332+
for _, sfile := range sfiles {
2333+
args = append(args, mkAbs(p.Dir, sfile))
2334+
}
23322335
if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
2333-
return err
2336+
return nil, err
23342337
}
2335-
return nil
2338+
return []string{ofile}, nil
23362339
}
23372340

23382341
// toolVerify checks that the command line args writes the same output file
@@ -2599,15 +2602,24 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
25992602
return ofile, output, err
26002603
}
26012604

2602-
func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
2603-
sfile = mkAbs(p.Dir, sfile)
2604-
defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
2605-
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
2606-
defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
2605+
func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
2606+
var ofiles []string
2607+
for _, sfile := range sfiles {
2608+
ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
2609+
ofiles = append(ofiles, ofile)
2610+
sfile = mkAbs(p.Dir, sfile)
2611+
defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
2612+
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
2613+
defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
2614+
}
2615+
defs = tools.maybePIC(defs)
2616+
defs = append(defs, b.gccArchArgs()...)
2617+
err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
2618+
if err != nil {
2619+
return nil, err
2620+
}
26072621
}
2608-
defs = tools.maybePIC(defs)
2609-
defs = append(defs, b.gccArchArgs()...)
2610-
return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
2622+
return ofiles, nil
26112623
}
26122624

26132625
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {

0 commit comments

Comments
 (0)