123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- //===- MachOObject.cpp - Mach-O object file model ---------------*- 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
- //
- //===----------------------------------------------------------------------===//
- #include "MachOObject.h"
- #include "llvm/ADT/SmallPtrSet.h"
- #include <unordered_set>
- using namespace llvm;
- using namespace llvm::objcopy::macho;
- Section::Section(StringRef SegName, StringRef SectName)
- : Segname(SegName), Sectname(SectName),
- CanonicalName((Twine(SegName) + Twine(',') + SectName).str()) {}
- Section::Section(StringRef SegName, StringRef SectName, StringRef Content)
- : Segname(SegName), Sectname(SectName),
- CanonicalName((Twine(SegName) + Twine(',') + SectName).str()),
- Content(Content) {}
- const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {
- assert(Index < Symbols.size() && "invalid symbol index");
- return Symbols[Index].get();
- }
- SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
- return const_cast<SymbolEntry *>(
- static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
- }
- void SymbolTable::removeSymbols(
- function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
- llvm::erase_if(Symbols, ToRemove);
- }
- void Object::updateLoadCommandIndexes() {
- static constexpr char TextSegmentName[] = "__TEXT";
- // Update indices of special load commands
- for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {
- LoadCommand &LC = LoadCommands[Index];
- switch (LC.MachOLoadCommand.load_command_data.cmd) {
- case MachO::LC_CODE_SIGNATURE:
- CodeSignatureCommandIndex = Index;
- break;
- case MachO::LC_SEGMENT:
- if (StringRef(LC.MachOLoadCommand.segment_command_data.segname) ==
- TextSegmentName)
- TextSegmentCommandIndex = Index;
- break;
- case MachO::LC_SEGMENT_64:
- if (StringRef(LC.MachOLoadCommand.segment_command_64_data.segname) ==
- TextSegmentName)
- TextSegmentCommandIndex = Index;
- break;
- case MachO::LC_SYMTAB:
- SymTabCommandIndex = Index;
- break;
- case MachO::LC_DYSYMTAB:
- DySymTabCommandIndex = Index;
- break;
- case MachO::LC_DYLD_INFO:
- case MachO::LC_DYLD_INFO_ONLY:
- DyLdInfoCommandIndex = Index;
- break;
- case MachO::LC_DATA_IN_CODE:
- DataInCodeCommandIndex = Index;
- break;
- case MachO::LC_LINKER_OPTIMIZATION_HINT:
- LinkerOptimizationHintCommandIndex = Index;
- break;
- case MachO::LC_FUNCTION_STARTS:
- FunctionStartsCommandIndex = Index;
- break;
- case MachO::LC_DYLIB_CODE_SIGN_DRS:
- DylibCodeSignDRsIndex = Index;
- break;
- case MachO::LC_DYLD_CHAINED_FIXUPS:
- ChainedFixupsCommandIndex = Index;
- break;
- case MachO::LC_DYLD_EXPORTS_TRIE:
- ExportsTrieCommandIndex = Index;
- break;
- }
- }
- }
- Error Object::removeLoadCommands(
- function_ref<bool(const LoadCommand &)> ToRemove) {
- auto It = std::stable_partition(
- LoadCommands.begin(), LoadCommands.end(),
- [&](const LoadCommand &LC) { return !ToRemove(LC); });
- LoadCommands.erase(It, LoadCommands.end());
- updateLoadCommandIndexes();
- return Error::success();
- }
- Error Object::removeSections(
- function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {
- DenseMap<uint32_t, const Section *> OldIndexToSection;
- uint32_t NextSectionIndex = 1;
- for (LoadCommand &LC : LoadCommands) {
- auto It = std::stable_partition(
- std::begin(LC.Sections), std::end(LC.Sections),
- [&](const std::unique_ptr<Section> &Sec) { return !ToRemove(Sec); });
- for (auto I = LC.Sections.begin(), End = It; I != End; ++I) {
- OldIndexToSection[(*I)->Index] = I->get();
- (*I)->Index = NextSectionIndex++;
- }
- LC.Sections.erase(It, LC.Sections.end());
- }
- auto IsDead = [&](const std::unique_ptr<SymbolEntry> &S) -> bool {
- std::optional<uint32_t> Section = S->section();
- return (Section && !OldIndexToSection.count(*Section));
- };
- SmallPtrSet<const SymbolEntry *, 2> DeadSymbols;
- for (const std::unique_ptr<SymbolEntry> &Sym : SymTable.Symbols)
- if (IsDead(Sym))
- DeadSymbols.insert(Sym.get());
- for (const LoadCommand &LC : LoadCommands)
- for (const std::unique_ptr<Section> &Sec : LC.Sections)
- for (const RelocationInfo &R : Sec->Relocations)
- if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol))
- return createStringError(std::errc::invalid_argument,
- "symbol '%s' defined in section with index "
- "'%u' cannot be removed because it is "
- "referenced by a relocation in section '%s'",
- (*R.Symbol)->Name.c_str(),
- *((*R.Symbol)->section()),
- Sec->CanonicalName.c_str());
- SymTable.removeSymbols(IsDead);
- for (std::unique_ptr<SymbolEntry> &S : SymTable.Symbols)
- if (S->section())
- S->n_sect = OldIndexToSection[S->n_sect]->Index;
- return Error::success();
- }
- uint64_t Object::nextAvailableSegmentAddress() const {
- uint64_t HeaderSize =
- is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
- uint64_t Addr = HeaderSize + Header.SizeOfCmds;
- for (const LoadCommand &LC : LoadCommands) {
- const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
- switch (MLC.load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- Addr = std::max(Addr,
- static_cast<uint64_t>(MLC.segment_command_data.vmaddr) +
- MLC.segment_command_data.vmsize);
- break;
- case MachO::LC_SEGMENT_64:
- Addr = std::max(Addr, MLC.segment_command_64_data.vmaddr +
- MLC.segment_command_64_data.vmsize);
- break;
- default:
- continue;
- }
- }
- return Addr;
- }
- template <typename SegmentType>
- static void
- constructSegment(SegmentType &Seg, llvm::MachO::LoadCommandType CmdType,
- StringRef SegName, uint64_t SegVMAddr, uint64_t SegVMSize) {
- assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");
- memset(&Seg, 0, sizeof(SegmentType));
- Seg.cmd = CmdType;
- strncpy(Seg.segname, SegName.data(), SegName.size());
- Seg.maxprot |=
- (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
- Seg.initprot |=
- (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
- Seg.vmaddr = SegVMAddr;
- Seg.vmsize = SegVMSize;
- }
- LoadCommand &Object::addSegment(StringRef SegName, uint64_t SegVMSize) {
- LoadCommand LC;
- const uint64_t SegVMAddr = nextAvailableSegmentAddress();
- if (is64Bit())
- constructSegment(LC.MachOLoadCommand.segment_command_64_data,
- MachO::LC_SEGMENT_64, SegName, SegVMAddr, SegVMSize);
- else
- constructSegment(LC.MachOLoadCommand.segment_command_data,
- MachO::LC_SEGMENT, SegName, SegVMAddr, SegVMSize);
- LoadCommands.push_back(std::move(LC));
- return LoadCommands.back();
- }
- /// Extracts a segment name from a string which is possibly non-null-terminated.
- static StringRef extractSegmentName(const char *SegName) {
- return StringRef(SegName,
- strnlen(SegName, sizeof(MachO::segment_command::segname)));
- }
- std::optional<StringRef> LoadCommand::getSegmentName() const {
- const MachO::macho_load_command &MLC = MachOLoadCommand;
- switch (MLC.load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- return extractSegmentName(MLC.segment_command_data.segname);
- case MachO::LC_SEGMENT_64:
- return extractSegmentName(MLC.segment_command_64_data.segname);
- default:
- return std::nullopt;
- }
- }
- std::optional<uint64_t> LoadCommand::getSegmentVMAddr() const {
- const MachO::macho_load_command &MLC = MachOLoadCommand;
- switch (MLC.load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- return MLC.segment_command_data.vmaddr;
- case MachO::LC_SEGMENT_64:
- return MLC.segment_command_64_data.vmaddr;
- default:
- return std::nullopt;
- }
- }
|