diff options
Diffstat (limited to 'llvm/tools/llvm-objcopy/MachO/MachOReader.cpp')
-rw-r--r-- | llvm/tools/llvm-objcopy/MachO/MachOReader.cpp | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp new file mode 100644 index 000000000000..b48a0d8952d0 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -0,0 +1,282 @@ +//===- MachOReader.cpp ------------------------------------------*- 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 "MachOReader.h" +#include "../llvm-objcopy.h" +#include "Object.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Object/MachO.h" +#include <memory> + +namespace llvm { +namespace objcopy { +namespace macho { + +void MachOReader::readHeader(Object &O) const { + O.Header.Magic = MachOObj.getHeader().magic; + O.Header.CPUType = MachOObj.getHeader().cputype; + O.Header.CPUSubType = MachOObj.getHeader().cpusubtype; + O.Header.FileType = MachOObj.getHeader().filetype; + O.Header.NCmds = MachOObj.getHeader().ncmds; + O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds; + O.Header.Flags = MachOObj.getHeader().flags; +} + +template <typename SectionType> +Section constructSectionCommon(SectionType Sec) { + Section S; + S.Sectname = + StringRef(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))) + .str(); + S.Segname = + StringRef(Sec.segname, strnlen(Sec.segname, sizeof(Sec.sectname))).str(); + S.Addr = Sec.addr; + S.Size = Sec.size; + S.Offset = Sec.offset; + S.Align = Sec.align; + S.RelOff = Sec.reloff; + S.NReloc = Sec.nreloc; + S.Flags = Sec.flags; + S.Reserved1 = Sec.reserved1; + S.Reserved2 = Sec.reserved2; + S.Reserved3 = 0; + return S; +} + +template <typename SectionType> Section constructSection(SectionType Sec); + +template <> Section constructSection(MachO::section Sec) { + return constructSectionCommon(Sec); +} + +template <> Section constructSection(MachO::section_64 Sec) { + Section S = constructSectionCommon(Sec); + S.Reserved3 = Sec.reserved3; + return S; +} + +// TODO: get rid of reportError and make MachOReader return Expected<> instead. +template <typename SectionType, typename SegmentType> +std::vector<Section> +extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd, + const object::MachOObjectFile &MachOObj, + size_t &NextSectionIndex) { + auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize; + const SectionType *Curr = + reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType)); + std::vector<Section> Sections; + for (; reinterpret_cast<const void *>(Curr) < End; Curr++) { + if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) { + SectionType Sec; + memcpy((void *)&Sec, Curr, sizeof(SectionType)); + MachO::swapStruct(Sec); + Sections.push_back(constructSection(Sec)); + } else { + Sections.push_back(constructSection(*Curr)); + } + + Section &S = Sections.back(); + + Expected<object::SectionRef> SecRef = + MachOObj.getSection(NextSectionIndex++); + if (!SecRef) + reportError(MachOObj.getFileName(), SecRef.takeError()); + + if (Expected<ArrayRef<uint8_t>> E = + MachOObj.getSectionContents(SecRef->getRawDataRefImpl())) + S.Content = + StringRef(reinterpret_cast<const char *>(E->data()), E->size()); + else + reportError(MachOObj.getFileName(), E.takeError()); + + S.Relocations.reserve(S.NReloc); + for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()), + RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl()); + RI != RE; ++RI) { + RelocationInfo R; + R.Symbol = nullptr; // We'll fill this field later. + R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl()); + R.Scattered = MachOObj.isRelocationScattered(R.Info); + S.Relocations.push_back(R); + } + + assert(S.NReloc == S.Relocations.size() && + "Incorrect number of relocations"); + } + return Sections; +} + +void MachOReader::readLoadCommands(Object &O) const { + // For MachO sections indices start from 1. + size_t NextSectionIndex = 1; + for (auto LoadCmd : MachOObj.load_commands()) { + LoadCommand LC; + switch (LoadCmd.C.cmd) { + case MachO::LC_SEGMENT: + LC.Sections = extractSections<MachO::section, MachO::segment_command>( + LoadCmd, MachOObj, NextSectionIndex); + break; + case MachO::LC_SEGMENT_64: + LC.Sections = + extractSections<MachO::section_64, MachO::segment_command_64>( + LoadCmd, MachOObj, NextSectionIndex); + break; + case MachO::LC_SYMTAB: + O.SymTabCommandIndex = O.LoadCommands.size(); + break; + case MachO::LC_DYSYMTAB: + O.DySymTabCommandIndex = O.LoadCommands.size(); + break; + case MachO::LC_DYLD_INFO: + case MachO::LC_DYLD_INFO_ONLY: + O.DyLdInfoCommandIndex = O.LoadCommands.size(); + break; + case MachO::LC_DATA_IN_CODE: + O.DataInCodeCommandIndex = O.LoadCommands.size(); + break; + case MachO::LC_FUNCTION_STARTS: + O.FunctionStartsCommandIndex = O.LoadCommands.size(); + break; + } +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ + case MachO::LCName: \ + memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \ + sizeof(MachO::LCStruct)); \ + if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \ + MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \ + LC.Payload = ArrayRef<uint8_t>( \ + reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \ + sizeof(MachO::LCStruct), \ + LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \ + break; + + switch (LoadCmd.C.cmd) { + default: + memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr, + sizeof(MachO::load_command)); + if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) + MachO::swapStruct(LC.MachOLoadCommand.load_command_data); + LC.Payload = ArrayRef<uint8_t>( + reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + + sizeof(MachO::load_command), + LoadCmd.C.cmdsize - sizeof(MachO::load_command)); + break; +#include "llvm/BinaryFormat/MachO.def" + } + O.LoadCommands.push_back(std::move(LC)); + } +} + +template <typename nlist_t> +SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) { + assert(nlist.n_strx < StrTable.size() && + "n_strx exceeds the size of the string table"); + SymbolEntry SE; + SE.Name = StringRef(StrTable.data() + nlist.n_strx).str(); + SE.n_type = nlist.n_type; + SE.n_sect = nlist.n_sect; + SE.n_desc = nlist.n_desc; + SE.n_value = nlist.n_value; + return SE; +} + +void MachOReader::readSymbolTable(Object &O) const { + StringRef StrTable = MachOObj.getStringTableData(); + for (auto Symbol : MachOObj.symbols()) { + SymbolEntry SE = + (MachOObj.is64Bit() + ? constructSymbolEntry( + StrTable, + MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl())) + : constructSymbolEntry( + StrTable, + MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl()))); + + O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE)); + } +} + +void MachOReader::setSymbolInRelocationInfo(Object &O) const { + for (auto &LC : O.LoadCommands) + for (auto &Sec : LC.Sections) + for (auto &Reloc : Sec.Relocations) + if (!Reloc.Scattered) { + auto *Info = reinterpret_cast<MachO::relocation_info *>(&Reloc.Info); + Reloc.Symbol = O.SymTable.getSymbolByIndex(Info->r_symbolnum); + } +} + +void MachOReader::readRebaseInfo(Object &O) const { + O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes(); +} + +void MachOReader::readBindInfo(Object &O) const { + O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes(); +} + +void MachOReader::readWeakBindInfo(Object &O) const { + O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes(); +} + +void MachOReader::readLazyBindInfo(Object &O) const { + O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes(); +} + +void MachOReader::readExportInfo(Object &O) const { + O.Exports.Trie = MachOObj.getDyldInfoExportsTrie(); +} + +void MachOReader::readDataInCodeData(Object &O) const { + if (!O.DataInCodeCommandIndex) + return; + const MachO::linkedit_data_command &LDC = + O.LoadCommands[*O.DataInCodeCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + + O.DataInCode.Data = arrayRefFromStringRef( + MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +} + +void MachOReader::readFunctionStartsData(Object &O) const { + if (!O.FunctionStartsCommandIndex) + return; + const MachO::linkedit_data_command &LDC = + O.LoadCommands[*O.FunctionStartsCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + + O.FunctionStarts.Data = arrayRefFromStringRef( + MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +} + +void MachOReader::readIndirectSymbolTable(Object &O) const { + MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand(); + for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) + O.IndirectSymTable.Symbols.push_back( + MachOObj.getIndirectSymbolTableEntry(DySymTab, i)); +} + +std::unique_ptr<Object> MachOReader::create() const { + auto Obj = std::make_unique<Object>(); + readHeader(*Obj); + readLoadCommands(*Obj); + readSymbolTable(*Obj); + setSymbolInRelocationInfo(*Obj); + readRebaseInfo(*Obj); + readBindInfo(*Obj); + readWeakBindInfo(*Obj); + readLazyBindInfo(*Obj); + readExportInfo(*Obj); + readDataInCodeData(*Obj); + readFunctionStartsData(*Obj); + readIndirectSymbolTable(*Obj); + return Obj; +} + +} // end namespace macho +} // end namespace objcopy +} // end namespace llvm |