1 | // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_VM_ELF_H_ |
6 | #define RUNTIME_VM_ELF_H_ |
7 | |
8 | #include "platform/globals.h" |
9 | |
10 | #if defined(DART_PRECOMPILER) |
11 | #include "vm/allocation.h" |
12 | #include "vm/compiler/runtime_api.h" |
13 | #include "vm/datastream.h" |
14 | #include "vm/growable_array.h" |
15 | #include "vm/zone.h" |
16 | #endif |
17 | |
18 | namespace dart { |
19 | |
20 | // The max page size on all supported architectures. Used to determine |
21 | // the alignment of load segments, so that they are guaranteed page-aligned, |
22 | // and no ELF section or segment should have a larger alignment. |
23 | #if defined(DART_TARGET_OS_LINUX) && defined(TARGET_ARCH_ARM64) |
24 | // Some Linux distributions on ARM64 select 64 KB page size. |
25 | // Follow LLVM (https://reviews.llvm.org/D25079) and set maximum page size |
26 | // to 64 KB for ARM64 Linux builds. |
27 | static constexpr intptr_t kElfPageSize = 64 * KB; |
28 | #else |
29 | static constexpr intptr_t kElfPageSize = 16 * KB; |
30 | #endif |
31 | |
32 | #if defined(DART_PRECOMPILER) |
33 | |
34 | class Dwarf; |
35 | class ProgramTable; |
36 | class Section; |
37 | class SectionTable; |
38 | class SymbolTable; |
39 | |
40 | class Elf : public ZoneAllocated { |
41 | public: |
42 | enum class Type { |
43 | // A snapshot that should include segment contents. |
44 | Snapshot, |
45 | // Separately compiled debugging information that should not include |
46 | // most segment contents. |
47 | DebugInfo, |
48 | }; |
49 | |
50 | Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf = nullptr); |
51 | |
52 | static constexpr intptr_t kPageSize = kElfPageSize; |
53 | |
54 | bool IsStripped() const { return dwarf_ == nullptr; } |
55 | |
56 | Zone* zone() const { return zone_; } |
57 | const Dwarf* dwarf() const { return dwarf_; } |
58 | Dwarf* dwarf() { return dwarf_; } |
59 | const SymbolTable& symtab() const { |
60 | ASSERT(symtab_ != nullptr); |
61 | return *symtab_; |
62 | } |
63 | const SectionTable& section_table() const { return *section_table_; } |
64 | |
65 | // Stores the information needed to appropriately generate a |
66 | // relocation from the target to the source at the given section offset. |
67 | struct Relocation { |
68 | size_t size_in_bytes; |
69 | intptr_t section_offset; |
70 | intptr_t source_label; |
71 | intptr_t source_offset; |
72 | intptr_t target_label; |
73 | intptr_t target_offset; |
74 | |
75 | // Used when the corresponding offset is relative from the location of the |
76 | // relocation itself. |
77 | static constexpr intptr_t kSelfRelative = -1; |
78 | // Used when the corresponding offset is relative to the start of the |
79 | // snapshot. |
80 | static constexpr intptr_t kSnapshotRelative = -2; |
81 | |
82 | Relocation(size_t size_in_bytes, |
83 | intptr_t section_offset, |
84 | intptr_t source_label, |
85 | intptr_t source_offset, |
86 | intptr_t target_label, |
87 | intptr_t target_offset) |
88 | : size_in_bytes(size_in_bytes), |
89 | section_offset(section_offset), |
90 | source_label(source_label), |
91 | source_offset(source_offset), |
92 | target_label(target_label), |
93 | target_offset(target_offset) { |
94 | // Other than special values, all labels should be positive. |
95 | ASSERT(source_label > 0 || source_label == kSelfRelative || |
96 | source_label == kSnapshotRelative); |
97 | ASSERT(target_label > 0 || target_label == kSelfRelative || |
98 | target_label == kSnapshotRelative); |
99 | } |
100 | }; |
101 | |
102 | // Stores the information needed to appropriately generate a symbol |
103 | // during finalization. |
104 | struct SymbolData { |
105 | const char* name; |
106 | intptr_t type; |
107 | intptr_t offset; |
108 | size_t size; |
109 | // A positive unique ID only used internally in the Dart VM, not part of |
110 | // the Elf output. |
111 | intptr_t label; |
112 | |
113 | SymbolData(const char* name, |
114 | intptr_t type, |
115 | intptr_t offset, |
116 | size_t size, |
117 | intptr_t label) |
118 | : name(name), type(type), offset(offset), size(size), label(label) { |
119 | ASSERT(label > 0); |
120 | } |
121 | }; |
122 | |
123 | // Must be the same value as the values returned by ImageWriter::SectionLabel |
124 | // for the appropriate section and vm values. |
125 | static constexpr intptr_t kVmBssLabel = 5; |
126 | static constexpr intptr_t kIsolateBssLabel = 6; |
127 | static constexpr intptr_t kBuildIdLabel = 7; |
128 | |
129 | void AddText(const char* name, |
130 | intptr_t label, |
131 | const uint8_t* bytes, |
132 | intptr_t size, |
133 | const ZoneGrowableArray<Relocation>* relocations, |
134 | const ZoneGrowableArray<SymbolData>* symbol); |
135 | void AddROData(const char* name, |
136 | intptr_t label, |
137 | const uint8_t* bytes, |
138 | intptr_t size, |
139 | const ZoneGrowableArray<Relocation>* relocations, |
140 | const ZoneGrowableArray<SymbolData>* symbols); |
141 | |
142 | void Finalize(); |
143 | |
144 | private: |
145 | static constexpr const char kBuildIdNoteName[] = ".note.gnu.build-id" ; |
146 | static constexpr const char kTextName[] = ".text" ; |
147 | static constexpr const char kDataName[] = ".rodata" ; |
148 | static constexpr const char kBssName[] = ".bss" ; |
149 | static constexpr const char kDynamicTableName[] = ".dynamic" ; |
150 | |
151 | void CreateBSS(); |
152 | void GenerateBuildId(); |
153 | void InitializeSymbolTables(); |
154 | void FinalizeDwarfSections(); |
155 | void FinalizeEhFrame(); |
156 | void ComputeOffsets(); |
157 | |
158 | Zone* const zone_; |
159 | BaseWriteStream* const unwrapped_stream_; |
160 | const Type type_; |
161 | |
162 | // If nullptr, then the ELF file should be stripped of static information like |
163 | // the static symbol table (and its corresponding string table). |
164 | Dwarf* const dwarf_; |
165 | |
166 | // Contains all sections that will have entries in the section header table. |
167 | SectionTable* const section_table_; |
168 | |
169 | // Contains all segments in the program header table. Set after finalizing |
170 | // the section table. |
171 | ProgramTable* program_table_ = nullptr; |
172 | |
173 | // The static tables are always created for use in relocation calculations, |
174 | // even though they may not end up in the final ELF file. |
175 | SymbolTable* symtab_ = nullptr; |
176 | |
177 | friend class SectionTable; // For section name static fields. |
178 | }; |
179 | |
180 | #endif // DART_PRECOMPILER |
181 | |
182 | } // namespace dart |
183 | |
184 | #endif // RUNTIME_VM_ELF_H_ |
185 | |