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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
| //===- Core/DefinedAtom.h - An Atom with content --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_DEFINED_ATOM_H
#define LLD_CORE_DEFINED_ATOM_H
#include "lld/Common/LLVM.h"
#include "lld/Core/Atom.h"
#include "lld/Core/Reference.h"
#include "llvm/Support/ErrorHandling.h"
namespace lld {
class File;
/// The fundamental unit of linking.
///
/// A C function or global variable is an atom. An atom has content and
/// attributes. The content of a function atom is the instructions that
/// implement the function. The content of a global variable atom is its
/// initial bytes.
///
/// Here are some example attribute sets for common atoms. If a particular
/// attribute is not listed, the default values are: definition=regular,
/// sectionChoice=basedOnContent, scope=translationUnit, merge=no,
/// deadStrip=normal, interposable=no
///
/// C function: void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global
///
/// C static function: staic void func() {} <br>
/// name=func, type=code, perm=r_x
///
/// C global variable: int count = 1; <br>
/// name=count, type=data, perm=rw_, scope=global
///
/// C tentative definition: int bar; <br>
/// name=bar, type=zerofill, perm=rw_, scope=global,
/// merge=asTentative, interposable=yesAndRuntimeWeak
///
/// Uninitialized C static variable: static int stuff; <br>
/// name=stuff, type=zerofill, perm=rw_
///
/// Weak C function: __attribute__((weak)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, merge=asWeak
///
/// Hidden C function: __attribute__((visibility("hidden"))) void foo() {}<br>
/// name=foo, type=code, perm=r_x, scope=linkageUnit
///
/// No-dead-strip function: __attribute__((used)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, deadStrip=never
///
/// Non-inlined C++ inline method: inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
/// mergeDupes=asWeak
///
/// Non-inlined C++ inline method whose address is taken:
/// inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
/// mergeDupes=asAddressedWeak
///
/// literal c-string: "hello" <br>
/// name="" type=cstring, perm=r__, scope=linkageUnit
///
/// literal double: 1.234 <br>
/// name="" type=literal8, perm=r__, scope=linkageUnit
///
/// constant: { 1,2,3 } <br>
/// name="" type=constant, perm=r__, scope=linkageUnit
///
/// Pointer to initializer function: <br>
/// name="" type=initializer, perm=rw_l,
/// sectionChoice=customRequired
///
/// C function place in custom section: __attribute__((section("__foo")))
/// void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global,
/// sectionChoice=customRequired, customSectionName=__foo
///
class DefinedAtom : public Atom {
public:
enum Interposable {
interposeNo, // linker can directly bind uses of this atom
interposeYes, // linker must indirect (through GOT) uses
interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
// linked image
};
enum Merge {
mergeNo, // Another atom with same name is error
mergeAsTentative, // Is ANSI C tentative definition, can be coalesced
mergeAsWeak, // Is C++ inline definition that was not inlined,
// but address was not taken, so atom can be hidden
// by linker
mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose
// address was taken.
mergeSameNameAndSize, // Another atom with different size is error
mergeByLargestSection, // Choose an atom whose section is the largest.
mergeByContent, // Merge with other constants with same content.
};
enum ContentType {
typeUnknown, // for use with definitionUndefined
typeMachHeader, // atom representing mach_header [Darwin]
typeCode, // executable code
typeResolver, // function which returns address of target
typeBranchIsland, // linker created for large binaries
typeBranchShim, // linker created to switch thumb mode
typeStub, // linker created for calling external function
typeStubHelper, // linker created for initial stub binding
typeConstant, // a read-only constant
typeCString, // a zero terminated UTF8 C string
typeUTF16String, // a zero terminated UTF16 string
typeCFI, // a FDE or CIE from dwarf unwind info
typeLSDA, // extra unwinding info
typeLiteral4, // a four-btye read-only constant
typeLiteral8, // an eight-btye read-only constant
typeLiteral16, // a sixteen-btye read-only constant
typeData, // read-write data
typeDataFast, // allow data to be quickly accessed
typeZeroFill, // zero-fill data
typeZeroFillFast, // allow zero-fill data to be quicky accessed
typeConstData, // read-only data after dynamic linker is done
typeObjC1Class, // ObjC1 class [Darwin]
typeLazyPointer, // pointer through which a stub jumps
typeLazyDylibPointer, // pointer through which a stub jumps [Darwin]
typeNonLazyPointer, // pointer to external symbol
typeCFString, // NS/CFString object [Darwin]
typeGOT, // pointer to external symbol
typeInitializerPtr, // pointer to initializer function
typeTerminatorPtr, // pointer to terminator function
typeCStringPtr, // pointer to UTF8 C string [Darwin]
typeObjCClassPtr, // pointer to ObjC class [Darwin]
typeObjC2CategoryList, // pointers to ObjC category [Darwin]
typeObjCImageInfo, // pointer to ObjC class [Darwin]
typeObjCMethodList, // pointer to ObjC method list [Darwin]
typeDTraceDOF, // runtime data for Dtrace [Darwin]
typeInterposingTuples, // tuples of interposing info for dyld [Darwin]
typeTempLTO, // temporary atom for bitcode reader
typeCompactUnwindInfo, // runtime data for unwinder [Darwin]
typeProcessedUnwindInfo,// compressed compact unwind info [Darwin]
typeThunkTLV, // thunk used to access a TLV [Darwin]
typeTLVInitialData, // initial data for a TLV [Darwin]
typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
typeTLVInitializerPtr, // pointer to thread local initializer [Darwin]
typeDSOHandle, // atom representing DSO handle [Darwin]
typeSectCreate, // Created via the -sectcreate option [Darwin]
};
// Permission bits for atoms and segments. The order of these values are
// important, because the layout pass may sort atoms by permission if other
// attributes are the same.
enum ContentPermissions {
perm___ = 0, // mapped as unaccessible
permR__ = 8, // mapped read-only
permRW_ = 8 + 2, // mapped readable and writable
permRW_L = 8 + 2 + 1, // initially mapped r/w, then made read-only
// loader writable
permR_X = 8 + 4, // mapped readable and executable
permRWX = 8 + 2 + 4, // mapped readable and writable and executable
permUnknown = 16 // unknown or invalid permissions
};
enum SectionChoice {
sectionBasedOnContent, // linker infers final section based on content
sectionCustomPreferred, // linker may place in specific section
sectionCustomRequired // linker must place in specific section
};
enum DeadStripKind {
deadStripNormal, // linker may dead strip this atom
deadStripNever, // linker must never dead strip this atom
deadStripAlways // linker must remove this atom if unused
};
enum DynamicExport {
/// The linker may or may not export this atom dynamically depending
/// on the output type and other context of the link.
dynamicExportNormal,
/// The linker will always export this atom dynamically.
dynamicExportAlways,
};
// Attributes describe a code model used by the atom.
enum CodeModel {
codeNA, // no specific code model
// MIPS code models
codeMipsPIC, // PIC function in a PIC / non-PIC mixed file
codeMipsMicro, // microMIPS instruction encoding
codeMipsMicroPIC, // microMIPS instruction encoding + PIC
codeMips16, // MIPS-16 instruction encoding
// ARM code models
codeARMThumb, // ARM Thumb instruction set
codeARM_a, // $a-like mapping symbol (for ARM code)
codeARM_d, // $d-like mapping symbol (for data)
codeARM_t, // $t-like mapping symbol (for Thumb code)
};
struct Alignment {
Alignment(int v, int m = 0) : value(v), modulus(m) {}
uint16_t value;
uint16_t modulus;
bool operator==(const Alignment &rhs) const {
return (value == rhs.value) && (modulus == rhs.modulus);
}
};
/// returns a value for the order of this Atom within its file.
///
/// This is used by the linker to order the layout of Atoms so that the
/// resulting image is stable and reproducible.
virtual uint64_t ordinal() const = 0;
/// the number of bytes of space this atom's content will occupy in the
/// final linked image.
///
/// For a function atom, it is the number of bytes of code in the function.
virtual uint64_t size() const = 0;
/// The size of the section from which the atom is instantiated.
///
/// Merge::mergeByLargestSection is defined in terms of section size
/// and not in terms of atom size, so we need this function separate
/// from size().
virtual uint64_t sectionSize() const { return 0; }
/// The visibility of this atom to other atoms.
///
/// C static functions have scope scopeTranslationUnit. Regular C functions
/// have scope scopeGlobal. Functions compiled with visibility=hidden have
/// scope scopeLinkageUnit so they can be see by other atoms being linked but
/// not by the OS loader.
virtual Scope scope() const = 0;
/// Whether the linker should use direct or indirect access to this
/// atom.
virtual Interposable interposable() const = 0;
/// how the linker should handle if multiple atoms have the same name.
virtual Merge merge() const = 0;
/// The type of this atom, such as code or data.
virtual ContentType contentType() const = 0;
/// The alignment constraints on how this atom must be laid out in the
/// final linked image (e.g. 16-byte aligned).
virtual Alignment alignment() const = 0;
/// Whether this atom must be in a specially named section in the final
/// linked image, or if the linker can infer the section based on the
/// contentType().
virtual SectionChoice sectionChoice() const = 0;
/// If sectionChoice() != sectionBasedOnContent, then this return the
/// name of the section the atom should be placed into.
virtual StringRef customSectionName() const = 0;
/// constraints on whether the linker may dead strip away this atom.
virtual DeadStripKind deadStrip() const = 0;
/// Under which conditions should this atom be dynamically exported.
virtual DynamicExport dynamicExport() const {
return dynamicExportNormal;
}
/// Code model used by the atom.
virtual CodeModel codeModel() const { return codeNA; }
/// Returns the OS memory protections required for this atom's content
/// at runtime.
///
/// A function atom is R_X, a global variable is RW_, and a read-only constant
/// is R__.
virtual ContentPermissions permissions() const;
/// returns a reference to the raw (unrelocated) bytes of this Atom's
/// content.
virtual ArrayRef<uint8_t> rawContent() const = 0;
/// This class abstracts iterating over the sequence of References
/// in an Atom. Concrete instances of DefinedAtom must implement
/// the derefIterator() and incrementIterator() methods.
class reference_iterator {
public:
reference_iterator(const DefinedAtom &a, const void *it)
: _atom(a), _it(it) { }
const Reference *operator*() const {
return _atom.derefIterator(_it);
}
const Reference *operator->() const {
return _atom.derefIterator(_it);
}
bool operator==(const reference_iterator &other) const {
return _it == other._it;
}
bool operator!=(const reference_iterator &other) const {
return !(*this == other);
}
reference_iterator &operator++() {
_atom.incrementIterator(_it);
return *this;
}
private:
const DefinedAtom &_atom;
const void *_it;
};
/// Returns an iterator to the beginning of this Atom's References.
virtual reference_iterator begin() const = 0;
/// Returns an iterator to the end of this Atom's References.
virtual reference_iterator end() const = 0;
/// Adds a reference to this atom.
virtual void addReference(Reference::KindNamespace ns,
Reference::KindArch arch,
Reference::KindValue kindValue, uint64_t off,
const Atom *target, Reference::Addend a) {
llvm_unreachable("Subclass does not permit adding references");
}
static bool classof(const Atom *a) {
return a->definition() == definitionRegular;
}
/// Utility for deriving permissions from content type
static ContentPermissions permissions(ContentType type);
/// Utility function to check if the atom occupies file space
bool occupiesDiskSpace() const {
ContentType atomContentType = contentType();
return !(atomContentType == DefinedAtom::typeZeroFill ||
atomContentType == DefinedAtom::typeZeroFillFast ||
atomContentType == DefinedAtom::typeTLVInitialZeroFill);
}
/// Utility function to check if relocations in this atom to other defined
/// atoms can be implicitly generated, and so we don't need to explicitly
/// emit those relocations.
bool relocsToDefinedCanBeImplicit() const {
ContentType atomContentType = contentType();
return atomContentType == typeCFI;
}
protected:
// DefinedAtom is an abstract base class. Only subclasses can access
// constructor.
DefinedAtom() : Atom(definitionRegular) { }
~DefinedAtom() override = default;
/// Returns a pointer to the Reference object that the abstract
/// iterator "points" to.
virtual const Reference *derefIterator(const void *iter) const = 0;
/// Adjusts the abstract iterator to "point" to the next Reference
/// object for this Atom.
virtual void incrementIterator(const void *&iter) const = 0;
};
} // end namespace lld
#endif
|