brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 9b55f76 Raw
226 lines · cpp
1//===- COFFReader.cpp -----------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "COFFReader.h"10#include "COFFObject.h"11#include "llvm/ADT/ArrayRef.h"12#include "llvm/ADT/StringRef.h"13#include "llvm/BinaryFormat/COFF.h"14#include "llvm/Object/COFF.h"15#include "llvm/Support/ErrorHandling.h"16#include <cstddef>17#include <cstdint>18 19namespace llvm {20namespace objcopy {21namespace coff {22 23using namespace object;24using namespace COFF;25 26Error COFFReader::readExecutableHeaders(Object &Obj) const {27  const dos_header *DH = COFFObj.getDOSHeader();28  Obj.Is64 = COFFObj.is64();29  if (!DH)30    return Error::success();31 32  Obj.IsPE = true;33  Obj.DosHeader = *DH;34  if (DH->AddressOfNewExeHeader > sizeof(*DH))35    Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),36                                    DH->AddressOfNewExeHeader - sizeof(*DH));37 38  if (COFFObj.is64()) {39    Obj.PeHeader = *COFFObj.getPE32PlusHeader();40  } else {41    const pe32_header *PE32 = COFFObj.getPE32Header();42    copyPeHeader(Obj.PeHeader, *PE32);43    // The pe32plus_header (stored in Object) lacks the BaseOfData field.44    Obj.BaseOfData = PE32->BaseOfData;45  }46 47  for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {48    const data_directory *Dir = COFFObj.getDataDirectory(I);49    if (!Dir)50      return errorCodeToError(object_error::parse_failed);51    Obj.DataDirectories.emplace_back(*Dir);52  }53  return Error::success();54}55 56Error COFFReader::readSections(Object &Obj) const {57  std::vector<Section> Sections;58  // Section indexing starts from 1.59  for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {60    Expected<const coff_section *> SecOrErr = COFFObj.getSection(I);61    if (!SecOrErr)62      return SecOrErr.takeError();63    const coff_section *Sec = *SecOrErr;64    Sections.push_back(Section());65    Section &S = Sections.back();66    S.Header = *Sec;67    S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;68    ArrayRef<uint8_t> Contents;69    if (Error E = COFFObj.getSectionContents(Sec, Contents))70      return E;71    S.setContentsRef(Contents);72    ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);73    llvm::append_range(S.Relocs, Relocs);74    if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))75      S.Name = *NameOrErr;76    else77      return NameOrErr.takeError();78  }79  Obj.addSections(Sections);80  return Error::success();81}82 83Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {84  std::vector<Symbol> Symbols;85  Symbols.reserve(COFFObj.getNumberOfSymbols());86  ArrayRef<Section> Sections = Obj.getSections();87  for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); I < E;) {88    Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);89    if (!SymOrErr)90      return SymOrErr.takeError();91    COFFSymbolRef SymRef = *SymOrErr;92 93    Symbols.push_back(Symbol());94    Symbol &Sym = Symbols.back();95    // Copy symbols from the original form into an intermediate coff_symbol32.96    if (IsBigObj)97      copySymbol(Sym.Sym,98                 *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));99    else100      copySymbol(Sym.Sym,101                 *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));102    auto NameOrErr = COFFObj.getSymbolName(SymRef);103    if (!NameOrErr)104      return NameOrErr.takeError();105    Sym.Name = *NameOrErr;106 107    ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);108    size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);109    assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());110    // The auxillary symbols are structs of sizeof(coff_symbol16) each.111    // In the big object format (where symbols are coff_symbol32), each112    // auxillary symbol is padded with 2 bytes at the end. Copy each113    // auxillary symbol to the Sym.AuxData vector. For file symbols,114    // the whole range of aux symbols are interpreted as one null padded115    // string instead.116    if (SymRef.isFileRecord())117      Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),118                              AuxData.size())119                        .rtrim('\0');120    else121      for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)122        Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));123 124    // Find the unique id of the section125    if (SymRef.getSectionNumber() <=126        0) // Special symbol (undefined/absolute/debug)127      Sym.TargetSectionId = SymRef.getSectionNumber();128    else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <129             Sections.size())130      Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;131    else132      return createStringError(object_error::parse_failed,133                               "section number out of range");134    // For section definitions, check if it is comdat associative, and if135    // it is, find the target section unique id.136    const coff_aux_section_definition *SD = SymRef.getSectionDefinition();137    const coff_aux_weak_external *WE = SymRef.getWeakExternal();138    if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE && !Obj.IsPE) {139      int32_t Index = SD->getNumber(IsBigObj);140      if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())141        return createStringError(object_error::parse_failed,142                                 "unexpected associative section index");143      Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;144    } else if (WE) {145      // This is a raw symbol index for now, but store it in the Symbol146      // until we've added them to the Object, which assigns the final147      // unique ids.148      Sym.WeakTargetSymbolId = WE->TagIndex;149    }150    I += 1 + SymRef.getNumberOfAuxSymbols();151  }152  Obj.addSymbols(Symbols);153  return Error::success();154}155 156Error COFFReader::setSymbolTargets(Object &Obj) const {157  std::vector<const Symbol *> RawSymbolTable;158  for (const Symbol &Sym : Obj.getSymbols()) {159    RawSymbolTable.push_back(&Sym);160    for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)161      RawSymbolTable.push_back(nullptr);162  }163  for (Symbol &Sym : Obj.getMutableSymbols()) {164    // Convert WeakTargetSymbolId from the original raw symbol index to165    // a proper unique id.166    if (Sym.WeakTargetSymbolId) {167      if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())168        return createStringError(object_error::parse_failed,169                                 "weak external reference out of range");170      const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];171      if (Target == nullptr)172        return createStringError(object_error::parse_failed,173                                 "invalid SymbolTableIndex");174      Sym.WeakTargetSymbolId = Target->UniqueId;175    }176  }177  for (Section &Sec : Obj.getMutableSections()) {178    for (Relocation &R : Sec.Relocs) {179      if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())180        return createStringError(object_error::parse_failed,181                                 "SymbolTableIndex out of range");182      const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];183      if (Sym == nullptr)184        return createStringError(object_error::parse_failed,185                                 "invalid SymbolTableIndex");186      R.Target = Sym->UniqueId;187      R.TargetName = Sym->Name;188    }189  }190  return Error::success();191}192 193Expected<std::unique_ptr<Object>> COFFReader::create() const {194  auto Obj = std::make_unique<Object>();195 196  bool IsBigObj = false;197  if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {198    Obj->CoffFileHeader = *CFH;199  } else {200    const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();201    if (!CBFH)202      return createStringError(object_error::parse_failed,203                               "no COFF file header returned");204    // Only copying the few fields from the bigobj header that we need205    // and won't recreate in the end.206    Obj->CoffFileHeader.Machine = CBFH->Machine;207    Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;208    IsBigObj = true;209  }210 211  if (Error E = readExecutableHeaders(*Obj))212    return std::move(E);213  if (Error E = readSections(*Obj))214    return std::move(E);215  if (Error E = readSymbols(*Obj, IsBigObj))216    return std::move(E);217  if (Error E = setSymbolTargets(*Obj))218    return std::move(E);219 220  return std::move(Obj);221}222 223} // end namespace coff224} // end namespace objcopy225} // end namespace llvm226