aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/sym/attribute.go
blob: eda3fe60e4d232505fd4af65a59f5b8bd07661a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sym

import "sync/atomic"

// Attribute is a set of common symbol attributes.
type Attribute int32

const (
	// AttrDuplicateOK marks a symbol that can be present in multiple object
	// files.
	AttrDuplicateOK Attribute = 1 << iota
	// AttrExternal marks function symbols loaded from host object files.
	AttrExternal
	// AttrNoSplit marks functions that cannot split the stack; the linker
	// cares because it checks that there are no call chains of nosplit
	// functions that require more than StackLimit bytes (see
	// lib.go:dostkcheck)
	AttrNoSplit
	// AttrReachable marks symbols that are transitively referenced from the
	// entry points. Unreachable symbols are not written to the output.
	AttrReachable
	// AttrCgoExportDynamic and AttrCgoExportStatic mark symbols referenced
	// by directives written by cgo (in response to //export directives in
	// the source).
	AttrCgoExportDynamic
	AttrCgoExportStatic
	// AttrSpecial marks symbols that do not have their address (i.e. Value)
	// computed by the usual mechanism of data.go:dodata() &
	// data.go:address().
	AttrSpecial
	// AttrStackCheck is used by dostkcheck to only check each NoSplit
	// function's stack usage once.
	AttrStackCheck
	// AttrNotInSymbolTable marks symbols that are not written to the symbol table.
	AttrNotInSymbolTable
	// AttrOnList marks symbols that are on some list (such as the list of
	// all text symbols, or one of the lists of data symbols) and is
	// consulted to avoid bugs where a symbol is put on a list twice.
	AttrOnList
	// AttrLocal marks symbols that are only visible within the module
	// (executable or shared library) being linked. Only relevant when
	// dynamically linking Go code.
	AttrLocal
	// AttrReflectMethod marks certain methods from the reflect package that
	// can be used to call arbitrary methods. If no symbol with this bit set
	// is marked as reachable, more dead code elimination can be done.
	AttrReflectMethod
	// AttrMakeTypelink Amarks types that should be added to the typelink
	// table. See typelinks.go:typelinks().
	AttrMakeTypelink
	// AttrShared marks symbols compiled with the -shared option.
	AttrShared
	// AttrVisibilityHidden symbols are ELF symbols with
	// visibility set to STV_HIDDEN. They become local symbols in
	// the final executable. Only relevant when internally linking
	// on an ELF platform.
	AttrVisibilityHidden
	// AttrSubSymbol mostly means that the symbol appears on the Sub list of some
	// other symbol.  Unfortunately, it's not 100% reliable; at least, it's not set
	// correctly for the .TOC. symbol in Link.dodata.  Usually the Outer field of the
	// symbol points to the symbol whose list it is on, but that it is not set for the
	// symbols added to .windynamic in initdynimport in pe.go.
	//
	// TODO(mwhudson): fix the inconsistencies noticed above.
	//
	// Sub lists are used when loading host objects (sections from the host object
	// become regular linker symbols and symbols go on the Sub list of their section)
	// and for constructing the global offset table when internally linking a dynamic
	// executable.
	//
	// TODO(mwhudson): perhaps a better name for this is AttrNonGoSymbol.
	AttrSubSymbol
	// AttrContainer is set on text symbols that are present as the .Outer for some
	// other symbol.
	AttrContainer
	// AttrTopFrame means that the function is an entry point and unwinders
	// should stop when they hit this function.
	AttrTopFrame
	// AttrReadOnly indicates whether the symbol's content (Symbol.P) is backed by
	// read-only memory.
	AttrReadOnly
	// 19 attributes defined so far.
)

func (a *Attribute) load() Attribute { return Attribute(atomic.LoadInt32((*int32)(a))) }

func (a *Attribute) DuplicateOK() bool      { return a.load()&AttrDuplicateOK != 0 }
func (a *Attribute) External() bool         { return a.load()&AttrExternal != 0 }
func (a *Attribute) NoSplit() bool          { return a.load()&AttrNoSplit != 0 }
func (a *Attribute) Reachable() bool        { return a.load()&AttrReachable != 0 }
func (a *Attribute) CgoExportDynamic() bool { return a.load()&AttrCgoExportDynamic != 0 }
func (a *Attribute) CgoExportStatic() bool  { return a.load()&AttrCgoExportStatic != 0 }
func (a *Attribute) Special() bool          { return a.load()&AttrSpecial != 0 }
func (a *Attribute) StackCheck() bool       { return a.load()&AttrStackCheck != 0 }
func (a *Attribute) NotInSymbolTable() bool { return a.load()&AttrNotInSymbolTable != 0 }
func (a *Attribute) OnList() bool           { return a.load()&AttrOnList != 0 }
func (a *Attribute) Local() bool            { return a.load()&AttrLocal != 0 }
func (a *Attribute) ReflectMethod() bool    { return a.load()&AttrReflectMethod != 0 }
func (a *Attribute) MakeTypelink() bool     { return a.load()&AttrMakeTypelink != 0 }
func (a *Attribute) Shared() bool           { return a.load()&AttrShared != 0 }
func (a *Attribute) VisibilityHidden() bool { return a.load()&AttrVisibilityHidden != 0 }
func (a *Attribute) SubSymbol() bool        { return a.load()&AttrSubSymbol != 0 }
func (a *Attribute) Container() bool        { return a.load()&AttrContainer != 0 }
func (a *Attribute) TopFrame() bool         { return a.load()&AttrTopFrame != 0 }
func (a *Attribute) ReadOnly() bool         { return a.load()&AttrReadOnly != 0 }

func (a *Attribute) CgoExport() bool {
	return a.CgoExportDynamic() || a.CgoExportStatic()
}

func (a *Attribute) Set(flag Attribute, value bool) {
	// XXX it would be nice if we have atomic And, Or.
	for {
		a0 := a.load()
		var anew Attribute
		if value {
			anew = a0 | flag
		} else {
			anew = a0 &^ flag
		}
		if atomic.CompareAndSwapInt32((*int32)(a), int32(a0), int32(anew)) {
			return
		}
	}
}