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 }