123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- //===- COFFReader.cpp -----------------------------------------------------===//
- //
- // 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 "COFFReader.h"
- #include "COFFObject.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/BinaryFormat/COFF.h"
- #include "llvm/Object/COFF.h"
- #include "llvm/Support/ErrorHandling.h"
- #include <cstddef>
- #include <cstdint>
- namespace llvm {
- namespace objcopy {
- namespace coff {
- using namespace object;
- using namespace COFF;
- Error COFFReader::readExecutableHeaders(Object &Obj) const {
- const dos_header *DH = COFFObj.getDOSHeader();
- Obj.Is64 = COFFObj.is64();
- if (!DH)
- return Error::success();
- Obj.IsPE = true;
- Obj.DosHeader = *DH;
- if (DH->AddressOfNewExeHeader > sizeof(*DH))
- Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
- DH->AddressOfNewExeHeader - sizeof(*DH));
- if (COFFObj.is64()) {
- Obj.PeHeader = *COFFObj.getPE32PlusHeader();
- } else {
- const pe32_header *PE32 = COFFObj.getPE32Header();
- copyPeHeader(Obj.PeHeader, *PE32);
- // The pe32plus_header (stored in Object) lacks the BaseOfData field.
- Obj.BaseOfData = PE32->BaseOfData;
- }
- for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
- const data_directory *Dir = COFFObj.getDataDirectory(I);
- if (!Dir)
- return errorCodeToError(object_error::parse_failed);
- Obj.DataDirectories.emplace_back(*Dir);
- }
- return Error::success();
- }
- Error COFFReader::readSections(Object &Obj) const {
- std::vector<Section> Sections;
- // Section indexing starts from 1.
- for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
- Expected<const coff_section *> SecOrErr = COFFObj.getSection(I);
- if (!SecOrErr)
- return SecOrErr.takeError();
- const coff_section *Sec = *SecOrErr;
- Sections.push_back(Section());
- Section &S = Sections.back();
- S.Header = *Sec;
- S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
- ArrayRef<uint8_t> Contents;
- if (Error E = COFFObj.getSectionContents(Sec, Contents))
- return E;
- S.setContentsRef(Contents);
- ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
- for (const coff_relocation &R : Relocs)
- S.Relocs.push_back(R);
- if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
- S.Name = *NameOrErr;
- else
- return NameOrErr.takeError();
- }
- Obj.addSections(Sections);
- return Error::success();
- }
- Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
- std::vector<Symbol> Symbols;
- Symbols.reserve(COFFObj.getNumberOfSymbols());
- ArrayRef<Section> Sections = Obj.getSections();
- for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); I < E;) {
- Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
- if (!SymOrErr)
- return SymOrErr.takeError();
- COFFSymbolRef SymRef = *SymOrErr;
- Symbols.push_back(Symbol());
- Symbol &Sym = Symbols.back();
- // Copy symbols from the original form into an intermediate coff_symbol32.
- if (IsBigObj)
- copySymbol(Sym.Sym,
- *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
- else
- copySymbol(Sym.Sym,
- *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
- auto NameOrErr = COFFObj.getSymbolName(SymRef);
- if (!NameOrErr)
- return NameOrErr.takeError();
- Sym.Name = *NameOrErr;
- ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
- size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
- assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
- // The auxillary symbols are structs of sizeof(coff_symbol16) each.
- // In the big object format (where symbols are coff_symbol32), each
- // auxillary symbol is padded with 2 bytes at the end. Copy each
- // auxillary symbol to the Sym.AuxData vector. For file symbols,
- // the whole range of aux symbols are interpreted as one null padded
- // string instead.
- if (SymRef.isFileRecord())
- Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
- AuxData.size())
- .rtrim('\0');
- else
- for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
- Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
- // Find the unique id of the section
- if (SymRef.getSectionNumber() <=
- 0) // Special symbol (undefined/absolute/debug)
- Sym.TargetSectionId = SymRef.getSectionNumber();
- else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
- Sections.size())
- Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
- else
- return createStringError(object_error::parse_failed,
- "section number out of range");
- // For section definitions, check if it is comdat associative, and if
- // it is, find the target section unique id.
- const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
- const coff_aux_weak_external *WE = SymRef.getWeakExternal();
- if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- int32_t Index = SD->getNumber(IsBigObj);
- if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
- return createStringError(object_error::parse_failed,
- "unexpected associative section index");
- Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
- } else if (WE) {
- // This is a raw symbol index for now, but store it in the Symbol
- // until we've added them to the Object, which assigns the final
- // unique ids.
- Sym.WeakTargetSymbolId = WE->TagIndex;
- }
- I += 1 + SymRef.getNumberOfAuxSymbols();
- }
- Obj.addSymbols(Symbols);
- return Error::success();
- }
- Error COFFReader::setSymbolTargets(Object &Obj) const {
- std::vector<const Symbol *> RawSymbolTable;
- for (const Symbol &Sym : Obj.getSymbols()) {
- RawSymbolTable.push_back(&Sym);
- for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
- RawSymbolTable.push_back(nullptr);
- }
- for (Symbol &Sym : Obj.getMutableSymbols()) {
- // Convert WeakTargetSymbolId from the original raw symbol index to
- // a proper unique id.
- if (Sym.WeakTargetSymbolId) {
- if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
- return createStringError(object_error::parse_failed,
- "weak external reference out of range");
- const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
- if (Target == nullptr)
- return createStringError(object_error::parse_failed,
- "invalid SymbolTableIndex");
- Sym.WeakTargetSymbolId = Target->UniqueId;
- }
- }
- for (Section &Sec : Obj.getMutableSections()) {
- for (Relocation &R : Sec.Relocs) {
- if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
- return createStringError(object_error::parse_failed,
- "SymbolTableIndex out of range");
- const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
- if (Sym == nullptr)
- return createStringError(object_error::parse_failed,
- "invalid SymbolTableIndex");
- R.Target = Sym->UniqueId;
- R.TargetName = Sym->Name;
- }
- }
- return Error::success();
- }
- Expected<std::unique_ptr<Object>> COFFReader::create() const {
- auto Obj = std::make_unique<Object>();
- bool IsBigObj = false;
- if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {
- Obj->CoffFileHeader = *CFH;
- } else {
- const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();
- if (!CBFH)
- return createStringError(object_error::parse_failed,
- "no COFF file header returned");
- // Only copying the few fields from the bigobj header that we need
- // and won't recreate in the end.
- Obj->CoffFileHeader.Machine = CBFH->Machine;
- Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
- IsBigObj = true;
- }
- if (Error E = readExecutableHeaders(*Obj))
- return std::move(E);
- if (Error E = readSections(*Obj))
- return std::move(E);
- if (Error E = readSymbols(*Obj, IsBigObj))
- return std::move(E);
- if (Error E = setSymbolTargets(*Obj))
- return std::move(E);
- return std::move(Obj);
- }
- } // end namespace coff
- } // end namespace objcopy
- } // end namespace llvm
|