Path: blob/main/contrib/llvm-project/llvm/lib/ObjCopy/COFF/COFFReader.cpp
35294 views
//===- COFFReader.cpp -----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "COFFReader.h"9#include "COFFObject.h"10#include "llvm/ADT/ArrayRef.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/BinaryFormat/COFF.h"13#include "llvm/Object/COFF.h"14#include "llvm/Support/ErrorHandling.h"15#include <cstddef>16#include <cstdint>1718namespace llvm {19namespace objcopy {20namespace coff {2122using namespace object;23using namespace COFF;2425Error COFFReader::readExecutableHeaders(Object &Obj) const {26const dos_header *DH = COFFObj.getDOSHeader();27Obj.Is64 = COFFObj.is64();28if (!DH)29return Error::success();3031Obj.IsPE = true;32Obj.DosHeader = *DH;33if (DH->AddressOfNewExeHeader > sizeof(*DH))34Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),35DH->AddressOfNewExeHeader - sizeof(*DH));3637if (COFFObj.is64()) {38Obj.PeHeader = *COFFObj.getPE32PlusHeader();39} else {40const pe32_header *PE32 = COFFObj.getPE32Header();41copyPeHeader(Obj.PeHeader, *PE32);42// The pe32plus_header (stored in Object) lacks the BaseOfData field.43Obj.BaseOfData = PE32->BaseOfData;44}4546for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {47const data_directory *Dir = COFFObj.getDataDirectory(I);48if (!Dir)49return errorCodeToError(object_error::parse_failed);50Obj.DataDirectories.emplace_back(*Dir);51}52return Error::success();53}5455Error COFFReader::readSections(Object &Obj) const {56std::vector<Section> Sections;57// Section indexing starts from 1.58for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {59Expected<const coff_section *> SecOrErr = COFFObj.getSection(I);60if (!SecOrErr)61return SecOrErr.takeError();62const coff_section *Sec = *SecOrErr;63Sections.push_back(Section());64Section &S = Sections.back();65S.Header = *Sec;66S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;67ArrayRef<uint8_t> Contents;68if (Error E = COFFObj.getSectionContents(Sec, Contents))69return E;70S.setContentsRef(Contents);71ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);72for (const coff_relocation &R : Relocs)73S.Relocs.push_back(R);74if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))75S.Name = *NameOrErr;76else77return NameOrErr.takeError();78}79Obj.addSections(Sections);80return Error::success();81}8283Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {84std::vector<Symbol> Symbols;85Symbols.reserve(COFFObj.getNumberOfSymbols());86ArrayRef<Section> Sections = Obj.getSections();87for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); I < E;) {88Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);89if (!SymOrErr)90return SymOrErr.takeError();91COFFSymbolRef SymRef = *SymOrErr;9293Symbols.push_back(Symbol());94Symbol &Sym = Symbols.back();95// Copy symbols from the original form into an intermediate coff_symbol32.96if (IsBigObj)97copySymbol(Sym.Sym,98*reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));99else100copySymbol(Sym.Sym,101*reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));102auto NameOrErr = COFFObj.getSymbolName(SymRef);103if (!NameOrErr)104return NameOrErr.takeError();105Sym.Name = *NameOrErr;106107ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);108size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);109assert(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.116if (SymRef.isFileRecord())117Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),118AuxData.size())119.rtrim('\0');120else121for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)122Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));123124// Find the unique id of the section125if (SymRef.getSectionNumber() <=1260) // Special symbol (undefined/absolute/debug)127Sym.TargetSectionId = SymRef.getSectionNumber();128else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <129Sections.size())130Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;131else132return 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.136const coff_aux_section_definition *SD = SymRef.getSectionDefinition();137const coff_aux_weak_external *WE = SymRef.getWeakExternal();138if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {139int32_t Index = SD->getNumber(IsBigObj);140if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())141return createStringError(object_error::parse_failed,142"unexpected associative section index");143Sym.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.148Sym.WeakTargetSymbolId = WE->TagIndex;149}150I += 1 + SymRef.getNumberOfAuxSymbols();151}152Obj.addSymbols(Symbols);153return Error::success();154}155156Error COFFReader::setSymbolTargets(Object &Obj) const {157std::vector<const Symbol *> RawSymbolTable;158for (const Symbol &Sym : Obj.getSymbols()) {159RawSymbolTable.push_back(&Sym);160for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)161RawSymbolTable.push_back(nullptr);162}163for (Symbol &Sym : Obj.getMutableSymbols()) {164// Convert WeakTargetSymbolId from the original raw symbol index to165// a proper unique id.166if (Sym.WeakTargetSymbolId) {167if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())168return createStringError(object_error::parse_failed,169"weak external reference out of range");170const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];171if (Target == nullptr)172return createStringError(object_error::parse_failed,173"invalid SymbolTableIndex");174Sym.WeakTargetSymbolId = Target->UniqueId;175}176}177for (Section &Sec : Obj.getMutableSections()) {178for (Relocation &R : Sec.Relocs) {179if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())180return createStringError(object_error::parse_failed,181"SymbolTableIndex out of range");182const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];183if (Sym == nullptr)184return createStringError(object_error::parse_failed,185"invalid SymbolTableIndex");186R.Target = Sym->UniqueId;187R.TargetName = Sym->Name;188}189}190return Error::success();191}192193Expected<std::unique_ptr<Object>> COFFReader::create() const {194auto Obj = std::make_unique<Object>();195196bool IsBigObj = false;197if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {198Obj->CoffFileHeader = *CFH;199} else {200const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();201if (!CBFH)202return 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.206Obj->CoffFileHeader.Machine = CBFH->Machine;207Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;208IsBigObj = true;209}210211if (Error E = readExecutableHeaders(*Obj))212return std::move(E);213if (Error E = readSections(*Obj))214return std::move(E);215if (Error E = readSymbols(*Obj, IsBigObj))216return std::move(E);217if (Error E = setSymbolTargets(*Obj))218return std::move(E);219220return std::move(Obj);221}222223} // end namespace coff224} // end namespace objcopy225} // end namespace llvm226227228