• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     /* CC-OFFNXT(G.PRE.02) name part */                                   \
45     auto name = LoadSymbol(handle, (#name));                              \
46     if (!(name)) {                                                        \
47         /* CC-OFFNXT(G.PRE.05) code generation */                         \
48         return Unexpected("Cannot load name section: " + (name).Error()); \
49     }
50 
Open(const std::string & fileName,uint32_t gcType,bool forDump)51 Expected<std::unique_ptr<AotFile>, std::string> AotFile::Open(const std::string &fileName, uint32_t gcType,
52                                                               bool forDump)
53 {
54     trace::ScopedTrace scopedTrace("Open aot file " + fileName);
55     auto handleLoad = ark::os::library_loader::Load(fileName);
56     if (!handleLoad) {
57         return Unexpected("AOT elf library open failed: " + handleLoad.Error().ToString());
58     }
59     auto handle = std::move(handleLoad.Value());
60 
61     LOAD_AOT_SYMBOL(aot);
62     LOAD_AOT_SYMBOL(aot_end);
63     LOAD_AOT_SYMBOL(code);
64     LOAD_AOT_SYMBOL(code_end);
65 
66     if (code_end.Value() < code.Value() || aot_end.Value() <= aot.Value()) {
67         return Unexpected(std::string("Invalid symbols"));
68     }
69 
70     auto aotHeader = reinterpret_cast<const AotHeader *>(aot.Value());
71     if (aotHeader->magic != MAGIC) {
72         return Unexpected(std::string("Wrong AotHeader magic"));
73     }
74 
75     if (aotHeader->version != VERSION) {
76         return Unexpected(std::string("Wrong AotHeader version"));
77     }
78 
79     if (!forDump && aotHeader->environmentChecksum != RuntimeInterface::GetEnvironmentChecksum(RUNTIME_ARCH)) {
80         return Unexpected(std::string("Compiler environment checksum mismatch"));
81     }
82 
83     if (!forDump && aotHeader->gcType != gcType) {
84         return Unexpected(std::string("Wrong AotHeader gc-type: ") +
85                           std::string(mem::GCStringFromType(static_cast<mem::GCType>(aotHeader->gcType))) + " vs " +
86                           std::string(mem::GCStringFromType(static_cast<mem::GCType>(gcType))));
87     }
88     return std::make_unique<AotFile>(std::move(handle), Span(aot.Value(), aot_end.Value() - aot.Value()),
89                                      Span(code.Value(), code_end.Value() - code.Value()));
90 }
91 
InitializeGot(RuntimeInterface * runtime)92 void AotFile::InitializeGot(RuntimeInterface *runtime)
93 {
94     size_t minusFirstSlot = static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT) + 1;
95     auto *table = const_cast<uintptr_t *>(
96         reinterpret_cast<const uintptr_t *>(code_.data() - minusFirstSlot * PointerSize(RUNTIME_ARCH)));
97     ASSERT(BitsToBytesRoundUp(MinimumBitsToStore(static_cast<uint32_t>(AotSlotType::COUNT) - 1)) == 1);
98     while (*table != 0) {
99         switch (GetByteFrom(*table, 0U)) {
100             case AotSlotType::PLT_SLOT:
101                 table -= 2U;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
102                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
103                 table[1] = reinterpret_cast<uintptr_t>(CallStaticPltResolver);
104                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
105                 table[2U] = reinterpret_cast<uintptr_t>(
106                     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
107                     table + 1 - runtime->GetCompiledEntryPointOffset(RUNTIME_ARCH) / sizeof(uintptr_t));
108                 break;
109             case AotSlotType::VTABLE_INDEX:
110                 table--;       // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
111                 table[1] = 0;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
112                 break;
113             case AotSlotType::CLASS_SLOT:
114                 table -= 2U;    // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
115                 table[1] = 0;   // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
116                 table[2U] = 0;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
117                 break;
118             case AotSlotType::STRING_SLOT:
119                 table--;       // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
120                 table[1] = 0;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
121                 break;
122             case AotSlotType::INLINECACHE_SLOT:
123                 break;
124             case AotSlotType::COMMON_SLOT:
125                 table[0] = 0;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
126                 break;
127             default:
128                 UNREACHABLE();
129                 break;
130         }
131         table--;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
132     }
133 }
134 
PatchTable(RuntimeInterface * runtime)135 void AotFile::PatchTable(RuntimeInterface *runtime)
136 {
137     auto *table = const_cast<uintptr_t *>(reinterpret_cast<const uintptr_t *>(
138         code_.data() - static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT) * PointerSize(RUNTIME_ARCH)));
139     for (size_t i = 0; i < static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT); i++) {
140         IntrinsicInst inst(Opcode::Intrinsic, static_cast<RuntimeInterface::IntrinsicId>(i));
141         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
142         table[i] = runtime->GetIntrinsicAddress(inst.IsRuntimeCall(), SourceLanguage::INVALID,
143                                                 static_cast<RuntimeInterface::IntrinsicId>(i));
144     }
145 }
146 
GetClass(uint32_t classId) const147 AotClass AotPandaFile::GetClass(uint32_t classId) const
148 {
149     auto classes = aotFile_->GetClassHeaders(*header_);
150     auto it = std::lower_bound(classes.begin(), classes.end(), classId,
151                                [](const auto &a, uintptr_t klassId) { return a.classId < klassId; });
152     if (it == classes.end() || it->classId != classId) {
153         return {};
154     }
155     ASSERT(it->methodsCount != 0 && "AOT file shall not contain empty classes");
156     return AotClass(aotFile_, &*it);
157 }
158 
FindMethodCodeEntry(size_t index) const159 const void *AotClass::FindMethodCodeEntry(size_t index) const
160 {
161     auto methodHeader = FindMethodHeader(index);
162     if (methodHeader == nullptr) {
163         return nullptr;
164     }
165 
166     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
167     return aotFile_->GetMethodCode(methodHeader) + CodeInfo::GetCodeOffset(RUNTIME_ARCH);
168 }
169 
FindMethodCodeSpan(size_t index) const170 Span<const uint8_t> AotClass::FindMethodCodeSpan(size_t index) const
171 {
172     auto methodHeader = FindMethodHeader(index);
173     if (methodHeader == nullptr) {
174         return {};
175     }
176     auto code = Span(aotFile_->GetMethodCode(methodHeader), methodHeader->codeSize);
177     return CodeInfo(code).GetCodeSpan();
178 }
179 
FindMethodHeader(size_t index) const180 const MethodHeader *AotClass::FindMethodHeader(size_t index) const
181 {
182     auto bitmap = GetBitmap();
183     CHECK_LT(index, bitmap.size());
184     if (!bitmap[index]) {
185         return nullptr;
186     }
187     auto methodIndex = bitmap.PopCount(index);
188     ASSERT(methodIndex < header_->methodsCount);
189     return aotFile_->GetMethodHeader(header_->methodsOffset + methodIndex);
190 }
191 
GetBitmap() const192 BitVectorSpan AotClass::GetBitmap() const
193 {
194     // NOTE(msherstennikov): remove const_cast once BitVector support constant storage
195     auto bitmapBase = const_cast<uint32_t *>(reinterpret_cast<const uint32_t *>(aotFile_->GetMethodsBitmap()));
196     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
197     return BitVectorSpan(bitmapBase + header_->methodsBitmapOffset, header_->methodsBitmapSize);
198 }
199 
200 }  // namespace ark::compiler
201