LLVM: lib/InterfaceStub/ELFObjHandler.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

20#include

21

23

24using namespace llvm;

27

28namespace llvm {

29namespace ifs {

30

31

37

39

42};

43

44

45

46

47

48

49

50

51template

53 memset(&ElfHeader, 0, sizeof(ElfHeader));

54

64

65

66 ElfHeader.e_type = ET_DYN;

67 ElfHeader.e_machine = Machine;

69 ElfHeader.e_ehsize = sizeof(typename ELFT::Ehdr);

70 ElfHeader.e_phentsize = sizeof(typename ELFT::Phdr);

71 ElfHeader.e_shentsize = sizeof(typename ELFT::Shdr);

72}

73

74namespace {

75template struct OutputSection {

76 using Elf_Shdr = typename ELFT::Shdr;

77 std::string Name;

85};

86

87template <class T, class ELFT>

88struct ContentSection : public OutputSection {

90 ContentSection() { this->NoBits = false; }

91};

92

93

94

96public:

98};

99

100template class ELFSymbolTableBuilder {

101public:

102 using Elf_Sym = typename ELFT::Sym;

103

104 ELFSymbolTableBuilder() { Symbols.push_back({}); }

105

108 Elf_Sym S{};

109 S.st_name = StNameOffset;

110 S.st_size = StSize;

111 S.st_info = (StBind << 4) | (StType & 0xf);

112 S.st_other = StOther;

113 S.st_shndx = StShndx;

114 Symbols.push_back(S);

115 }

116

117 size_t getSize() const { return Symbols.size() * sizeof(Elf_Sym); }

118

120 memcpy(Buf, Symbols.data(), sizeof(Elf_Sym) * Symbols.size());

121 }

122

123private:

125};

126

127template class ELFDynamicTableBuilder {

128public:

129 using Elf_Dyn = typename ELFT::Dyn;

130

135 Entries.push_back(Entry);

136 return Entries.size() - 1;

137 }

138

139 void modifyAddr(size_t Index, uint64_t Addr) {

140 Entries[Index].d_un.d_ptr = Addr;

141 }

142

147 Entries.push_back(Entry);

148 return Entries.size() - 1;

149 }

150

153 }

154

156

157 return (Entries.size() + 1) * sizeof(Elf_Dyn);

158 }

159

161 memcpy(Buf, Entries.data(), sizeof(Elf_Dyn) * Entries.size());

162

163 memset(Buf + sizeof(Elf_Dyn) * Entries.size(), 0, sizeof(Elf_Dyn));

164 }

165

166private:

168};

169

170template class ELFStubBuilder {

171public:

172 using Elf_Ehdr = typename ELFT::Ehdr;

173 using Elf_Shdr = typename ELFT::Shdr;

174 using Elf_Phdr = typename ELFT::Phdr;

175 using Elf_Sym = typename ELFT::Sym;

176 using Elf_Addr = typename ELFT::Addr;

177 using Elf_Dyn = typename ELFT::Dyn;

178

179 ELFStubBuilder(const ELFStubBuilder &) = delete;

180 ELFStubBuilder(ELFStubBuilder &&) = default;

181

182 explicit ELFStubBuilder(const IFSStub &Stub) {

183 DynSym.Name = ".dynsym";

184 DynSym.Align = sizeof(Elf_Addr);

185 DynStr.Name = ".dynstr";

186 DynStr.Align = 1;

187 DynTab.Name = ".dynamic";

188 DynTab.Align = sizeof(Elf_Addr);

189 ShStrTab.Name = ".shstrtab";

190 ShStrTab.Align = 1;

191

192

193 for (const IFSSymbol &Sym : Stub.Symbols)

194 DynStr.Content.add(Sym.Name);

195 for (const std::string &Lib : Stub.NeededLibs)

196 DynStr.Content.add(Lib);

197 if (Stub.SoName)

198 DynStr.Content.add(*Stub.SoName);

199

200 std::vector<OutputSection *> Sections = {&DynSym, &DynStr, &DynTab,

201 &ShStrTab};

202 const OutputSection *LastSection = Sections.back();

203

205 for (OutputSection *Sec : Sections) {

206 Sec->Index = Index++;

207 ShStrTab.Content.add(Sec->Name);

208 }

209 ShStrTab.Content.finalize();

210 ShStrTab.Size = ShStrTab.Content.getSize();

211 DynStr.Content.finalize();

212 DynStr.Size = DynStr.Content.getSize();

213

214

215 for (const IFSSymbol &Sym : Stub.Symbols) {

217

218

219

222 DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Size, Bind,

224 }

225 DynSym.Size = DynSym.Content.getSize();

226

227

228 size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0);

229 size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0);

230 DynTab.Content.addValue(DT_STRSZ, DynSym.Size);

231 for (const std::string &Lib : Stub.NeededLibs)

232 DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib));

233 if (Stub.SoName)

234 DynTab.Content.addValue(DT_SONAME,

235 DynStr.Content.getOffset(*Stub.SoName));

236 DynTab.Size = DynTab.Content.getSize();

237

238 uint64_t CurrentOffset = sizeof(Elf_Ehdr);

239 for (OutputSection *Sec : Sections) {

240 Sec->Offset = alignTo(CurrentOffset, Sec->Align);

241 Sec->Addr = Sec->Offset;

242 CurrentOffset = Sec->Offset + Sec->Size;

243 }

244

245 DynTab.Content.modifyAddr(DynSymIndex, DynSym.Addr);

246 DynTab.Content.modifyAddr(DynStrIndex, DynStr.Addr);

247

249 fillStrTabShdr(DynStr, SHF_ALLOC);

250 fillDynTabShdr(DynTab);

251 fillStrTabShdr(ShStrTab);

252

253

254 initELFHeader(ElfHeader, static_cast<uint16_t>(*Stub.Target.Arch));

255 ElfHeader.e_shstrndx = ShStrTab.Index;

256 ElfHeader.e_shnum = LastSection->Index + 1;

257 ElfHeader.e_shoff =

258 alignTo(LastSection->Offset + LastSection->Size, sizeof(Elf_Addr));

259 }

260

262 return ElfHeader.e_shoff + ElfHeader.e_shnum * sizeof(Elf_Shdr);

263 }

264

267 DynSym.Content.write(Data + DynSym.Shdr.sh_offset);

268 DynStr.Content.write(Data + DynStr.Shdr.sh_offset);

269 DynTab.Content.write(Data + DynTab.Shdr.sh_offset);

270 ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset);

271 writeShdr(Data, DynSym);

272 writeShdr(Data, DynStr);

273 writeShdr(Data, DynTab);

274 writeShdr(Data, ShStrTab);

275 }

276

277private:

278 Elf_Ehdr ElfHeader;

279 ContentSection<ELFStringTableBuilder, ELFT> DynStr;

280 ContentSection<ELFStringTableBuilder, ELFT> ShStrTab;

281 ContentSection<ELFSymbolTableBuilder, ELFT> DynSym;

282 ContentSection<ELFDynamicTableBuilder, ELFT> DynTab;

283

285 *reinterpret_cast<T *>(Data) = Value;

286 }

287

288 void fillStrTabShdr(ContentSection<ELFStringTableBuilder, ELFT> &StrTab,

289 uint32_t ShFlags = 0) const {

291 StrTab.Shdr.sh_flags = ShFlags;

292 StrTab.Shdr.sh_addr = StrTab.Addr;

293 StrTab.Shdr.sh_offset = StrTab.Offset;

294 StrTab.Shdr.sh_info = 0;

295 StrTab.Shdr.sh_size = StrTab.Size;

296 StrTab.Shdr.sh_name = ShStrTab.Content.getOffset(StrTab.Name);

297 StrTab.Shdr.sh_addralign = StrTab.Align;

298 StrTab.Shdr.sh_entsize = 0;

299 StrTab.Shdr.sh_link = 0;

300 }

301 void fillSymTabShdr(ContentSection<ELFSymbolTableBuilder, ELFT> &SymTab,

303 SymTab.Shdr.sh_type = ShType;

304 SymTab.Shdr.sh_flags = SHF_ALLOC;

305 SymTab.Shdr.sh_addr = SymTab.Addr;

306 SymTab.Shdr.sh_offset = SymTab.Offset;

307

308

309

310 SymTab.Shdr.sh_info = 1;

311 SymTab.Shdr.sh_size = SymTab.Size;

312 SymTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(SymTab.Name);

313 SymTab.Shdr.sh_addralign = SymTab.Align;

314 SymTab.Shdr.sh_entsize = sizeof(Elf_Sym);

315 SymTab.Shdr.sh_link = this->DynStr.Index;

316 }

317 void fillDynTabShdr(

318 ContentSection<ELFDynamicTableBuilder, ELFT> &DynTab) const {

320 DynTab.Shdr.sh_flags = SHF_ALLOC;

321 DynTab.Shdr.sh_addr = DynTab.Addr;

322 DynTab.Shdr.sh_offset = DynTab.Offset;

323 DynTab.Shdr.sh_info = 0;

324 DynTab.Shdr.sh_size = DynTab.Size;

325 DynTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(DynTab.Name);

326 DynTab.Shdr.sh_addralign = DynTab.Align;

327 DynTab.Shdr.sh_entsize = sizeof(Elf_Dyn);

328 DynTab.Shdr.sh_link = this->DynStr.Index;

329 }

330 uint64_t shdrOffset(const OutputSection &Sec) const {

331 return ElfHeader.e_shoff + Sec.Index * sizeof(Elf_Shdr);

332 }

333

334 void writeShdr(uint8_t *Data, const OutputSection &Sec) const {

335 write(Data + shdrOffset(Sec), Sec.Shdr);

336 }

337};

338

339

340

341

342

343

344

345

347 std::string Message;

349 Stream << Err;

350 Stream << " " << After;

353}

354

355template class DynSym {

356 using Elf_Shdr_Range = typename ELFT::ShdrRange;

357 using Elf_Shdr = typename ELFT::Shdr;

358

359public:

361 const DynamicEntries &DynEnt) {

363 if (!Shdrs)

364 return Shdrs.takeError();

365 return DynSym(ElfFile, DynEnt, *Shdrs);

366 }

367

369 if (DynSymHdr)

370 return ElfFile.base() + DynSymHdr->sh_offset;

371 return getDynamicData(DynEnt.DynSymAddr, "dynamic symbol table");

372 }

373

375 if (DynSymHdr)

376 return ElfFile.getStringTableForSymtab(*DynSymHdr, Shdrs);

378 DynEnt.StrTabAddr, "dynamic string table", DynEnt.StrSize);

379 if (!DataOrErr)

381 return StringRef(reinterpret_cast<const char *>(*DataOrErr),

382 DynEnt.StrSize);

383 }

384

385private:

386 DynSym(const ELFFile &ElfFile, const DynamicEntries &DynEnt,

387 Elf_Shdr_Range Shdrs)

388 : ElfFile(ElfFile), DynEnt(DynEnt), Shdrs(Shdrs),

389 DynSymHdr(findDynSymHdr()) {}

390

391 const Elf_Shdr *findDynSymHdr() {

392 for (const Elf_Shdr &Sec : Shdrs)

394

395

396 return &Sec;

397 }

398 return nullptr;

399 }

400

404 if (!SecPtr)

405 return appendToError(

407 ("when locating " + Name + " section contents").str());

409 if (!SecEndPtr)

410 return appendToError(

412 ("when locating " + Name + " section contents").str());

413 return *SecPtr;

414 }

415

417 const DynamicEntries &DynEnt;

418 Elf_Shdr_Range Shdrs;

419 const Elf_Shdr *DynSymHdr;

420};

421}

422

423

424

425

426

427

428

430 size_t StrEnd = Str.find('\0', Offset);

433 "String overran bounds of string table (no null terminator)");

434 }

435

436 size_t StrLen = StrEnd - Offset;

437 return Str.substr(Offset, StrLen);

438}

439

440

441

442

443

444

445

446template

448 typename ELFT::DynRange DynTable) {

449 if (DynTable.empty())

450 return createError("No .dynamic section found");

451

452

453 bool FoundDynStr = false;

454 bool FoundDynStrSz = false;

455 bool FoundDynSym = false;

456 for (auto &Entry : DynTable) {

457 switch (Entry.d_tag) {

458 case DT_SONAME:

460 break;

461 case DT_STRTAB:

463 FoundDynStr = true;

464 break;

465 case DT_STRSZ:

466 Dyn.StrSize = Entry.d_un.d_val;

467 FoundDynStrSz = true;

468 break;

469 case DT_NEEDED:

471 break;

472 case DT_SYMTAB:

474 FoundDynSym = true;

475 break;

476 case DT_HASH:

477 Dyn.ElfHash = Entry.d_un.d_ptr;

478 break;

479 case DT_GNU_HASH:

480 Dyn.GnuHash = Entry.d_un.d_ptr;

481 }

482 }

483

484 if (!FoundDynStr) {

486 "Couldn't locate dynamic string table (no DT_STRTAB entry)");

487 }

488 if (!FoundDynStrSz) {

490 "Couldn't determine dynamic string table size (no DT_STRSZ entry)");

491 }

492 if (!FoundDynSym) {

494 "Couldn't locate dynamic symbol table (no DT_SYMTAB entry)");

495 }

498 "DT_SONAME string offset (0x%016" PRIx64

499 ") outside of dynamic string table",

501 }

505 "DT_NEEDED string offset (0x%016" PRIx64

506 ") outside of dynamic string table",

508 }

509 }

510

512}

513

514

515

516

517

518

519template

521 const typename ELFT::Sym &RawSym) {

522 IFSSymbol TargetSym{std::string(SymName)};

523 uint8_t Binding = RawSym.getBinding();

525 TargetSym.Weak = true;

526 else

527 TargetSym.Weak = false;

528

529 TargetSym.Undefined = RawSym.isUndefined();

531

533 TargetSym.Size = 0;

534 } else {

535 TargetSym.Size = RawSym.st_size;

536 }

537 return TargetSym;

538}

539

540

541

542

543

544

545

546template

548 const typename ELFT::SymRange DynSym,

550

551 for (auto RawSym : DynSym.drop_front(1)) {

552

553 uint8_t Binding = RawSym.getBinding();

555 continue;

556

557 uint8_t Visibility = RawSym.getVisibility();

559 continue;

560

561

563 if (!SymName)

565 IFSSymbol Sym = createELFSym(*SymName, RawSym);

566 TargetStub.Symbols.push_back(std::move(Sym));

567

568 }

570}

571

572

573

574template

577 using Elf_Dyn_Range = typename ELFT::DynRange;

578 using Elf_Sym_Range = typename ELFT::SymRange;

579 using Elf_Sym = typename ELFT::Sym;

580 std::unique_ptr DestStub = std::make_unique();

582

584 if (!DynTable) {

586 }

587

588

590 if (Error Err = populateDynamic(DynEnt, *DynTable))

591 return std::move(Err);

593 if (!EDynSym)

595

597 if (!EDynStr)

599

601

602

603 DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine);

604 DestStub->Target.BitWidth =

606 DestStub->Target.Endianness =

608 DestStub->Target.ObjectFormat = "ELF";

609

610

614 if (!NameOrErr) {

615 return appendToError(NameOrErr.takeError(), "when reading DT_SONAME");

616 }

617 DestStub->SoName = std::string(*NameOrErr);

618 }

619

620

624 if (!LibNameOrErr) {

625 return appendToError(LibNameOrErr.takeError(), "when reading DT_NEEDED");

626 }

627 DestStub->NeededLibs.push_back(std::string(*LibNameOrErr));

628 }

629

630

632 if (!SymCount)

634 if (*SymCount > 0) {

635

637 if (!DynSymPtr)

638 return appendToError(DynSymPtr.takeError(),

639 "when locating .dynsym section contents");

641 reinterpret_cast<const Elf_Sym *>(*DynSymPtr), *SymCount);

642 Error SymReadError = populateSymbols(*DestStub, DynSyms, DynStr);

643 if (SymReadError)

644 return appendToError(std::move(SymReadError),

645 "when reading dynamic symbols");

646 }

647

648 return std::move(DestStub);

649}

650

651

652

653

654

655

656template

659 ELFStubBuilder Builder{Stub};

660

661 std::vector<uint8_t> Buf(Builder.getSize());

662 Builder.write(Buf.data());

663

665 if (ErrorOr<std::unique_ptr> BufOrError =

667

668

669 if ((*BufOrError)->getBufferSize() == Builder.getSize() &&

670 memcmp((*BufOrError)->getBufferStart(), Buf.data(),

671 Builder.getSize()))

673 }

674 }

675

678 if (!BufOrError)

681 " when trying to open `" + FilePath +

682 "` for writing");

683

684

685 std::unique_ptr FileBuf = std::move(*BufOrError);

686 memcpy(FileBuf->getBufferStart(), Buf.data(), Buf.size());

687

688 return FileBuf->commit();

689}

690

693 if (!BinOrErr) {

695 }

696

706 }

708}

709

710

711

719 return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged);

720 } else {

721 return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged);

722 }

723 } else {

725 return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged);

726 } else {

727 return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged);

728 }

729 }

731}

732

733}

734}

COFF::MachineTypes Machine

This supports reading and writing of elf dynamic shared objects.

This file defines an internal representation of an InterFace Stub.

static cl::opt< bool > WriteIfChanged("write-if-changed", cl::desc("Only write output if it changed"))

Merge contiguous icmps into a memcmp

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

static unsigned getSize(unsigned Kind)

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

Represents either an error or a value T.

Lightweight error class with error context and mandatory checking.

static ErrorSuccess success()

Create a success value.

Tagged union holding either a T or a Error.

Error takeError()

Take ownership of the stored error.

reference get()

Returns a reference to the stored T value.

static Expected< std::unique_ptr< FileOutputBuffer > > create(StringRef FilePath, size_t Size, unsigned Flags=0)

Factory method to create an OutputBuffer object which manages a read/write buffer of the specified si...

static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)

Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

static constexpr size_t npos

Utility for building string tables with deduplicated suffixes.

LLVM Value Representation.

const ELFFile< ELFT > & getELFFile() const

A raw_ostream that writes to an std::string.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

static const char ElfMagic[]

static Error writeELFBinaryToFile(StringRef FilePath, const IFSStub &Stub, bool WriteIfChanged)

This function opens a file for writing and then writes a binary ELF stub to the file.

Expected< std::unique_ptr< IFSStub > > readELFFile(MemoryBufferRef Buf)

Attempt to read a binary ELF file from a MemoryBuffer.

Error writeBinaryStub(StringRef FilePath, const IFSStub &Stub, bool WriteIfChanged=false)

Attempt to write a binary ELF stub.

uint8_t convertIFSSymbolTypeToELF(IFSSymbolType SymbolType)

This function convert symbol type from IFS enum to ELF format Currently, STT_NOTYPE,...

static Expected< std::unique_ptr< IFSStub > > buildStub(const ELFObjectFile< ELFT > &ElfObj)

Returns a new IFSStub with all members populated from an ELFObjectFile.

static Error populateSymbols(IFSStub &TargetStub, const typename ELFT::SymRange DynSym, StringRef DynStr)

This function populates an IFSStub with symbols using information read from an ELF binary.

static void initELFHeader(typename ELFT::Ehdr &ElfHeader, uint16_t Machine)

This initializes an ELF file header with information specific to a binary dynamic shared object.

IFSBitWidthType convertELFBitWidthToIFS(uint8_t BitWidth)

This function extracts ELF bit width from e_ident[EI_CLASS] of an ELF file Currently,...

IFSEndiannessType convertELFEndiannessToIFS(uint8_t Endianness)

This function extracts ELF endianness from e_ident[EI_DATA] of an ELF file Currently,...

static Error populateDynamic(DynamicEntries &Dyn, typename ELFT::DynRange DynTable)

This function populates a DynamicEntries struct using an ELFT::DynRange.

static IFSSymbol createELFSym(StringRef SymName, const typename ELFT::Sym &RawSym)

This function creates an IFSSymbol and populates all members using information from a binary ELFT::Sy...

IFSSymbolType convertELFSymbolTypeToIFS(uint8_t SymbolType)

This function extracts symbol type from a symbol's st_info member and maps it to an IFSSymbolType enu...

static Expected< StringRef > terminatedSubstr(StringRef Str, size_t Offset)

This function behaves similarly to StringRef::substr(), but attempts to terminate the returned String...

Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)

Create a Binary from Source, autodetecting the file type.

This is an optimization pass for GlobalISel generic memory operations.

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)

Create formatted StringError object.

Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)

static Error createError(const Twine &Err)

uint64_t alignTo(uint64_t Size, Align A)

Returns a multiple of A needed to store Size bytes.

const char * toString(DWARFSectionKind Kind)

void consumeError(Error Err)

Consume a Error without doing anything.

This struct is a compact representation of a valid (non-zero power of two) alignment.

std::optional< uint64_t > ElfHash

std::vector< uint64_t > NeededLibNames

std::optional< uint64_t > GnuHash

std::optional< uint64_t > SONameOffset

std::vector< IFSSymbol > Symbols

std::optional< IFSEndiannessType > Endianness

std::optional< IFSBitWidthType > BitWidth

std::optional< IFSArch > Arch