aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/ld/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/ld/main.go')
-rw-r--r--src/cmd/link/internal/ld/main.go148
1 files changed, 133 insertions, 15 deletions
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 9f9395b757..3772c5090c 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -34,10 +34,12 @@ import (
"bufio"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/benchmark"
"cmd/link/internal/sym"
"flag"
"log"
"os"
+ "os/exec"
"runtime"
"runtime/pprof"
"strings"
@@ -87,8 +89,6 @@ var (
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
- flagNewobj = flag.Bool("newobj", false, "use new object file format")
-
FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
@@ -96,6 +96,11 @@ var (
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
memprofile = flag.String("memprofile", "", "write memory profile to `file`")
memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
+
+ benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
+ benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
+
+ flagGo115Newobj = flag.Bool("go115newobj", true, "use new object file format")
)
// Main is the main entry point for the linker code.
@@ -135,6 +140,10 @@ func Main(arch *sys.Arch, theArch Arch) {
objabi.Flagparse(usage)
+ if !*flagGo115Newobj {
+ oldlink()
+ }
+
switch *flagHeadType {
case "":
case "windowsgui":
@@ -170,13 +179,29 @@ func Main(arch *sys.Arch, theArch Arch) {
interpreter = *flagInterpreter
+ // enable benchmarking
+ var bench *benchmark.Metrics
+ if len(*benchmarkFlag) != 0 {
+ if *benchmarkFlag == "mem" {
+ bench = benchmark.New(benchmark.GC, *benchmarkFileFlag)
+ } else if *benchmarkFlag == "cpu" {
+ bench = benchmark.New(benchmark.NoGC, *benchmarkFileFlag)
+ } else {
+ Errorf(nil, "unknown benchmark flag: %q", *benchmarkFlag)
+ usage()
+ }
+ }
+
+ bench.Start("libinit")
libinit(ctxt) // creates outfile
if ctxt.HeadType == objabi.Hunknown {
ctxt.HeadType.Set(objabi.GOOS)
}
+ bench.Start("computeTLSOffset")
ctxt.computeTLSOffset()
+ bench.Start("Archinit")
thearch.Archinit(ctxt)
if ctxt.linkShared && !ctxt.IsELF {
@@ -207,47 +232,84 @@ func Main(arch *sys.Arch, theArch Arch) {
default:
addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "")
}
+ bench.Start("loadlib")
ctxt.loadlib()
+ bench.Start("deadcode")
deadcode(ctxt)
- if *flagNewobj {
- ctxt.loadlibfull() // XXX do it here for now
- }
+
+ bench.Start("linksetup")
ctxt.linksetup()
- ctxt.dostrdata()
- dwarfGenerateDebugInfo(ctxt)
+ bench.Start("dostrdata")
+ ctxt.dostrdata()
if objabi.Fieldtrack_enabled != 0 {
- fieldtrack(ctxt)
+ bench.Start("fieldtrack")
+ fieldtrack(ctxt.Arch, ctxt.loader)
}
- ctxt.mangleTypeSym()
+
+ bench.Start("dwarfGenerateDebugInfo")
+ dwarfGenerateDebugInfo(ctxt)
+
+ bench.Start("callgraph")
ctxt.callgraph()
- ctxt.doelf()
- if ctxt.HeadType == objabi.Hdarwin {
+ bench.Start("dostkcheck")
+ ctxt.dostkcheck()
+
+ bench.Start("mangleTypeSym")
+ ctxt.mangleTypeSym()
+
+ if ctxt.IsELF {
+ bench.Start("doelf")
+ ctxt.doelf()
+ }
+ if ctxt.IsDarwin() {
+ bench.Start("domacho")
ctxt.domacho()
}
- ctxt.dostkcheck()
- if ctxt.HeadType == objabi.Hwindows {
+ if ctxt.IsWindows() {
+ bench.Start("dope")
ctxt.dope()
+ bench.Start("windynrelocsyms")
ctxt.windynrelocsyms()
}
- if ctxt.HeadType == objabi.Haix {
+ if ctxt.IsAIX() {
+ bench.Start("doxcoff")
ctxt.doxcoff()
}
+ bench.Start("textbuildid")
+ ctxt.textbuildid()
+ bench.Start("addexport")
+ setupdynexp(ctxt)
+ ctxt.setArchSyms(BeforeLoadlibFull)
ctxt.addexport()
+
+ bench.Start("loadlibfull")
+ ctxt.loadlibfull() // XXX do it here for now
+
+ bench.Start("Gentext")
thearch.Gentext(ctxt) // trampolines, call stubs, etc.
- ctxt.textbuildid()
+ bench.Start("textaddress")
ctxt.textaddress()
+ bench.Start("pclntab")
ctxt.pclntab()
+ bench.Start("findfunctab")
ctxt.findfunctab()
+ bench.Start("typelink")
ctxt.typelink()
+ bench.Start("symtab")
ctxt.symtab()
+ bench.Start("buildinfo")
ctxt.buildinfo()
+ bench.Start("dodata")
ctxt.dodata()
+ bench.Start("address")
order := ctxt.address()
+ bench.Start("dwarfcompress")
dwarfcompress(ctxt)
+ bench.Start("layout")
filesize := ctxt.layout(order)
// Write out the output file.
@@ -266,25 +328,36 @@ func Main(arch *sys.Arch, theArch Arch) {
if outputMmapped {
// Asmb will redirect symbols to the output file mmap, and relocations
// will be applied directly there.
+ bench.Start("Asmb")
thearch.Asmb(ctxt)
+ bench.Start("reloc")
ctxt.reloc()
+ bench.Start("Munmap")
ctxt.Out.Munmap()
} else {
// If we don't mmap, we need to apply relocations before
// writing out.
+ bench.Start("reloc")
ctxt.reloc()
+ bench.Start("Asmb")
thearch.Asmb(ctxt)
}
+ bench.Start("Asmb2")
thearch.Asmb2(ctxt)
+ bench.Start("undef")
ctxt.undef()
+ bench.Start("hostlink")
ctxt.hostlink()
if ctxt.Debugvlog != 0 {
ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
ctxt.Logf("%d liveness data\n", liveness)
}
+ bench.Start("Flush")
ctxt.Bso.Flush()
+ bench.Start("archive")
ctxt.archive()
+ bench.Report(os.Stdout)
errorexit()
}
@@ -336,3 +409,48 @@ func startProfile() {
})
}
}
+
+// Invoke the old linker and exit.
+func oldlink() {
+ linker := os.Args[0]
+ if strings.HasSuffix(linker, "link") {
+ linker = linker[:len(linker)-4] + "oldlink"
+ } else if strings.HasSuffix(linker, "link.exe") {
+ linker = linker[:len(linker)-8] + "oldlink.exe"
+ } else {
+ log.Fatal("cannot find oldlink. arg0=", linker)
+ }
+
+ // Copy args, filter out -go115newobj flag
+ args := make([]string, 0, len(os.Args)-1)
+ skipNext := false
+ for i, a := range os.Args {
+ if i == 0 {
+ continue // skip arg0
+ }
+ if skipNext {
+ skipNext = false
+ continue
+ }
+ if a == "-go115newobj" {
+ skipNext = true
+ continue
+ }
+ if strings.HasPrefix(a, "-go115newobj=") {
+ continue
+ }
+ args = append(args, a)
+ }
+
+ cmd := exec.Command(linker, args...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ err := cmd.Run()
+ if err == nil {
+ os.Exit(0)
+ }
+ if _, ok := err.(*exec.ExitError); ok {
+ os.Exit(2) // would be nice to use ExitError.ExitCode(), but that is too new
+ }
+ log.Fatal("invoke oldlink failed:", err)
+}