github.com/bir3/gocompiler@v0.9.2202/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 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 }