1 //===---- ELF_x86_64.cpp -JIT linker implementation for ELF/x86-64 ----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // ELF/x86-64 jit-link implementation.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
14 #include "JITLinkGeneric.h"
15 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
16 #include "llvm/Object/ELFObjectFile.h"
18 #define DEBUG_TYPE "jitlink"
21 using namespace llvm::jitlink;
23 static const char *CommonSectionName = "__common";
28 // This should become a template as the ELFFile is so a lot of this could become
30 class ELFLinkGraphBuilder_x86_64 {
33 Section *CommonSection = nullptr;
34 // TODO hack to get this working
36 using SymbolTable = object::ELFFile<object::ELF64LE>::Elf_Shdr;
37 // For now we just assume
38 std::map<int32_t, Symbol *> JITSymbolTable;
40 Section &getCommonSection() {
42 auto Prot = static_cast<sys::Memory::ProtectionFlags>(
43 sys::Memory::MF_READ | sys::Memory::MF_WRITE);
44 CommonSection = &G->createSection(CommonSectionName, Prot);
46 return *CommonSection;
49 static Expected<ELF_x86_64_Edges::ELFX86RelocationKind>
50 getRelocationKind(const uint32_t Type) {
52 case ELF::R_X86_64_PC32:
53 return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32;
55 return make_error<JITLinkError>("Unsupported x86-64 relocation:" +
56 formatv("{0:d}", Type));
59 std::unique_ptr<LinkGraph> G;
60 // This could be a template
61 const object::ELFFile<object::ELF64LE> &Obj;
62 object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections;
65 bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; }
68 getEndianness(const object::ELFFile<object::ELF64LE> &Obj) {
69 return Obj.isLE() ? support::little : support::big;
72 // This could also just become part of a template
73 unsigned getPointerSize(const object::ELFFile<object::ELF64LE> &Obj) {
74 return Obj.getHeader()->getFileClass() == ELF::ELFCLASS64 ? 8 : 4;
77 // We don't technically need this right now
78 // But for now going to keep it as it helps me to debug things
80 Error createNormalizedSymbols() {
81 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
83 for (auto SecRef : sections) {
84 if (SecRef.sh_type != ELF::SHT_SYMTAB &&
85 SecRef.sh_type != ELF::SHT_DYNSYM)
88 auto Symbols = Obj.symbols(&SecRef);
89 // TODO: Currently I use this function to test things
90 // I also want to leave it to see if its common between MACH and elf
91 // so for now I just want to continue even if there is an error
92 if (errorToBool(Symbols.takeError()))
95 auto StrTabSec = Obj.getSection(SecRef.sh_link);
97 return StrTabSec.takeError();
98 auto StringTable = Obj.getStringTable(*StrTabSec);
100 return StringTable.takeError();
102 for (auto SymRef : *Symbols) {
103 Optional<StringRef> Name;
109 if (auto NameOrErr = SymRef.getName(*StringTable))
112 return NameOrErr.takeError();
117 dbgs() << "<anonymous symbol>";
120 dbgs() << ": value = " << formatv("{0:x16}", SymRef.getValue())
121 << ", type = " << formatv("{0:x2}", SymRef.getType())
122 << ", binding = " << SymRef.getBinding()
123 << ", size =" << Size;
128 return Error::success();
131 Error createNormalizedSections() {
132 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
133 for (auto &SecRef : sections) {
134 auto Name = Obj.getSectionName(&SecRef);
136 return Name.takeError();
137 sys::Memory::ProtectionFlags Prot;
138 if (SecRef.sh_flags & ELF::SHF_EXECINSTR) {
139 Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
140 sys::Memory::MF_EXEC);
142 Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
143 sys::Memory::MF_WRITE);
145 uint64_t Address = SecRef.sh_addr;
146 uint64_t Size = SecRef.sh_size;
147 uint64_t Flags = SecRef.sh_flags;
148 uint64_t Alignment = SecRef.sh_addralign;
149 const char *Data = nullptr;
150 // TODO: figure out what it is that has 0 size no name and address
159 dbgs() << " " << *Name << ": " << formatv("{0:x16}", Address) << " -- "
160 << formatv("{0:x16}", Address + Size) << ", align: " << Alignment
161 << " Flags:" << Flags << "\n";
164 if (SecRef.sh_type != ELF::SHT_NOBITS) {
165 // .sections() already checks that the data is not beyond the end of
167 auto contents = Obj.getSectionContentsAsArray<char>(&SecRef);
169 return contents.takeError();
171 Data = contents->data();
172 // TODO protection flags.
173 // for now everything is
174 auto §ion = G->createSection(*Name, Prot);
175 // Do this here because we have it, but move it into graphify later
176 G->createContentBlock(section, StringRef(Data, Size), Address,
178 if (SecRef.sh_type == ELF::SHT_SYMTAB)
184 return Error::success();
187 Error addRelocations() {
188 LLVM_DEBUG(dbgs() << "Adding relocations\n");
189 // TODO a partern is forming of iterate some sections but only give me
190 // ones I am interested, i should abstract that concept some where
191 for (auto &SecRef : sections) {
192 if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL)
194 // TODO can the elf obj file do this for me?
195 if (SecRef.sh_type == ELF::SHT_REL)
196 return make_error<llvm::StringError>("Shouldn't have REL in x64",
197 llvm::inconvertibleErrorCode());
199 auto RelSectName = Obj.getSectionName(&SecRef);
201 return RelSectName.takeError();
202 // Deal with .eh_frame later
203 if (*RelSectName == StringRef(".rela.eh_frame"))
206 auto UpdateSection = Obj.getSection(SecRef.sh_info);
208 return UpdateSection.takeError();
210 auto UpdateSectionName = Obj.getSectionName(*UpdateSection);
211 if (!UpdateSectionName)
212 return UpdateSectionName.takeError();
214 auto JITSection = G->findSectionByName(*UpdateSectionName);
216 return make_error<llvm::StringError>(
217 "Refencing a a section that wasn't added to graph" +
219 llvm::inconvertibleErrorCode());
221 auto Relocations = Obj.relas(&SecRef);
223 return Relocations.takeError();
225 for (const auto &Rela : *Relocations) {
226 auto Type = Rela.getType(false);
229 dbgs() << "Relocation Type: " << Type << "\n"
230 << "Name: " << Obj.getRelocationTypeName(Type) << "\n";
233 auto Symbol = Obj.getRelocationSymbol(&Rela, &SymTab);
235 return Symbol.takeError();
237 auto BlockToFix = *(JITSection->blocks().begin());
238 auto TargetSymbol = JITSymbolTable[(*Symbol)->st_shndx];
239 uint64_t Addend = Rela.r_addend;
240 JITTargetAddress FixupAddress =
241 (*UpdateSection)->sh_addr + Rela.r_offset;
244 dbgs() << "Processing relocation at "
245 << format("0x%016" PRIx64, FixupAddress) << "\n";
247 auto Kind = getRelocationKind(Type);
249 return Kind.takeError();
252 Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
254 // TODO a mapping of KIND => type then call getRelocationTypeName4
255 printEdge(dbgs(), *BlockToFix, GE, StringRef(""));
258 BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
259 *TargetSymbol, Addend);
262 return Error::success();
265 Error graphifyRegularSymbols() {
267 // TODO: ELF supports beyond SHN_LORESERVE,
268 // need to perf test how a vector vs map handles those cases
270 std::vector<std::vector<object::ELFFile<object::ELF64LE>::Elf_Shdr_Range *>>
273 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
275 for (auto SecRef : sections) {
277 if (SecRef.sh_type != ELF::SHT_SYMTAB &&
278 SecRef.sh_type != ELF::SHT_DYNSYM)
280 auto Symbols = Obj.symbols(&SecRef);
282 return Symbols.takeError();
284 auto StrTabSec = Obj.getSection(SecRef.sh_link);
286 return StrTabSec.takeError();
287 auto StringTable = Obj.getStringTable(*StrTabSec);
289 return StringTable.takeError();
290 auto Name = Obj.getSectionName(&SecRef);
292 return Name.takeError();
293 auto Section = G->findSectionByName(*Name);
295 return make_error<llvm::StringError>("Could not find a section",
296 llvm::inconvertibleErrorCode());
297 // we only have one for now
298 auto blocks = Section->blocks();
300 return make_error<llvm::StringError>("Section has no block",
301 llvm::inconvertibleErrorCode());
303 for (auto SymRef : *Symbols) {
304 auto Type = SymRef.getType();
305 if (Type == ELF::STT_NOTYPE || Type == ELF::STT_FILE)
307 // these should do it for now
308 // if(Type != ELF::STT_NOTYPE &&
309 // Type != ELF::STT_OBJECT &&
310 // Type != ELF::STT_FUNC &&
311 // Type != ELF::STT_SECTION &&
312 // Type != ELF::STT_COMMON) {
315 std::pair<Linkage, Scope> bindings;
316 auto Name = SymRef.getName(*StringTable);
317 // I am not sure on If this is going to hold as an invariant. Revisit.
319 return Name.takeError();
320 // TODO: weak and hidden
321 if (SymRef.isExternal())
322 bindings = {Linkage::Strong, Scope::Default};
324 bindings = {Linkage::Strong, Scope::Local};
326 if (SymRef.isDefined() &&
327 (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) {
329 auto DefinedSection = Obj.getSection(SymRef.st_shndx);
331 return DefinedSection.takeError();
332 auto sectName = Obj.getSectionName(*DefinedSection);
334 return Name.takeError();
336 auto JitSection = G->findSectionByName(*sectName);
338 return make_error<llvm::StringError>(
339 "Could not find a section", llvm::inconvertibleErrorCode());
340 auto bs = JitSection->blocks();
342 return make_error<llvm::StringError>(
343 "Section has no block", llvm::inconvertibleErrorCode());
345 auto B = *bs.begin();
346 LLVM_DEBUG({ dbgs() << " " << *Name << ": "; });
348 auto &S = G->addDefinedSymbol(
349 *B, SymRef.getValue(), *Name, SymRef.st_size, bindings.first,
350 bindings.second, SymRef.getType() == ELF::STT_FUNC, false);
351 JITSymbolTable[SymRef.st_shndx] = &S;
353 //TODO: The following has to be implmented.
354 // leaving commented out to save time for future patchs
356 G->addAbsoluteSymbol(*Name, SymRef.getValue(), SymRef.st_size,
357 Linkage::Strong, Scope::Default, false);
359 if(SymRef.isCommon()) {
360 G->addCommonSymbol(*Name, Scope::Default, getCommonSection(), 0, 0,
361 SymRef.getValue(), false);
365 //G->addExternalSymbol(*Name, SymRef.st_size, Linkage::Strong);
369 return Error::success();
373 ELFLinkGraphBuilder_x86_64(std::string filename,
374 const object::ELFFile<object::ELF64LE> &Obj)
375 : G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj),
376 getEndianness(Obj))),
379 Expected<std::unique_ptr<LinkGraph>> buildGraph() {
380 // Sanity check: we only operate on relocatable objects.
381 if (!isRelocatable())
382 return make_error<JITLinkError>("Object is not a relocatable ELF");
384 auto Secs = Obj.sections();
387 return Secs.takeError();
391 if (auto Err = createNormalizedSections())
392 return std::move(Err);
394 if (auto Err = createNormalizedSymbols())
395 return std::move(Err);
397 if (auto Err = graphifyRegularSymbols())
398 return std::move(Err);
400 if (auto Err = addRelocations())
401 return std::move(Err);
407 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
408 friend class JITLinker<ELFJITLinker_x86_64>;
411 ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
412 PassConfiguration PassConfig)
413 : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
416 StringRef getEdgeKindName(Edge::Kind R) const override { return StringRef(); }
418 Expected<std::unique_ptr<LinkGraph>>
419 buildGraph(MemoryBufferRef ObjBuffer) override {
420 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer);
422 return ELFObj.takeError();
424 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
425 std::string fileName(ELFObj->get()->getFileName());
426 return ELFLinkGraphBuilder_x86_64(std::move(fileName),
427 *ELFObjFile.getELFFile())
431 Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
432 using namespace ELF_x86_64_Edges;
433 char *FixupPtr = BlockWorkingMem + E.getOffset();
434 JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
435 switch (E.getKind()) {
437 case ELFX86RelocationKind::PCRel32:
438 int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
440 *(support::little32_t *)FixupPtr = Value;
443 return Error::success();
447 void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
448 PassConfiguration Config;
449 Triple TT("x86_64-linux");
450 // Construct a JITLinker and run the link function.
451 // Add a mark-live pass.
452 if (auto MarkLive = Ctx->getMarkLivePass(TT))
453 Config.PrePrunePasses.push_back(std::move(MarkLive));
455 Config.PrePrunePasses.push_back(markAllSymbolsLive);
457 if (auto Err = Ctx->modifyPassConfig(TT, Config))
458 return Ctx->notifyFailed(std::move(Err));
460 ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
462 } // end namespace jitlink
463 } // end namespace llvm