Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/link/internal/ld/asmb.go

Documentation: cmd/link/internal/ld

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ld
     6  
     7  import (
     8  	"cmd/internal/objabi"
     9  	"cmd/link/internal/loader"
    10  	"cmd/link/internal/sym"
    11  	"fmt"
    12  	"runtime"
    13  	"sync"
    14  )
    15  
    16  // Assembling the binary is broken into two steps:
    17  //  - writing out the code/data/dwarf Segments, applying relocations on the fly
    18  //  - writing out the architecture specific pieces.
    19  // This function handles the first part.
    20  func asmb(ctxt *Link) {
    21  	// TODO(jfaller): delete me.
    22  	if thearch.Asmb != nil {
    23  		thearch.Asmb(ctxt, ctxt.loader)
    24  		return
    25  	}
    26  
    27  	if ctxt.IsELF {
    28  		Asmbelfsetup()
    29  	}
    30  
    31  	var wg sync.WaitGroup
    32  	f := func(ctxt *Link, out *OutBuf, start, length int64) {
    33  		pad := thearch.CodePad
    34  		if pad == nil {
    35  			pad = zeros[:]
    36  		}
    37  		CodeblkPad(ctxt, out, start, length, pad)
    38  	}
    39  
    40  	for _, sect := range Segtext.Sections {
    41  		offset := sect.Vaddr - Segtext.Vaddr + Segtext.Fileoff
    42  		// Handle text sections with Codeblk
    43  		if sect.Name == ".text" {
    44  			writeParallel(&wg, f, ctxt, offset, sect.Vaddr, sect.Length)
    45  		} else {
    46  			writeParallel(&wg, datblk, ctxt, offset, sect.Vaddr, sect.Length)
    47  		}
    48  	}
    49  
    50  	if Segrodata.Filelen > 0 {
    51  		writeParallel(&wg, datblk, ctxt, Segrodata.Fileoff, Segrodata.Vaddr, Segrodata.Filelen)
    52  	}
    53  
    54  	if Segrelrodata.Filelen > 0 {
    55  		writeParallel(&wg, datblk, ctxt, Segrelrodata.Fileoff, Segrelrodata.Vaddr, Segrelrodata.Filelen)
    56  	}
    57  
    58  	writeParallel(&wg, datblk, ctxt, Segdata.Fileoff, Segdata.Vaddr, Segdata.Filelen)
    59  
    60  	writeParallel(&wg, dwarfblk, ctxt, Segdwarf.Fileoff, Segdwarf.Vaddr, Segdwarf.Filelen)
    61  
    62  	wg.Wait()
    63  }
    64  
    65  // Assembling the binary is broken into two steps:
    66  //  - writing out the code/data/dwarf Segments
    67  //  - writing out the architecture specific pieces.
    68  // This function handles the second part.
    69  func asmb2(ctxt *Link) {
    70  	if thearch.Asmb2 != nil {
    71  		thearch.Asmb2(ctxt, ctxt.loader)
    72  		return
    73  	}
    74  
    75  	symSize = 0
    76  	spSize = 0
    77  	lcSize = 0
    78  
    79  	switch ctxt.HeadType {
    80  	default:
    81  		panic("unknown platform")
    82  
    83  	// Macho
    84  	case objabi.Hdarwin:
    85  		asmbMacho(ctxt)
    86  
    87  	// Plan9
    88  	case objabi.Hplan9:
    89  		asmbPlan9(ctxt)
    90  
    91  	// PE
    92  	case objabi.Hwindows:
    93  		asmbPe(ctxt)
    94  
    95  	// Xcoff
    96  	case objabi.Haix:
    97  		asmbXcoff(ctxt)
    98  
    99  	// Elf
   100  	case objabi.Hdragonfly,
   101  		objabi.Hfreebsd,
   102  		objabi.Hlinux,
   103  		objabi.Hnetbsd,
   104  		objabi.Hopenbsd,
   105  		objabi.Hsolaris:
   106  		asmbElf(ctxt)
   107  	}
   108  
   109  	if *FlagC {
   110  		fmt.Printf("textsize=%d\n", Segtext.Filelen)
   111  		fmt.Printf("datsize=%d\n", Segdata.Filelen)
   112  		fmt.Printf("bsssize=%d\n", Segdata.Length-Segdata.Filelen)
   113  		fmt.Printf("symsize=%d\n", symSize)
   114  		fmt.Printf("lcsize=%d\n", lcSize)
   115  		fmt.Printf("total=%d\n", Segtext.Filelen+Segdata.Length+uint64(symSize)+uint64(lcSize))
   116  	}
   117  }
   118  
   119  // writePlan9Header writes out the plan9 header at the present position in the OutBuf.
   120  func writePlan9Header(buf *OutBuf, magic uint32, entry int64, is64Bit bool) {
   121  	if is64Bit {
   122  		magic |= 0x00008000
   123  	}
   124  	buf.Write32b(magic)
   125  	buf.Write32b(uint32(Segtext.Filelen))
   126  	buf.Write32b(uint32(Segdata.Filelen))
   127  	buf.Write32b(uint32(Segdata.Length - Segdata.Filelen))
   128  	buf.Write32b(uint32(symSize))
   129  	if is64Bit {
   130  		buf.Write32b(uint32(entry &^ 0x80000000))
   131  	} else {
   132  		buf.Write32b(uint32(entry))
   133  	}
   134  	buf.Write32b(uint32(spSize))
   135  	buf.Write32b(uint32(lcSize))
   136  	// amd64 includes the entry at the beginning of the symbol table.
   137  	if is64Bit {
   138  		buf.Write64b(uint64(entry))
   139  	}
   140  }
   141  
   142  // asmbPlan9 assembles a plan 9 binary.
   143  func asmbPlan9(ctxt *Link) {
   144  	if !*FlagS {
   145  		*FlagS = true
   146  		symo := int64(Segdata.Fileoff + Segdata.Filelen)
   147  		ctxt.Out.SeekSet(symo)
   148  		asmbPlan9Sym(ctxt)
   149  	}
   150  	ctxt.Out.SeekSet(0)
   151  	writePlan9Header(ctxt.Out, thearch.Plan9Magic, Entryvalue(ctxt), thearch.Plan9_64Bit)
   152  }
   153  
   154  // sizeExtRelocs precomputes the size needed for the reloc records,
   155  // sets the size and offset for relocation records in each section,
   156  // and mmap the output buffer with the proper size.
   157  func sizeExtRelocs(ctxt *Link, relsize uint32) {
   158  	if relsize == 0 {
   159  		panic("sizeExtRelocs: relocation size not set")
   160  	}
   161  	var sz int64
   162  	for _, seg := range Segments {
   163  		for _, sect := range seg.Sections {
   164  			sect.Reloff = uint64(ctxt.Out.Offset() + sz)
   165  			sect.Rellen = uint64(relsize * sect.Relcount)
   166  			sz += int64(sect.Rellen)
   167  		}
   168  	}
   169  	filesz := ctxt.Out.Offset() + sz
   170  	err := ctxt.Out.Mmap(uint64(filesz))
   171  	if err != nil {
   172  		Exitf("mapping output file failed: %v", err)
   173  	}
   174  }
   175  
   176  // relocSectFn wraps the function writing relocations of a section
   177  // for parallel execution. Returns the wrapped function and a wait
   178  // group for which the caller should wait.
   179  func relocSectFn(ctxt *Link, relocSect func(*Link, *OutBuf, *sym.Section, []loader.Sym)) (func(*Link, *sym.Section, []loader.Sym), *sync.WaitGroup) {
   180  	var fn func(ctxt *Link, sect *sym.Section, syms []loader.Sym)
   181  	var wg sync.WaitGroup
   182  	var sem chan int
   183  	if ctxt.Out.isMmapped() {
   184  		// Write sections in parallel.
   185  		sem = make(chan int, 2*runtime.GOMAXPROCS(0))
   186  		fn = func(ctxt *Link, sect *sym.Section, syms []loader.Sym) {
   187  			wg.Add(1)
   188  			sem <- 1
   189  			out, err := ctxt.Out.View(sect.Reloff)
   190  			if err != nil {
   191  				panic(err)
   192  			}
   193  			go func() {
   194  				relocSect(ctxt, out, sect, syms)
   195  				wg.Done()
   196  				<-sem
   197  			}()
   198  		}
   199  	} else {
   200  		// We cannot Mmap. Write sequentially.
   201  		fn = func(ctxt *Link, sect *sym.Section, syms []loader.Sym) {
   202  			relocSect(ctxt, ctxt.Out, sect, syms)
   203  		}
   204  	}
   205  	return fn, &wg
   206  }
   207  

View as plain text