1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
|
//===------- ELFLinkGraphBuilder.h - ELF LinkGraph builder ------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Generic ELF LinkGraph building code.
//
//===----------------------------------------------------------------------===//
#ifndef LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
#define LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#define DEBUG_TYPE "jitlink"
namespace llvm {
namespace jitlink {
/// Common link-graph building code shared between all ELFFiles.
class ELFLinkGraphBuilderBase {
public:
ELFLinkGraphBuilderBase(std::unique_ptr<LinkGraph> G) : G(std::move(G)) {}
virtual ~ELFLinkGraphBuilderBase();
protected:
static bool isDwarfSection(StringRef SectionName) {
return llvm::is_contained(DwarfSectionNames, SectionName);
}
Section &getCommonSection() {
if (!CommonSection)
CommonSection =
&G->createSection(CommonSectionName, MemProt::Read | MemProt::Write);
return *CommonSection;
}
std::unique_ptr<LinkGraph> G;
private:
static StringRef CommonSectionName;
static ArrayRef<const char *> DwarfSectionNames;
Section *CommonSection = nullptr;
};
/// Ling-graph building code that's specific to the given ELFT, but common
/// across all architectures.
template <typename ELFT>
class ELFLinkGraphBuilder : public ELFLinkGraphBuilderBase {
using ELFFile = object::ELFFile<ELFT>;
public:
ELFLinkGraphBuilder(const object::ELFFile<ELFT> &Obj, Triple TT,
StringRef FileName,
LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
/// Attempt to construct and return the LinkGraph.
Expected<std::unique_ptr<LinkGraph>> buildGraph();
/// Call to derived class to handle relocations. These require
/// architecture specific knowledge to map to JITLink edge kinds.
virtual Error addRelocations() = 0;
protected:
using ELFSectionIndex = unsigned;
using ELFSymbolIndex = unsigned;
bool isRelocatable() const {
return Obj.getHeader().e_type == llvm::ELF::ET_REL;
}
void setGraphBlock(ELFSectionIndex SecIndex, Block *B) {
assert(!GraphBlocks.count(SecIndex) && "Duplicate section at index");
GraphBlocks[SecIndex] = B;
}
Block *getGraphBlock(ELFSectionIndex SecIndex) {
auto I = GraphBlocks.find(SecIndex);
if (I == GraphBlocks.end())
return nullptr;
return I->second;
}
void setGraphSymbol(ELFSymbolIndex SymIndex, Symbol &Sym) {
assert(!GraphSymbols.count(SymIndex) && "Duplicate symbol at index");
GraphSymbols[SymIndex] = &Sym;
}
Symbol *getGraphSymbol(ELFSymbolIndex SymIndex) {
auto I = GraphSymbols.find(SymIndex);
if (I == GraphSymbols.end())
return nullptr;
return I->second;
}
Expected<std::pair<Linkage, Scope>>
getSymbolLinkageAndScope(const typename ELFT::Sym &Sym, StringRef Name);
Error prepare();
Error graphifySections();
Error graphifySymbols();
/// Traverse all matching relocation records in the given section. The handler
/// function Func should be callable with this signature:
/// Error(const typename ELFT::Rela &,
/// const typename ELFT::Shdr &, Section &)
///
template <typename RelocHandlerFunction>
Error forEachRelocation(const typename ELFT::Shdr &RelSect,
RelocHandlerFunction &&Func,
bool ProcessDebugSections = false);
/// Traverse all matching relocation records in the given section. Convenience
/// wrapper to allow passing a member function for the handler.
///
template <typename ClassT, typename RelocHandlerMethod>
Error forEachRelocation(const typename ELFT::Shdr &RelSect, ClassT *Instance,
RelocHandlerMethod &&Method,
bool ProcessDebugSections = false) {
return forEachRelocation(
RelSect,
[Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
return (Instance->*Method)(Rel, Target, GS);
},
ProcessDebugSections);
}
const ELFFile &Obj;
typename ELFFile::Elf_Shdr_Range Sections;
const typename ELFFile::Elf_Shdr *SymTabSec = nullptr;
StringRef SectionStringTab;
// Maps ELF section indexes to LinkGraph Blocks.
// Only SHF_ALLOC sections will have graph blocks.
DenseMap<ELFSectionIndex, Block *> GraphBlocks;
DenseMap<ELFSymbolIndex, Symbol *> GraphSymbols;
DenseMap<const typename ELFFile::Elf_Shdr *,
ArrayRef<typename ELFFile::Elf_Word>>
ShndxTables;
};
template <typename ELFT>
ELFLinkGraphBuilder<ELFT>::ELFLinkGraphBuilder(
const ELFFile &Obj, Triple TT, StringRef FileName,
LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
: ELFLinkGraphBuilderBase(std::make_unique<LinkGraph>(
FileName.str(), Triple(std::move(TT)), ELFT::Is64Bits ? 8 : 4,
support::endianness(ELFT::TargetEndianness),
std::move(GetEdgeKindName))),
Obj(Obj) {
LLVM_DEBUG(
{ dbgs() << "Created ELFLinkGraphBuilder for \"" << FileName << "\""; });
}
template <typename ELFT>
Expected<std::unique_ptr<LinkGraph>> ELFLinkGraphBuilder<ELFT>::buildGraph() {
if (!isRelocatable())
return make_error<JITLinkError>("Object is not a relocatable ELF file");
if (auto Err = prepare())
return std::move(Err);
if (auto Err = graphifySections())
return std::move(Err);
if (auto Err = graphifySymbols())
return std::move(Err);
if (auto Err = addRelocations())
return std::move(Err);
return std::move(G);
}
template <typename ELFT>
Expected<std::pair<Linkage, Scope>>
ELFLinkGraphBuilder<ELFT>::getSymbolLinkageAndScope(
const typename ELFT::Sym &Sym, StringRef Name) {
Linkage L = Linkage::Strong;
Scope S = Scope::Default;
switch (Sym.getBinding()) {
case ELF::STB_LOCAL:
S = Scope::Local;
break;
case ELF::STB_GLOBAL:
// Nothing to do here.
break;
case ELF::STB_WEAK:
case ELF::STB_GNU_UNIQUE:
L = Linkage::Weak;
break;
default:
return make_error<StringError>(
"Unrecognized symbol binding " +
Twine(static_cast<int>(Sym.getBinding())) + " for " + Name,
inconvertibleErrorCode());
}
switch (Sym.getVisibility()) {
case ELF::STV_DEFAULT:
case ELF::STV_PROTECTED:
// FIXME: Make STV_DEFAULT symbols pre-emptible? This probably needs
// Orc support.
// Otherwise nothing to do here.
break;
case ELF::STV_HIDDEN:
// Default scope -> Hidden scope. No effect on local scope.
if (S == Scope::Default)
S = Scope::Hidden;
break;
case ELF::STV_INTERNAL:
return make_error<StringError>(
"Unrecognized symbol visibility " +
Twine(static_cast<int>(Sym.getVisibility())) + " for " + Name,
inconvertibleErrorCode());
}
return std::make_pair(L, S);
}
template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::prepare() {
LLVM_DEBUG(dbgs() << " Preparing to build...\n");
// Get the sections array.
if (auto SectionsOrErr = Obj.sections())
Sections = *SectionsOrErr;
else
return SectionsOrErr.takeError();
// Get the section string table.
if (auto SectionStringTabOrErr = Obj.getSectionStringTable(Sections))
SectionStringTab = *SectionStringTabOrErr;
else
return SectionStringTabOrErr.takeError();
// Get the SHT_SYMTAB section.
for (auto &Sec : Sections) {
if (Sec.sh_type == ELF::SHT_SYMTAB) {
if (!SymTabSec)
SymTabSec = &Sec;
else
return make_error<JITLinkError>("Multiple SHT_SYMTAB sections in " +
G->getName());
}
// Extended table.
if (Sec.sh_type == ELF::SHT_SYMTAB_SHNDX) {
uint32_t SymtabNdx = Sec.sh_link;
if (SymtabNdx >= Sections.size())
return make_error<JITLinkError>("sh_link is out of bound");
auto ShndxTable = Obj.getSHNDXTable(Sec);
if (!ShndxTable)
return ShndxTable.takeError();
ShndxTables.insert({&Sections[SymtabNdx], *ShndxTable});
}
}
return Error::success();
}
template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySections() {
LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
// For each section...
for (ELFSectionIndex SecIndex = 0; SecIndex != Sections.size(); ++SecIndex) {
auto &Sec = Sections[SecIndex];
// Start by getting the section name.
auto Name = Obj.getSectionName(Sec, SectionStringTab);
if (!Name)
return Name.takeError();
// If the name indicates that it's a debug section then skip it: We don't
// support those yet.
if (isDwarfSection(*Name)) {
LLVM_DEBUG({
dbgs() << " " << SecIndex << ": \"" << *Name
<< "\" is a debug section: "
"No graph section will be created.\n";
});
continue;
}
// Skip non-SHF_ALLOC sections
if (!(Sec.sh_flags & ELF::SHF_ALLOC)) {
LLVM_DEBUG({
dbgs() << " " << SecIndex << ": \"" << *Name
<< "\" is not an SHF_ALLOC section: "
"No graph section will be created.\n";
});
continue;
}
LLVM_DEBUG({
dbgs() << " " << SecIndex << ": Creating section for \"" << *Name
<< "\"\n";
});
// Get the section's memory protection flags.
MemProt Prot;
if (Sec.sh_flags & ELF::SHF_EXECINSTR)
Prot = MemProt::Read | MemProt::Exec;
else
Prot = MemProt::Read | MemProt::Write;
// Look for existing sections first.
auto *GraphSec = G->findSectionByName(*Name);
if (!GraphSec)
GraphSec = &G->createSection(*Name, Prot);
assert(GraphSec->getMemProt() == Prot && "MemProt should match");
Block *B = nullptr;
if (Sec.sh_type != ELF::SHT_NOBITS) {
auto Data = Obj.template getSectionContentsAsArray<char>(Sec);
if (!Data)
return Data.takeError();
B = &G->createContentBlock(*GraphSec, *Data,
orc::ExecutorAddr(Sec.sh_addr),
Sec.sh_addralign, 0);
} else
B = &G->createZeroFillBlock(*GraphSec, Sec.sh_size,
orc::ExecutorAddr(Sec.sh_addr),
Sec.sh_addralign, 0);
setGraphBlock(SecIndex, B);
}
return Error::success();
}
template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySymbols() {
LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");
// No SYMTAB -- Bail out early.
if (!SymTabSec)
return Error::success();
// Get the section content as a Symbols array.
auto Symbols = Obj.symbols(SymTabSec);
if (!Symbols)
return Symbols.takeError();
// Get the string table for this section.
auto StringTab = Obj.getStringTableForSymtab(*SymTabSec, Sections);
if (!StringTab)
return StringTab.takeError();
LLVM_DEBUG({
StringRef SymTabName;
if (auto SymTabNameOrErr = Obj.getSectionName(*SymTabSec, SectionStringTab))
SymTabName = *SymTabNameOrErr;
else {
dbgs() << "Could not get ELF SHT_SYMTAB section name for logging: "
<< toString(SymTabNameOrErr.takeError()) << "\n";
SymTabName = "<SHT_SYMTAB section with invalid name>";
}
dbgs() << " Adding symbols from symtab section \"" << SymTabName
<< "\"\n";
});
for (ELFSymbolIndex SymIndex = 0; SymIndex != Symbols->size(); ++SymIndex) {
auto &Sym = (*Symbols)[SymIndex];
// Check symbol type.
switch (Sym.getType()) {
case ELF::STT_FILE:
LLVM_DEBUG({
if (auto Name = Sym.getName(*StringTab))
dbgs() << " " << SymIndex << ": Skipping STT_FILE symbol \""
<< *Name << "\"\n";
else {
dbgs() << "Could not get STT_FILE symbol name: "
<< toString(Name.takeError()) << "\n";
dbgs() << " " << SymIndex
<< ": Skipping STT_FILE symbol with invalid name\n";
}
});
continue;
break;
}
// Get the symbol name.
auto Name = Sym.getName(*StringTab);
if (!Name)
return Name.takeError();
// Handle common symbols specially.
if (Sym.isCommon()) {
Symbol &GSym = G->addCommonSymbol(*Name, Scope::Default,
getCommonSection(), orc::ExecutorAddr(),
Sym.st_size, Sym.getValue(), false);
setGraphSymbol(SymIndex, GSym);
continue;
}
// Map Visibility and Binding to Scope and Linkage:
Linkage L;
Scope S;
if (auto LSOrErr = getSymbolLinkageAndScope(Sym, *Name))
std::tie(L, S) = *LSOrErr;
else
return LSOrErr.takeError();
if (Sym.isDefined() &&
(Sym.getType() == ELF::STT_NOTYPE || Sym.getType() == ELF::STT_FUNC ||
Sym.getType() == ELF::STT_OBJECT ||
Sym.getType() == ELF::STT_SECTION || Sym.getType() == ELF::STT_TLS)) {
// Handle extended tables.
unsigned Shndx = Sym.st_shndx;
if (Shndx == ELF::SHN_XINDEX) {
auto ShndxTable = ShndxTables.find(SymTabSec);
if (ShndxTable == ShndxTables.end())
continue;
auto NdxOrErr = object::getExtendedSymbolTableIndex<ELFT>(
Sym, SymIndex, ShndxTable->second);
if (!NdxOrErr)
return NdxOrErr.takeError();
Shndx = *NdxOrErr;
}
if (auto *B = getGraphBlock(Shndx)) {
LLVM_DEBUG({
dbgs() << " " << SymIndex
<< ": Creating defined graph symbol for ELF symbol \"" << *Name
<< "\"\n";
});
// In RISCV, temporary symbols (Used to generate dwarf, eh_frame
// sections...) will appear in object code's symbol table, and LLVM does
// not use names on these temporary symbols (RISCV gnu toolchain uses
// names on these temporary symbols). If the symbol is unnamed, add an
// anonymous symbol.
auto &GSym =
Name->empty()
? G->addAnonymousSymbol(*B, Sym.getValue(), Sym.st_size,
false, false)
: G->addDefinedSymbol(*B, Sym.getValue(), *Name, Sym.st_size, L,
S, Sym.getType() == ELF::STT_FUNC, false);
setGraphSymbol(SymIndex, GSym);
}
} else if (Sym.isUndefined() && Sym.isExternal()) {
LLVM_DEBUG({
dbgs() << " " << SymIndex
<< ": Creating external graph symbol for ELF symbol \"" << *Name
<< "\"\n";
});
auto &GSym = G->addExternalSymbol(*Name, Sym.st_size, L);
setGraphSymbol(SymIndex, GSym);
} else {
LLVM_DEBUG({
dbgs() << " " << SymIndex
<< ": Not creating graph symbol for ELF symbol \"" << *Name
<< "\" with unrecognized type\n";
});
}
}
return Error::success();
}
template <typename ELFT>
template <typename RelocHandlerFunction>
Error ELFLinkGraphBuilder<ELFT>::forEachRelocation(
const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func,
bool ProcessDebugSections) {
// Only look into sections that store relocation entries.
if (RelSect.sh_type != ELF::SHT_RELA && RelSect.sh_type != ELF::SHT_REL)
return Error::success();
// sh_info contains the section header index of the target (FixupSection),
// which is the section to which all relocations in RelSect apply.
auto FixupSection = Obj.getSection(RelSect.sh_info);
if (!FixupSection)
return FixupSection.takeError();
// Target sections have names in valid ELF object files.
Expected<StringRef> Name = Obj.getSectionName(**FixupSection);
if (!Name)
return Name.takeError();
LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
// Consider skipping these relocations.
if (!ProcessDebugSections && isDwarfSection(*Name)) {
LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");
return Error::success();
}
// Lookup the link-graph node corresponding to the target section name.
auto *BlockToFix = getGraphBlock(RelSect.sh_info);
if (!BlockToFix)
return make_error<StringError>(
"Refencing a section that wasn't added to the graph: " + *Name,
inconvertibleErrorCode());
auto RelEntries = Obj.relas(RelSect);
if (!RelEntries)
return RelEntries.takeError();
// Let the callee process relocation entries one by one.
for (const typename ELFT::Rela &R : *RelEntries)
if (Error Err = Func(R, **FixupSection, *BlockToFix))
return Err;
LLVM_DEBUG(dbgs() << "\n");
return Error::success();
}
} // end namespace jitlink
} // end namespace llvm
#undef DEBUG_TYPE
#endif // LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
|