• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 "ark_aot_linker.h"
17 #include "created_object_file.h"
18 
19 #include "transforms/transform_utils.h"
20 
21 #include <llvm/Transforms/Scalar.h>
22 #include <llvm/CodeGen/Passes.h>
23 #include <llvm/ExecutionEngine/SectionMemoryManager.h>
24 #include <llvm/IR/LLVMContext.h>
25 #include <llvm/Support/Debug.h>
26 
27 #define DEBUG_TYPE "ark-aot-linker"
28 
29 // NB: Do not include anything panda's. It may lead to macro collisions.
30 
31 namespace ark::llvmbackend {
32 
allowStubAllocation() const33 bool PandaSectionMemoryManager::allowStubAllocation() const
34 {
35     return false;
36 }
37 
allocateCodeSection(uintptr_t size,unsigned int alignment,unsigned int sectionId,llvm::StringRef sectionName)38 uint8_t *PandaSectionMemoryManager::allocateCodeSection(uintptr_t size, unsigned int alignment, unsigned int sectionId,
39                                                         llvm::StringRef sectionName)
40 {
41     auto memory = SectionMemoryManager::allocateCodeSection(size, alignment, sectionId, sectionName);
42     RememberAllocation(sectionName, memory, size, alignment);
43     return memory;
44 }
45 
allocateDataSection(uintptr_t size,unsigned int alignment,unsigned int sectionId,llvm::StringRef sectionName,bool readOnly)46 uint8_t *PandaSectionMemoryManager::allocateDataSection(uintptr_t size, unsigned int alignment, unsigned int sectionId,
47                                                         llvm::StringRef sectionName, bool readOnly)
48 {
49     auto memory = SectionMemoryManager::allocateDataSection(size, alignment, sectionId, sectionName, readOnly);
50     RememberAllocation(sectionName, memory, size, alignment);
51     return memory;
52 }
53 
GetSections() const54 const std::unordered_map<std::string, SectionReference> &PandaSectionMemoryManager::GetSections() const
55 {
56     return sections_;
57 }
58 
RememberAllocation(llvm::StringRef sectionName,uint8_t * memory,uintptr_t size,size_t alignment)59 void PandaSectionMemoryManager::RememberAllocation(llvm::StringRef sectionName, uint8_t *memory, uintptr_t size,
60                                                    size_t alignment)
61 {
62     static constexpr std::array SECTIONS_PREFIXES_TO_REMEMBER = {
63         TEXT_SECTION_PREFIX,     // .text.
64         RO_DATA_SECTION_PREFIX,  // .rodata
65         AOT_GOT_SECTION,         // .aot_got
66     };
67 
68     if (!llvm::any_of(SECTIONS_PREFIXES_TO_REMEMBER,
69                       [sectionName](auto prefix) { return sectionName.startswith(prefix); })) {
70         LLVM_DEBUG(llvm::dbgs() << "Not remembering allocation for '" << sectionName << "'\n");
71         return;
72     }
73 
74     SectionReference sectionReference {memory, size, sectionName.str(), alignment};
75     [[maybe_unused]] auto insertionResult = sections_.insert({sectionName.str(), sectionReference});
76     // Check if we've inserted section reference.
77     // If we did not, then there is a section duplicate, which we cannot handle
78     ASSERT(insertionResult.second);
79     LLVM_DEBUG(llvm::dbgs() << "Remembered allocation for '" << sectionName << "', its address = " << memory
80                             << ", its size = " << size << '\n');
81 }
82 
83 ArkAotLinker::~ArkAotLinker() = default;
84 
LoadObject(std::unique_ptr<CreatedObjectFile> objectFile)85 llvm::Error ArkAotLinker::LoadObject(std::unique_ptr<CreatedObjectFile> objectFile)
86 {
87     runtimeDyLd_.loadObject(*objectFile->GetObjectFile());
88     objects_.push_back(std::move(objectFile));
89     if (runtimeDyLd_.hasError()) {
90         return llvm::createStringError(llvm::inconvertibleErrorCode(),
91                                        "Could not load object file, error = '" + runtimeDyLd_.getErrorString() + "'");
92     }
93     return llvm::Error::success();
94 }
95 
GetLinkedSection(const std::string & name) const96 SectionReference ArkAotLinker::GetLinkedSection(const std::string &name) const
97 {
98     const auto &sections = memoryManager_.GetSections();
99     ASSERT(sections.find(name) != sections.end() && "Attempt to access an unknown linked section");
100     return sections.at(name);
101 }
102 
GetLinkedFunctionSection(const std::string & fullFunctionName) const103 SectionReference ArkAotLinker::GetLinkedFunctionSection(const std::string &fullFunctionName) const
104 {
105     return GetLinkedSection(".text." + fullFunctionName + ".");
106 }
107 
GetLinkedRoDataSections() const108 ArkAotLinker::RoDataSections ArkAotLinker::GetLinkedRoDataSections() const
109 {
110     RoDataSections references;
111 
112     for (const auto &file : objects_) {
113         for (const auto &section : file->GetRoDataSections()) {
114             references.push_back(GetLinkedSection(section.GetName()));
115         }
116     }
117     return references;
118 }
119 
RelocateSections(const std::unordered_map<std::string,size_t> & sectionAddresses,const std::unordered_map<std::string,size_t> & methodOffsets,uint32_t moduleId)120 llvm::Error ArkAotLinker::RelocateSections(const std::unordered_map<std::string, size_t> &sectionAddresses,
121                                            const std::unordered_map<std::string, size_t> &methodOffsets,
122                                            uint32_t moduleId)
123 {
124     for (const auto &objectFile : objects_) {
125         for (auto section : objectFile->GetObjectFile()->sections()) {
126             llvm::StringRef name = cantFail(section.getName());
127 
128             bool functionSection = name.startswith(TEXT_SECTION_PREFIX);
129             bool roDataSection = name.startswith(RO_DATA_SECTION_PREFIX);
130             bool aotGotSection = name.startswith(AOT_GOT_SECTION);
131 
132             if (functionSection) {
133                 RelocateFunctionSection(memoryManager_.GetSections().at(name.str()), sectionAddresses, methodOffsets);
134             }
135             if (roDataSection || aotGotSection) {
136                 RelocateSection(memoryManager_.GetSections().at(name.str()), sectionAddresses, moduleId);
137             }
138         }
139     }
140     runtimeDyLd_.resolveRelocations();
141     if (runtimeDyLd_.hasError()) {
142         return llvm::createStringError(llvm::inconvertibleErrorCode(),
143                                        "Could not relocate sections, error = '" + runtimeDyLd_.getErrorString() + "'");
144     }
145     return llvm::Error::success();
146 }
147 
RelocateFunctionSection(const SectionReference & sectionReference,const std::unordered_map<std::string,size_t> & sectionAddresses,const std::unordered_map<std::string,size_t> & methodOffsets)148 void ArkAotLinker::RelocateFunctionSection(const SectionReference &sectionReference,
149                                            const std::unordered_map<std::string, size_t> &sectionAddresses,
150                                            const std::unordered_map<std::string, size_t> &methodOffsets)
151 {
152     if (sectionReference.GetMemory() == nullptr) {
153         return;
154     }
155     auto sectionStart = sectionAddresses.find(".text");
156     if (sectionStart == sectionAddresses.end()) {
157         return;
158     }
159 
160     // Section name = ".text." + fullMethodName
161     constexpr auto METHOD_NAME_START = std::string_view(".text.").length();
162     std::string methodName = sectionReference.GetName().substr(METHOD_NAME_START);
163     methodName.pop_back();  // remove addition dot
164     auto methodOffset = methodOffsets.find(methodName);
165     if (methodOffset == methodOffsets.end()) {
166         return;
167     }
168 
169     size_t targetAddress = sectionStart->second + methodOffset->second + functionHeaderSize_;
170     runtimeDyLd_.mapSectionAddress(sectionReference.GetMemory(), targetAddress);
171     LLVM_DEBUG(llvm::dbgs() << "Relocated section '" << sectionReference.GetName()
172                             << "' (size = " << sectionReference.GetSize() << ") to " << targetAddress << '\n');
173 }
174 
RelocateSection(const SectionReference & sectionReference,const std::unordered_map<std::string,size_t> & sectionAddresses,uint32_t moduleId)175 void ArkAotLinker::RelocateSection(const SectionReference &sectionReference,
176                                    const std::unordered_map<std::string, size_t> &sectionAddresses, uint32_t moduleId)
177 {
178     if (sectionReference.GetMemory() == nullptr) {
179         return;
180     }
181 
182     auto toFind = sectionReference.GetName();
183     if (toFind.find(RO_DATA_SECTION_PREFIX) == 0) {
184         toFind += std::to_string(moduleId);
185     }
186 
187     auto sectionStart = sectionAddresses.find(toFind);
188     if (sectionStart == sectionAddresses.end()) {
189         return;
190     }
191 
192     runtimeDyLd_.mapSectionAddress(sectionReference.GetMemory(), sectionStart->second);
193     LLVM_DEBUG(llvm::dbgs() << "Relocated section '" << sectionReference.GetName()
194                             << "' (size = " << sectionReference.GetSize() << ") to " << sectionStart->second << '\n');
195 }
196 
ArkAotLinker(size_t functionHeaderSize)197 ArkAotLinker::ArkAotLinker(size_t functionHeaderSize) : functionHeaderSize_(functionHeaderSize)
198 {
199     runtimeDyLd_.setProcessAllSections(true);
200 }
201 
202 }  // namespace ark::llvmbackend
203