1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "aot_file.h"
17 #include "compiler/optimizer/ir/inst.h"
18 #include "optimizer/ir/runtime_interface.h"
19 #include "utils/logger.h"
20 #include "code_info/code_info.h"
21 #include "mem/gc/gc_types.h"
22 #include "trace/trace.h"
23 #include "entrypoints/entrypoints.h"
24
25 // In some targets, runtime library is not linked, so linker will fail while searching CallStaticPltResolver symbol.
26 // To solve this issue, we define this function as weak.
27 // NOTE(msherstennikov): find a better way instead of weak function, e.g. make aot_manager library static.
28 extern "C" void CallStaticPltResolver([[maybe_unused]] void *slot) __attribute__((weak));
CallStaticPltResolver(void * slot)29 extern "C" void CallStaticPltResolver([[maybe_unused]] void *slot) {}
30
31 namespace ark::compiler {
LoadSymbol(const ark::os::library_loader::LibraryHandle & handle,const char * name)32 static inline Expected<const uint8_t *, std::string> LoadSymbol(const ark::os::library_loader::LibraryHandle &handle,
33 const char *name)
34 {
35 auto sym = ark::os::library_loader::ResolveSymbol(handle, name);
36 if (!sym) {
37 return Unexpected(sym.Error().ToString());
38 }
39 return reinterpret_cast<uint8_t *>(sym.Value());
40 }
41
42 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
43 #define LOAD_AOT_SYMBOL(name) \
44 auto name = LoadSymbol(handle, (#name)); \
45 if (!(name)) { \
46 return Unexpected("Cannot load name section: " + (name).Error()); \
47 }
48
Open(const std::string & fileName,uint32_t gcType,bool forDump)49 Expected<std::unique_ptr<AotFile>, std::string> AotFile::Open(const std::string &fileName, uint32_t gcType,
50 bool forDump)
51 {
52 trace::ScopedTrace scopedTrace("Open aot file " + fileName);
53 auto handleLoad = ark::os::library_loader::Load(fileName);
54 if (!handleLoad) {
55 return Unexpected("AOT elf library open failed: " + handleLoad.Error().ToString());
56 }
57 auto handle = std::move(handleLoad.Value());
58
59 LOAD_AOT_SYMBOL(aot);
60 LOAD_AOT_SYMBOL(aot_end);
61 LOAD_AOT_SYMBOL(code);
62 LOAD_AOT_SYMBOL(code_end);
63
64 if (code_end.Value() < code.Value() || aot_end.Value() <= aot.Value()) {
65 return Unexpected(std::string("Invalid symbols"));
66 }
67
68 auto aotHeader = reinterpret_cast<const AotHeader *>(aot.Value());
69 if (aotHeader->magic != MAGIC) {
70 return Unexpected(std::string("Wrong AotHeader magic"));
71 }
72
73 if (aotHeader->version != VERSION) {
74 return Unexpected(std::string("Wrong AotHeader version"));
75 }
76
77 if (!forDump && aotHeader->environmentChecksum != RuntimeInterface::GetEnvironmentChecksum(RUNTIME_ARCH)) {
78 return Unexpected(std::string("Compiler environment checksum mismatch"));
79 }
80
81 if (!forDump && aotHeader->gcType != gcType) {
82 return Unexpected(std::string("Wrong AotHeader gc-type: ") +
83 std::string(mem::GCStringFromType(static_cast<mem::GCType>(aotHeader->gcType))) + " vs " +
84 std::string(mem::GCStringFromType(static_cast<mem::GCType>(gcType))));
85 }
86 return std::make_unique<AotFile>(std::move(handle), Span(aot.Value(), aot_end.Value() - aot.Value()),
87 Span(code.Value(), code_end.Value() - code.Value()));
88 }
89
InitializeGot(RuntimeInterface * runtime)90 void AotFile::InitializeGot(RuntimeInterface *runtime)
91 {
92 size_t minusFirstSlot = static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT) + 1;
93 auto *table = const_cast<uintptr_t *>(
94 reinterpret_cast<const uintptr_t *>(code_.data() - minusFirstSlot * PointerSize(RUNTIME_ARCH)));
95 ASSERT(BitsToBytesRoundUp(MinimumBitsToStore(static_cast<uint32_t>(AotSlotType::COUNT) - 1)) == 1);
96 while (*table != 0) {
97 switch (GetByteFrom(*table, 0U)) {
98 case AotSlotType::PLT_SLOT:
99 table -= 2U; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
100 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
101 table[1] = reinterpret_cast<uintptr_t>(CallStaticPltResolver);
102 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
103 table[2U] = reinterpret_cast<uintptr_t>(
104 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
105 table + 1 - runtime->GetCompiledEntryPointOffset(RUNTIME_ARCH) / sizeof(uintptr_t));
106 break;
107 case AotSlotType::VTABLE_INDEX:
108 table--; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
109 table[1] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
110 break;
111 case AotSlotType::CLASS_SLOT:
112 table -= 2U; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
113 table[1] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
114 table[2U] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
115 break;
116 case AotSlotType::STRING_SLOT:
117 table--; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
118 table[1] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
119 break;
120 case AotSlotType::INLINECACHE_SLOT:
121 break;
122 case AotSlotType::COMMON_SLOT:
123 table[0] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
124 break;
125 default:
126 UNREACHABLE();
127 break;
128 }
129 table--; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
130 }
131 }
132
PatchTable(RuntimeInterface * runtime)133 void AotFile::PatchTable(RuntimeInterface *runtime)
134 {
135 auto *table = const_cast<uintptr_t *>(reinterpret_cast<const uintptr_t *>(
136 code_.data() - static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT) * PointerSize(RUNTIME_ARCH)));
137 for (size_t i = 0; i < static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT); i++) {
138 IntrinsicInst inst(Opcode::Intrinsic, static_cast<RuntimeInterface::IntrinsicId>(i));
139 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
140 table[i] = runtime->GetIntrinsicAddress(inst.IsRuntimeCall(), SourceLanguage::INVALID,
141 static_cast<RuntimeInterface::IntrinsicId>(i));
142 }
143 }
144
GetClass(uint32_t classId) const145 AotClass AotPandaFile::GetClass(uint32_t classId) const
146 {
147 auto classes = aotFile_->GetClassHeaders(*header_);
148 auto it = std::lower_bound(classes.begin(), classes.end(), classId,
149 [](const auto &a, uintptr_t klassId) { return a.classId < klassId; });
150 if (it == classes.end() || it->classId != classId) {
151 return {};
152 }
153 ASSERT(it->methodsCount != 0 && "AOT file shall not contain empty classes");
154 return AotClass(aotFile_, &*it);
155 }
156
FindMethodCodeEntry(size_t index) const157 const void *AotClass::FindMethodCodeEntry(size_t index) const
158 {
159 auto methodHeader = FindMethodHeader(index);
160 if (methodHeader == nullptr) {
161 return nullptr;
162 }
163
164 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
165 return aotFile_->GetMethodCode(methodHeader) + CodeInfo::GetCodeOffset(RUNTIME_ARCH);
166 }
167
FindMethodCodeSpan(size_t index) const168 Span<const uint8_t> AotClass::FindMethodCodeSpan(size_t index) const
169 {
170 auto methodHeader = FindMethodHeader(index);
171 if (methodHeader == nullptr) {
172 return {};
173 }
174 auto code = Span(aotFile_->GetMethodCode(methodHeader), methodHeader->codeSize);
175 return CodeInfo(code).GetCodeSpan();
176 }
177
FindMethodHeader(size_t index) const178 const MethodHeader *AotClass::FindMethodHeader(size_t index) const
179 {
180 auto bitmap = GetBitmap();
181 CHECK_LT(index, bitmap.size());
182 if (!bitmap[index]) {
183 return nullptr;
184 }
185 auto methodIndex = bitmap.PopCount(index);
186 ASSERT(methodIndex < header_->methodsCount);
187 return aotFile_->GetMethodHeader(header_->methodsOffset + methodIndex);
188 }
189
GetBitmap() const190 BitVectorSpan AotClass::GetBitmap() const
191 {
192 // NOTE(msherstennikov): remove const_cast once BitVector support constant storage
193 auto bitmapBase = const_cast<uint32_t *>(reinterpret_cast<const uint32_t *>(aotFile_->GetMethodsBitmap()));
194 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
195 return BitVectorSpan(bitmapBase + header_->methodsBitmapOffset, header_->methodsBitmapSize);
196 }
197
198 } // namespace ark::compiler
199