github.com/bir3/gocompiler@v0.3.205/src/cmd/link/internal/ld/asmb.go (about)

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