Skip to content

Commit bbae923

Browse files
committed
cmd: merge branch 'dev.link' into master
In the dev.link branch we implemented the new object file format and (part of) the linker improvements described in https://golang.org/s/better-linker The new object file is index-based and provides random access. The linker maps the object files into read-only memory, and access symbols on-demand using indices, as opposed to reading all object files sequentially into the heap with the old format. The linker carries symbol informations using indices (as opposed to Symbol data structure). Symbols are created after the reachability analysis, and only created for reachable symbols. This reduces the linker's memory usage. Linking cmd/compile, it creates ~25% fewer Symbols, and reduces memory usage (inuse_space) by ~15%. (More results from Than.) Currently, both the old and new object file formats are supported. The old format is used by default. The new format can be turned on by using the compiler/assembler/linker's -newobj flag. Note that the flag needs to be specified consistently to all compilations, i.e. go build -gcflags=all=-newobj -asmflags=all=-newobj -ldflags=-newobj Change-Id: Ia0e35306b5b9b5b19fdc7fa7c602d4ce36fa6abd
2 parents 7e71c9c + 9cf6c65 commit bbae923

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+4471
-336
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var (
2323
Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
2424
AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
2525
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
26+
Newobj = flag.Bool("newobj", false, "use new object file format")
2627
)
2728

2829
var (

src/cmd/asm/main.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ func main() {
4040
}
4141
ctxt.Flag_dynlink = *flags.Dynlink
4242
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
43+
ctxt.Flag_newobj = *flags.Newobj
4344
ctxt.Bso = bufio.NewWriter(os.Stdout)
4445
defer ctxt.Bso.Flush()
4546

4647
architecture.Init(ctxt)
4748

4849
// Create object file, write header.
49-
out, err := os.Create(*flags.OutputFile)
50+
buf, err := bio.Create(*flags.OutputFile)
5051
if err != nil {
5152
log.Fatal(err)
5253
}
53-
defer bio.MustClose(out)
54-
buf := bufio.NewWriter(bio.MustWriter(out))
54+
defer buf.Close()
5555

5656
if !*flags.SymABIs {
5757
fmt.Fprintf(buf, "go object %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version)
@@ -83,6 +83,7 @@ func main() {
8383
}
8484
}
8585
if ok && !*flags.SymABIs {
86+
ctxt.NumberSyms(true)
8687
obj.WriteObjFile(ctxt, buf, "")
8788
}
8889
if !ok || diag {
@@ -91,9 +92,8 @@ func main() {
9192
} else {
9293
log.Print("assembly failed")
9394
}
94-
out.Close()
95+
buf.Close()
9596
os.Remove(*flags.OutputFile)
9697
os.Exit(1)
9798
}
98-
buf.Flush()
9999
}

src/cmd/compile/internal/gc/iexport.go

+19
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ import (
203203
"bufio"
204204
"bytes"
205205
"cmd/compile/internal/types"
206+
"cmd/internal/goobj2"
206207
"cmd/internal/src"
207208
"encoding/binary"
208209
"fmt"
@@ -945,10 +946,12 @@ func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
945946

946947
func (w *exportWriter) varExt(n *Node) {
947948
w.linkname(n.Sym)
949+
w.symIdx(n.Sym)
948950
}
949951

950952
func (w *exportWriter) funcExt(n *Node) {
951953
w.linkname(n.Sym)
954+
w.symIdx(n.Sym)
952955

953956
// Escape analysis.
954957
for _, fs := range types.RecvsParams {
@@ -987,6 +990,22 @@ func (w *exportWriter) linkname(s *types.Sym) {
987990
w.string(s.Linkname)
988991
}
989992

993+
func (w *exportWriter) symIdx(s *types.Sym) {
994+
if Ctxt.Flag_newobj {
995+
lsym := s.Linksym()
996+
if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
997+
// Don't export index for non-package symbols, linkname'd symbols,
998+
// and symbols without an index. They can only be referenced by
999+
// name.
1000+
w.int64(-1)
1001+
} else {
1002+
// For a defined symbol, export its index.
1003+
// For re-exporting an imported symbol, pass its index through.
1004+
w.int64(int64(lsym.SymIdx))
1005+
}
1006+
}
1007+
}
1008+
9901009
// Inline bodies.
9911010

9921011
func (w *exportWriter) stmtList(list Nodes) {

src/cmd/compile/internal/gc/iimport.go

+17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package gc
1010
import (
1111
"cmd/compile/internal/types"
1212
"cmd/internal/bio"
13+
"cmd/internal/obj"
1314
"cmd/internal/src"
1415
"encoding/binary"
1516
"fmt"
@@ -651,10 +652,12 @@ func (r *importReader) byte() byte {
651652

652653
func (r *importReader) varExt(n *Node) {
653654
r.linkname(n.Sym)
655+
r.symIdx(n.Sym)
654656
}
655657

656658
func (r *importReader) funcExt(n *Node) {
657659
r.linkname(n.Sym)
660+
r.symIdx(n.Sym)
658661

659662
// Escape analysis.
660663
for _, fs := range types.RecvsParams {
@@ -683,6 +686,20 @@ func (r *importReader) linkname(s *types.Sym) {
683686
s.Linkname = r.string()
684687
}
685688

689+
func (r *importReader) symIdx(s *types.Sym) {
690+
if Ctxt.Flag_newobj {
691+
lsym := s.Linksym()
692+
idx := int32(r.int64())
693+
if idx != -1 {
694+
if s.Linkname != "" {
695+
Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
696+
}
697+
lsym.SymIdx = idx
698+
lsym.Set(obj.AttrIndexed, true)
699+
}
700+
}
701+
}
702+
686703
func (r *importReader) doInline(n *Node) {
687704
if len(n.Func.Inl.Body) != 0 {
688705
Fatalf("%v already has inline body", n)

src/cmd/compile/internal/gc/main.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ func Main(archInit func(*Arch)) {
260260
if supportsDynlink(thearch.LinkArch.Arch) {
261261
flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
262262
flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
263+
flag.BoolVar(&Ctxt.Flag_linkshared, "linkshared", false, "generate code that will be linked against Go shared libraries")
263264
}
264265
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
265266
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
@@ -274,12 +275,14 @@ func Main(archInit func(*Arch)) {
274275
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
275276
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
276277
flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
278+
flag.BoolVar(&Ctxt.Flag_newobj, "newobj", false, "use new object file format")
279+
277280
objabi.Flagparse(usage)
278281

279282
// Record flags that affect the build result. (And don't
280283
// record flags that don't, since that would cause spurious
281284
// changes in the binary.)
282-
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes")
285+
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "newobj")
283286

284287
if smallFrames {
285288
maxStackVarSize = 128 * 1024
@@ -746,6 +749,8 @@ func Main(archInit func(*Arch)) {
746749

747750
// Write object data to disk.
748751
timings.Start("be", "dumpobj")
752+
dumpdata()
753+
Ctxt.NumberSyms(false)
749754
dumpobj()
750755
if asmhdr != "" {
751756
dumpasmhdr()

src/cmd/compile/internal/gc/obj.go

+18-16
Original file line numberDiff line numberDiff line change
@@ -111,21 +111,7 @@ func dumpCompilerObj(bout *bio.Writer) {
111111
dumpexport(bout)
112112
}
113113

114-
func dumpLinkerObj(bout *bio.Writer) {
115-
printObjHeader(bout)
116-
117-
if len(pragcgobuf) != 0 {
118-
// write empty export section; must be before cgo section
119-
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
120-
fmt.Fprintf(bout, "\n$$ // cgo\n")
121-
if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
122-
Fatalf("serializing pragcgobuf: %v", err)
123-
}
124-
fmt.Fprintf(bout, "\n$$\n\n")
125-
}
126-
127-
fmt.Fprintf(bout, "\n!\n")
128-
114+
func dumpdata() {
129115
externs := len(externdcl)
130116

131117
dumpglobls()
@@ -163,8 +149,24 @@ func dumpLinkerObj(bout *bio.Writer) {
163149
}
164150

165151
addGCLocals()
152+
}
153+
154+
func dumpLinkerObj(bout *bio.Writer) {
155+
printObjHeader(bout)
156+
157+
if len(pragcgobuf) != 0 {
158+
// write empty export section; must be before cgo section
159+
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
160+
fmt.Fprintf(bout, "\n$$ // cgo\n")
161+
if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
162+
Fatalf("serializing pragcgobuf: %v", err)
163+
}
164+
fmt.Fprintf(bout, "\n$$\n\n")
165+
}
166+
167+
fmt.Fprintf(bout, "\n!\n")
166168

167-
obj.WriteObjFile(Ctxt, bout.Writer, myimportpath)
169+
obj.WriteObjFile(Ctxt, bout, myimportpath)
168170
}
169171

170172
func addptabs() {

src/cmd/compile/internal/types/sym.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,18 @@ func (sym *Sym) Linksym() *obj.LSym {
8080
if sym == nil {
8181
return nil
8282
}
83+
initPkg := func(r *obj.LSym) {
84+
if sym.Linkname != "" {
85+
r.Pkg = "_"
86+
} else {
87+
r.Pkg = sym.Pkg.Prefix
88+
}
89+
}
8390
if sym.Func() {
8491
// This is a function symbol. Mark it as "internal ABI".
85-
return Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
92+
return Ctxt.LookupABIInit(sym.LinksymName(), obj.ABIInternal, initPkg)
8693
}
87-
return Ctxt.Lookup(sym.LinksymName())
94+
return Ctxt.LookupInit(sym.LinksymName(), initPkg)
8895
}
8996

9097
// Less reports whether symbol a is ordered before symbol b.

src/cmd/dist/buildtool.go

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ var bootstrapDirs = []string{
5454
"cmd/internal/gcprog",
5555
"cmd/internal/dwarf",
5656
"cmd/internal/edit",
57+
"cmd/internal/goobj2",
5758
"cmd/internal/objabi",
5859
"cmd/internal/obj",
5960
"cmd/internal/obj/arm",
@@ -72,6 +73,7 @@ var bootstrapDirs = []string{
7273
"cmd/link/internal/arm64",
7374
"cmd/link/internal/ld",
7475
"cmd/link/internal/loadelf",
76+
"cmd/link/internal/loader",
7577
"cmd/link/internal/loadmacho",
7678
"cmd/link/internal/loadpe",
7779
"cmd/link/internal/loadxcoff",

src/cmd/dist/test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ func (t *tester) registerTests() {
585585
},
586586
})
587587
// Also test a cgo package.
588-
if t.cgoEnabled {
588+
if t.cgoEnabled && t.internalLink() {
589589
t.tests = append(t.tests, distTest{
590590
name: "pie_internal_cgo",
591591
heading: "internal linking of -buildmode=pie",

src/cmd/go/alldocs.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/go/internal/work/build.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ and test commands:
9797
-ldflags '[pattern=]arg list'
9898
arguments to pass on each go tool link invocation.
9999
-linkshared
100-
link against shared libraries previously created with
101-
-buildmode=shared.
100+
build code that will be linked against shared libraries previously
101+
created with -buildmode=shared.
102102
-mod mode
103103
module download mode to use: readonly or vendor.
104104
See 'go help modules' for more.

src/cmd/go/internal/work/init.go

+1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ func buildModeInit() {
224224
base.Fatalf("-linkshared not supported on %s\n", platform)
225225
}
226226
codegenArg = "-dynlink"
227+
forcedGcflags = append(forcedGcflags, "-linkshared")
227228
// TODO(mwhudson): remove -w when that gets fixed in linker.
228229
forcedLdflags = append(forcedLdflags, "-linkshared", "-w")
229230
}

src/cmd/internal/dwarf/dwarf.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,13 @@ func PutDefaultFunc(ctxt Context, s *FnState) error {
13721372
abbrev := DW_ABRV_FUNCTION
13731373
Uleb128put(ctxt, s.Info, int64(abbrev))
13741374

1375-
putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(s.Name)), s.Name)
1375+
// Expand '"".' to import path.
1376+
name := s.Name
1377+
if s.Importpath != "" {
1378+
name = strings.Replace(name, "\"\".", objabi.PathToPrefix(s.Importpath)+".", -1)
1379+
}
1380+
1381+
putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
13761382
putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC)
13771383
putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC)
13781384
putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})

src/cmd/internal/goobj/read.go

+8
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,14 @@ func (r *objReader) parseObject(prefix []byte) error {
502502
}
503503
// TODO: extract OS + build ID if/when we need it
504504

505+
p, err := r.peek(8)
506+
if err != nil {
507+
return err
508+
}
509+
if bytes.Equal(p, []byte("\x00go114LD")) {
510+
r.readNew()
511+
return nil
512+
}
505513
r.readFull(r.tmp[:8])
506514
if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) {
507515
return r.error(errCorruptObject)

0 commit comments

Comments
 (0)