diff options
Diffstat (limited to 'src/cmd/link/internal/ld/asmb.go')
-rw-r--r-- | src/cmd/link/internal/ld/asmb.go | 214 |
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 +} |