1 // Derived from Inferno utils/6l/obj.c and utils/6l/span.c
2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
3 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
5 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
6 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
7 // Portions Copyright © 1997-1999 Vita Nuova Limited
8 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
9 // Portions Copyright © 2004,2006 Bruce Ellis
10 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
11 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
12 // Portions Copyright © 2009 The Go Authors. All rights reserved.
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to deal
16 // in the Software without restriction, including without limitation the rights
17 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 // copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
21 // The above copyright notice and this permission notice shall be included in
22 // all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45 func Linknew(arch *LinkArch) *Link {
47 ctxt.hash = make(map[string]*LSym)
48 ctxt.funchash = make(map[string]*LSym)
49 ctxt.statichash = make(map[string]*LSym)
51 ctxt.Pathname = objabi.WorkingDir()
53 if err := ctxt.Headtype.Set(buildcfg.GOOS); err != nil {
54 log.Fatalf("unknown goos %s", buildcfg.GOOS)
57 ctxt.Flag_optimize = true
61 // LookupDerived looks up or creates the symbol with name derived from symbol s.
62 // The resulting symbol will be static iff s is.
63 func (ctxt *Link) LookupDerived(s *LSym, name string) *LSym {
65 return ctxt.LookupStatic(name)
67 return ctxt.Lookup(name)
70 // LookupStatic looks up the static symbol with name name.
71 // If it does not exist, it creates it.
72 func (ctxt *Link) LookupStatic(name string) *LSym {
73 s := ctxt.statichash[name]
75 s = &LSym{Name: name, Attribute: AttrStatic}
76 ctxt.statichash[name] = s
81 // LookupABI looks up a symbol with the given ABI.
82 // If it does not exist, it creates it.
83 func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
84 return ctxt.LookupABIInit(name, abi, nil)
87 // LookupABI looks up a symbol with the given ABI.
88 // If it does not exist, it creates it and
89 // passes it to init for one-time initialization.
90 func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
91 var hash map[string]*LSym
104 s = &LSym{Name: name}
115 // Lookup looks up the symbol with name name.
116 // If it does not exist, it creates it.
117 func (ctxt *Link) Lookup(name string) *LSym {
118 return ctxt.LookupInit(name, nil)
121 // LookupInit looks up the symbol with name name.
122 // If it does not exist, it creates it and
123 // passes it to init for one-time initialization.
124 func (ctxt *Link) LookupInit(name string, init func(s *LSym)) *LSym {
128 s = &LSym{Name: name}
138 func (ctxt *Link) Float32Sym(f float32) *LSym {
139 i := math.Float32bits(f)
140 name := fmt.Sprintf("$f32.%08x", i)
141 return ctxt.LookupInit(name, func(s *LSym) {
143 s.WriteFloat32(ctxt, 0, f)
144 s.Type = objabi.SRODATA
145 s.Set(AttrLocal, true)
146 s.Set(AttrContentAddressable, true)
147 ctxt.constSyms = append(ctxt.constSyms, s)
151 func (ctxt *Link) Float64Sym(f float64) *LSym {
152 i := math.Float64bits(f)
153 name := fmt.Sprintf("$f64.%016x", i)
154 return ctxt.LookupInit(name, func(s *LSym) {
156 s.WriteFloat64(ctxt, 0, f)
157 s.Type = objabi.SRODATA
158 s.Set(AttrLocal, true)
159 s.Set(AttrContentAddressable, true)
160 ctxt.constSyms = append(ctxt.constSyms, s)
164 func (ctxt *Link) Int64Sym(i int64) *LSym {
165 name := fmt.Sprintf("$i64.%016x", uint64(i))
166 return ctxt.LookupInit(name, func(s *LSym) {
168 s.WriteInt(ctxt, 0, 8, i)
169 s.Type = objabi.SRODATA
170 s.Set(AttrLocal, true)
171 s.Set(AttrContentAddressable, true)
172 ctxt.constSyms = append(ctxt.constSyms, s)
176 // Assign index to symbols.
177 // asm is set to true if this is called by the assembler (i.e. not the compiler),
178 // in which case all the symbols are non-package (for now).
179 func (ctxt *Link) NumberSyms() {
180 if ctxt.Headtype == objabi.Haix {
181 // Data must be sorted to keep a constant order in TOC symbols.
182 // As they are created during Progedit, two symbols can be switched between
183 // two different compilations. Therefore, BuildID will be different.
184 // TODO: find a better place and optimize to only sort TOC symbols
185 sort.Slice(ctxt.Data, func(i, j int) bool {
186 return ctxt.Data[i].Name < ctxt.Data[j].Name
190 // Constant symbols are created late in the concurrent phase. Sort them
191 // to ensure a deterministic order.
192 sort.Slice(ctxt.constSyms, func(i, j int) bool {
193 return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
195 ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
198 ctxt.pkgIdx = make(map[string]int32)
199 ctxt.defs = []*LSym{}
200 ctxt.hashed64defs = []*LSym{}
201 ctxt.hasheddefs = []*LSym{}
202 ctxt.nonpkgdefs = []*LSym{}
204 var idx, hashedidx, hashed64idx, nonpkgidx int32
205 ctxt.traverseSyms(traverseDefs, func(s *LSym) {
206 // if Pkgpath is unknown, cannot hash symbols with relocations, as it
207 // may reference named symbols whose names are not fully expanded.
208 if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
209 if s.Size <= 8 && len(s.R) == 0 && !strings.HasPrefix(s.Name, "type.") {
210 // We can use short hash only for symbols without relocations.
211 // Don't use short hash for type symbols, as they need special handling.
212 s.PkgIdx = goobj.PkgIdxHashed64
213 s.SymIdx = hashed64idx
214 if hashed64idx != int32(len(ctxt.hashed64defs)) {
217 ctxt.hashed64defs = append(ctxt.hashed64defs, s)
220 s.PkgIdx = goobj.PkgIdxHashed
222 if hashedidx != int32(len(ctxt.hasheddefs)) {
225 ctxt.hasheddefs = append(ctxt.hasheddefs, s)
228 } else if isNonPkgSym(ctxt, s) {
229 s.PkgIdx = goobj.PkgIdxNone
231 if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
234 ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
237 s.PkgIdx = goobj.PkgIdxSelf
239 if idx != int32(len(ctxt.defs)) {
242 ctxt.defs = append(ctxt.defs, s)
245 s.Set(AttrIndexed, true)
248 ipkg := int32(1) // 0 is invalid index
249 nonpkgdef := nonpkgidx
250 ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
251 if rs.PkgIdx != goobj.PkgIdxInvalid {
254 if !ctxt.Flag_linkshared {
255 // Assign special index for builtin symbols.
256 // Don't do it when linking against shared libraries, as the runtime
257 // may be in a different library.
258 if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
259 rs.PkgIdx = goobj.PkgIdxBuiltin
261 rs.Set(AttrIndexed, true)
266 if rs.ContentAddressable() {
267 // for now, only support content-addressable symbols that are always locally defined.
268 panic("hashed refs unsupported for now")
270 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
271 rs.PkgIdx = goobj.PkgIdxNone
272 rs.SymIdx = nonpkgidx
273 rs.Set(AttrIndexed, true)
274 if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
277 ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
281 if k, ok := ctxt.pkgIdx[pkg]; ok {
286 ctxt.pkgIdx[pkg] = ipkg
291 // Returns whether s is a non-package symbol, which needs to be referenced
292 // by name instead of by index.
293 func isNonPkgSym(ctxt *Link, s *LSym) bool {
294 if ctxt.IsAsm && !s.Static() {
295 // asm symbols are referenced by name only, except static symbols
296 // which are file-local and can be referenced by index.
299 if ctxt.Flag_linkshared {
300 // The referenced symbol may be in a different shared library so
301 // the linker cannot see its index.
305 // The frontend uses package "_" to mark symbols that should not
306 // be referenced by index, e.g. linkname'd symbols.
310 // Dupok symbol needs to be dedup'd by name.
316 // StaticNamePref is the prefix the front end applies to static temporary
317 // variables. When turned into LSyms, these can be tagged as static so
318 // as to avoid inserting them into the linker's name lookup tables.
319 const StaticNamePref = ".stmp_"
321 type traverseFlag uint32
324 traverseDefs traverseFlag = 1 << iota
328 traverseAll = traverseDefs | traverseRefs | traverseAux
331 // Traverse symbols based on flag, call fn for each symbol.
332 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
333 lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
334 for _, list := range lists {
335 for _, s := range list {
336 if flag&traverseDefs != 0 {
339 if flag&traverseRefs != 0 {
340 for _, r := range s.R {
346 if flag&traverseAux != 0 {
350 if s.Type == objabi.STEXT {
351 f := func(parent *LSym, aux *LSym) {
354 ctxt.traverseFuncAux(flag, s, f)
361 func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym)) {
362 fninfo := fsym.Func()
364 if flag&traverseAux == 0 {
365 // NB: should it become necessary to walk aux sym reloc references
366 // without walking the aux syms themselves, this can be changed.
367 panic("should not be here")
369 for _, d := range pc.Funcdata {
374 files := ctxt.PosTable.FileTable()
375 usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
376 for f := range pc.UsedFiles {
377 usedFiles = append(usedFiles, f)
379 sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
380 for _, f := range usedFiles {
381 if filesym := ctxt.Lookup(files[f]); filesym != nil {
385 for _, call := range pc.InlTree.nodes {
386 if call.Func != nil {
389 f, _ := linkgetlineFromPos(ctxt, call.Pos)
390 if filesym := ctxt.Lookup(f); filesym != nil {
395 dwsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym}
396 for _, dws := range dwsyms {
397 if dws == nil || dws.Size == 0 {
401 if flag&traverseRefs != 0 {
402 for _, r := range dws.R {
411 // Traverse aux symbols, calling fn for each sym/aux pair.
412 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
413 lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
414 for _, list := range lists {
415 for _, s := range list {
417 if flag&traverseDefs != 0 {
421 if s.Type != objabi.STEXT {
424 ctxt.traverseFuncAux(flag, s, fn)