summaryrefslogtreecommitdiffstats
path: root/src/cmd/link/internal/ld/asmb.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/ld/asmb.go')
-rw-r--r--src/cmd/link/internal/ld/asmb.go214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/cmd/link/internal/ld/asmb.go b/src/cmd/link/internal/ld/asmb.go
new file mode 100644
index 0000000..fda0439
--- /dev/null
+++ b/src/cmd/link/internal/ld/asmb.go
@@ -0,0 +1,214 @@
+// Copyright 2020 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 ld
+
+import (
+ "cmd/internal/objabi"
+ "cmd/link/internal/loader"
+ "cmd/link/internal/sym"
+ "fmt"
+ "runtime"
+ "sync"
+)
+
+// Assembling the binary is broken into two steps:
+// - writing out the code/data/dwarf Segments, applying relocations on the fly
+// - writing out the architecture specific pieces.
+// This function handles the first part.
+func asmb(ctxt *Link) {
+ // TODO(jfaller): delete me.
+ if thearch.Asmb != nil {
+ thearch.Asmb(ctxt, ctxt.loader)
+ return
+ }
+
+ if ctxt.IsELF {
+ Asmbelfsetup()
+ }
+
+ var wg sync.WaitGroup
+ sect := Segtext.Sections[0]
+ offset := sect.Vaddr - Segtext.Vaddr + Segtext.Fileoff
+ f := func(ctxt *Link, out *OutBuf, start, length int64) {
+ pad := thearch.CodePad
+ if pad == nil {
+ pad = zeros[:]
+ }
+ CodeblkPad(ctxt, out, start, length, pad)
+ }
+
+ if !thearch.WriteTextBlocks {
+ writeParallel(&wg, f, ctxt, offset, sect.Vaddr, sect.Length)
+ for _, sect := range Segtext.Sections[1:] {
+ offset := sect.Vaddr - Segtext.Vaddr + Segtext.Fileoff
+ writeParallel(&wg, datblk, ctxt, offset, sect.Vaddr, sect.Length)
+ }
+ } else {
+ // TODO why can't we handle all sections this way?
+ for _, sect := range Segtext.Sections {
+ offset := sect.Vaddr - Segtext.Vaddr + Segtext.Fileoff
+ // Handle additional text sections with Codeblk
+ if sect.Name == ".text" {
+ writeParallel(&wg, f, ctxt, offset, sect.Vaddr, sect.Length)
+ } else {
+ writeParallel(&wg, datblk, ctxt, offset, sect.Vaddr, sect.Length)
+ }
+ }
+ }
+
+ if Segrodata.Filelen > 0 {
+ writeParallel(&wg, datblk, ctxt, Segrodata.Fileoff, Segrodata.Vaddr, Segrodata.Filelen)
+ }
+
+ if Segrelrodata.Filelen > 0 {
+ writeParallel(&wg, datblk, ctxt, Segrelrodata.Fileoff, Segrelrodata.Vaddr, Segrelrodata.Filelen)
+ }
+
+ writeParallel(&wg, datblk, ctxt, Segdata.Fileoff, Segdata.Vaddr, Segdata.Filelen)
+
+ writeParallel(&wg, dwarfblk, ctxt, Segdwarf.Fileoff, Segdwarf.Vaddr, Segdwarf.Filelen)
+
+ wg.Wait()
+}
+
+// Assembling the binary is broken into two steps:
+// - writing out the code/data/dwarf Segments
+// - writing out the architecture specific pieces.
+// This function handles the second part.
+func asmb2(ctxt *Link) {
+ if thearch.Asmb2 != nil {
+ thearch.Asmb2(ctxt, ctxt.loader)
+ return
+ }
+
+ symSize = 0
+ spSize = 0
+ lcSize = 0
+
+ switch ctxt.HeadType {
+ default:
+ panic("unknown platform")
+
+ // Macho
+ case objabi.Hdarwin:
+ asmbMacho(ctxt)
+
+ // Plan9
+ case objabi.Hplan9:
+ asmbPlan9(ctxt)
+
+ // PE
+ case objabi.Hwindows:
+ asmbPe(ctxt)
+
+ // Xcoff
+ case objabi.Haix:
+ asmbXcoff(ctxt)
+
+ // Elf
+ case objabi.Hdragonfly,
+ objabi.Hfreebsd,
+ objabi.Hlinux,
+ objabi.Hnetbsd,
+ objabi.Hopenbsd,
+ objabi.Hsolaris:
+ asmbElf(ctxt)
+ }
+
+ if *FlagC {
+ fmt.Printf("textsize=%d\n", Segtext.Filelen)
+ fmt.Printf("datsize=%d\n", Segdata.Filelen)
+ fmt.Printf("bsssize=%d\n", Segdata.Length-Segdata.Filelen)
+ fmt.Printf("symsize=%d\n", symSize)
+ fmt.Printf("lcsize=%d\n", lcSize)
+ fmt.Printf("total=%d\n", Segtext.Filelen+Segdata.Length+uint64(symSize)+uint64(lcSize))
+ }
+}
+
+// writePlan9Header writes out the plan9 header at the present position in the OutBuf.
+func writePlan9Header(buf *OutBuf, magic uint32, entry int64, is64Bit bool) {
+ if is64Bit {
+ magic |= 0x00008000
+ }
+ buf.Write32b(magic)
+ buf.Write32b(uint32(Segtext.Filelen))
+ buf.Write32b(uint32(Segdata.Filelen))
+ buf.Write32b(uint32(Segdata.Length - Segdata.Filelen))
+ buf.Write32b(uint32(symSize))
+ if is64Bit {
+ buf.Write32b(uint32(entry &^ 0x80000000))
+ } else {
+ buf.Write32b(uint32(entry))
+ }
+ buf.Write32b(uint32(spSize))
+ buf.Write32b(uint32(lcSize))
+ // amd64 includes the entry at the beginning of the symbol table.
+ if is64Bit {
+ buf.Write64b(uint64(entry))
+ }
+}
+
+// asmbPlan9 assembles a plan 9 binary.
+func asmbPlan9(ctxt *Link) {
+ if !*FlagS {
+ *FlagS = true
+ symo := int64(Segdata.Fileoff + Segdata.Filelen)
+ ctxt.Out.SeekSet(symo)
+ asmbPlan9Sym(ctxt)
+ }
+ ctxt.Out.SeekSet(0)
+ writePlan9Header(ctxt.Out, thearch.Plan9Magic, Entryvalue(ctxt), thearch.Plan9_64Bit)
+}
+
+// sizeExtRelocs precomputes the size needed for the reloc records,
+// sets the size and offset for relocation records in each section,
+// and mmap the output buffer with the proper size.
+func sizeExtRelocs(ctxt *Link, relsize uint32) {
+ if relsize == 0 {
+ panic("sizeExtRelocs: relocation size not set")
+ }
+ var sz int64
+ for _, seg := range Segments {
+ for _, sect := range seg.Sections {
+ sect.Reloff = uint64(ctxt.Out.Offset() + sz)
+ sect.Rellen = uint64(relsize * sect.Relcount)
+ sz += int64(sect.Rellen)
+ }
+ }
+ filesz := ctxt.Out.Offset() + sz
+ ctxt.Out.Mmap(uint64(filesz))
+}
+
+// relocSectFn wraps the function writing relocations of a section
+// for parallel execution. Returns the wrapped function and a wait
+// group for which the caller should wait.
+func relocSectFn(ctxt *Link, relocSect func(*Link, *OutBuf, *sym.Section, []loader.Sym)) (func(*Link, *sym.Section, []loader.Sym), *sync.WaitGroup) {
+ var fn func(ctxt *Link, sect *sym.Section, syms []loader.Sym)
+ var wg sync.WaitGroup
+ var sem chan int
+ if ctxt.Out.isMmapped() {
+ // Write sections in parallel.
+ sem = make(chan int, 2*runtime.GOMAXPROCS(0))
+ fn = func(ctxt *Link, sect *sym.Section, syms []loader.Sym) {
+ wg.Add(1)
+ sem <- 1
+ out, err := ctxt.Out.View(sect.Reloff)
+ if err != nil {
+ panic(err)
+ }
+ go func() {
+ relocSect(ctxt, out, sect, syms)
+ wg.Done()
+ <-sem
+ }()
+ }
+ } else {
+ // We cannot Mmap. Write sequentially.
+ fn = func(ctxt *Link, sect *sym.Section, syms []loader.Sym) {
+ relocSect(ctxt, ctxt.Out, sect, syms)
+ }
+ }
+ return fn, &wg
+}