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

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

View as plain text