125d7b4fbSAlexey Lapshin //===- COFFReader.cpp -----------------------------------------------------===//
225d7b4fbSAlexey Lapshin //
325d7b4fbSAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
425d7b4fbSAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information.
525d7b4fbSAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
625d7b4fbSAlexey Lapshin //
725d7b4fbSAlexey Lapshin //===----------------------------------------------------------------------===//
825d7b4fbSAlexey Lapshin
925d7b4fbSAlexey Lapshin #include "COFFReader.h"
1025d7b4fbSAlexey Lapshin #include "COFFObject.h"
1125d7b4fbSAlexey Lapshin #include "llvm/ADT/ArrayRef.h"
1225d7b4fbSAlexey Lapshin #include "llvm/ADT/StringRef.h"
1325d7b4fbSAlexey Lapshin #include "llvm/BinaryFormat/COFF.h"
1425d7b4fbSAlexey Lapshin #include "llvm/Object/COFF.h"
1525d7b4fbSAlexey Lapshin #include "llvm/Support/ErrorHandling.h"
1625d7b4fbSAlexey Lapshin #include <cstddef>
1725d7b4fbSAlexey Lapshin #include <cstdint>
1825d7b4fbSAlexey Lapshin
1925d7b4fbSAlexey Lapshin namespace llvm {
2025d7b4fbSAlexey Lapshin namespace objcopy {
2125d7b4fbSAlexey Lapshin namespace coff {
2225d7b4fbSAlexey Lapshin
2325d7b4fbSAlexey Lapshin using namespace object;
2425d7b4fbSAlexey Lapshin using namespace COFF;
2525d7b4fbSAlexey Lapshin
readExecutableHeaders(Object & Obj) const2625d7b4fbSAlexey Lapshin Error COFFReader::readExecutableHeaders(Object &Obj) const {
2725d7b4fbSAlexey Lapshin const dos_header *DH = COFFObj.getDOSHeader();
2825d7b4fbSAlexey Lapshin Obj.Is64 = COFFObj.is64();
2925d7b4fbSAlexey Lapshin if (!DH)
3025d7b4fbSAlexey Lapshin return Error::success();
3125d7b4fbSAlexey Lapshin
3225d7b4fbSAlexey Lapshin Obj.IsPE = true;
3325d7b4fbSAlexey Lapshin Obj.DosHeader = *DH;
3425d7b4fbSAlexey Lapshin if (DH->AddressOfNewExeHeader > sizeof(*DH))
3525d7b4fbSAlexey Lapshin Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
3625d7b4fbSAlexey Lapshin DH->AddressOfNewExeHeader - sizeof(*DH));
3725d7b4fbSAlexey Lapshin
3825d7b4fbSAlexey Lapshin if (COFFObj.is64()) {
3925d7b4fbSAlexey Lapshin Obj.PeHeader = *COFFObj.getPE32PlusHeader();
4025d7b4fbSAlexey Lapshin } else {
4125d7b4fbSAlexey Lapshin const pe32_header *PE32 = COFFObj.getPE32Header();
4225d7b4fbSAlexey Lapshin copyPeHeader(Obj.PeHeader, *PE32);
4325d7b4fbSAlexey Lapshin // The pe32plus_header (stored in Object) lacks the BaseOfData field.
4425d7b4fbSAlexey Lapshin Obj.BaseOfData = PE32->BaseOfData;
4525d7b4fbSAlexey Lapshin }
4625d7b4fbSAlexey Lapshin
4725d7b4fbSAlexey Lapshin for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
4825d7b4fbSAlexey Lapshin const data_directory *Dir = COFFObj.getDataDirectory(I);
4925d7b4fbSAlexey Lapshin if (!Dir)
5025d7b4fbSAlexey Lapshin return errorCodeToError(object_error::parse_failed);
5125d7b4fbSAlexey Lapshin Obj.DataDirectories.emplace_back(*Dir);
5225d7b4fbSAlexey Lapshin }
5325d7b4fbSAlexey Lapshin return Error::success();
5425d7b4fbSAlexey Lapshin }
5525d7b4fbSAlexey Lapshin
readSections(Object & Obj) const5625d7b4fbSAlexey Lapshin Error COFFReader::readSections(Object &Obj) const {
5725d7b4fbSAlexey Lapshin std::vector<Section> Sections;
5825d7b4fbSAlexey Lapshin // Section indexing starts from 1.
5925d7b4fbSAlexey Lapshin for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
6025d7b4fbSAlexey Lapshin Expected<const coff_section *> SecOrErr = COFFObj.getSection(I);
6125d7b4fbSAlexey Lapshin if (!SecOrErr)
6225d7b4fbSAlexey Lapshin return SecOrErr.takeError();
6325d7b4fbSAlexey Lapshin const coff_section *Sec = *SecOrErr;
6425d7b4fbSAlexey Lapshin Sections.push_back(Section());
6525d7b4fbSAlexey Lapshin Section &S = Sections.back();
6625d7b4fbSAlexey Lapshin S.Header = *Sec;
6725d7b4fbSAlexey Lapshin S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
6825d7b4fbSAlexey Lapshin ArrayRef<uint8_t> Contents;
6925d7b4fbSAlexey Lapshin if (Error E = COFFObj.getSectionContents(Sec, Contents))
7025d7b4fbSAlexey Lapshin return E;
7125d7b4fbSAlexey Lapshin S.setContentsRef(Contents);
7225d7b4fbSAlexey Lapshin ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
7325d7b4fbSAlexey Lapshin for (const coff_relocation &R : Relocs)
7425d7b4fbSAlexey Lapshin S.Relocs.push_back(R);
7525d7b4fbSAlexey Lapshin if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
7625d7b4fbSAlexey Lapshin S.Name = *NameOrErr;
7725d7b4fbSAlexey Lapshin else
7825d7b4fbSAlexey Lapshin return NameOrErr.takeError();
7925d7b4fbSAlexey Lapshin }
8025d7b4fbSAlexey Lapshin Obj.addSections(Sections);
8125d7b4fbSAlexey Lapshin return Error::success();
8225d7b4fbSAlexey Lapshin }
8325d7b4fbSAlexey Lapshin
readSymbols(Object & Obj,bool IsBigObj) const8425d7b4fbSAlexey Lapshin Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
8525d7b4fbSAlexey Lapshin std::vector<Symbol> Symbols;
86*556af193SDaan De Meyer Symbols.reserve(COFFObj.getNumberOfSymbols());
8725d7b4fbSAlexey Lapshin ArrayRef<Section> Sections = Obj.getSections();
88*556af193SDaan De Meyer for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); I < E;) {
8925d7b4fbSAlexey Lapshin Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
9025d7b4fbSAlexey Lapshin if (!SymOrErr)
9125d7b4fbSAlexey Lapshin return SymOrErr.takeError();
9225d7b4fbSAlexey Lapshin COFFSymbolRef SymRef = *SymOrErr;
9325d7b4fbSAlexey Lapshin
9425d7b4fbSAlexey Lapshin Symbols.push_back(Symbol());
9525d7b4fbSAlexey Lapshin Symbol &Sym = Symbols.back();
9625d7b4fbSAlexey Lapshin // Copy symbols from the original form into an intermediate coff_symbol32.
9725d7b4fbSAlexey Lapshin if (IsBigObj)
9825d7b4fbSAlexey Lapshin copySymbol(Sym.Sym,
9925d7b4fbSAlexey Lapshin *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
10025d7b4fbSAlexey Lapshin else
10125d7b4fbSAlexey Lapshin copySymbol(Sym.Sym,
10225d7b4fbSAlexey Lapshin *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
10325d7b4fbSAlexey Lapshin auto NameOrErr = COFFObj.getSymbolName(SymRef);
10425d7b4fbSAlexey Lapshin if (!NameOrErr)
10525d7b4fbSAlexey Lapshin return NameOrErr.takeError();
10625d7b4fbSAlexey Lapshin Sym.Name = *NameOrErr;
10725d7b4fbSAlexey Lapshin
10825d7b4fbSAlexey Lapshin ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
10925d7b4fbSAlexey Lapshin size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
11025d7b4fbSAlexey Lapshin assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
11125d7b4fbSAlexey Lapshin // The auxillary symbols are structs of sizeof(coff_symbol16) each.
11225d7b4fbSAlexey Lapshin // In the big object format (where symbols are coff_symbol32), each
11325d7b4fbSAlexey Lapshin // auxillary symbol is padded with 2 bytes at the end. Copy each
11425d7b4fbSAlexey Lapshin // auxillary symbol to the Sym.AuxData vector. For file symbols,
11525d7b4fbSAlexey Lapshin // the whole range of aux symbols are interpreted as one null padded
11625d7b4fbSAlexey Lapshin // string instead.
11725d7b4fbSAlexey Lapshin if (SymRef.isFileRecord())
11825d7b4fbSAlexey Lapshin Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
11925d7b4fbSAlexey Lapshin AuxData.size())
12025d7b4fbSAlexey Lapshin .rtrim('\0');
12125d7b4fbSAlexey Lapshin else
12225d7b4fbSAlexey Lapshin for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
12325d7b4fbSAlexey Lapshin Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
12425d7b4fbSAlexey Lapshin
12525d7b4fbSAlexey Lapshin // Find the unique id of the section
12625d7b4fbSAlexey Lapshin if (SymRef.getSectionNumber() <=
12725d7b4fbSAlexey Lapshin 0) // Special symbol (undefined/absolute/debug)
12825d7b4fbSAlexey Lapshin Sym.TargetSectionId = SymRef.getSectionNumber();
12925d7b4fbSAlexey Lapshin else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
13025d7b4fbSAlexey Lapshin Sections.size())
13125d7b4fbSAlexey Lapshin Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
13225d7b4fbSAlexey Lapshin else
13325d7b4fbSAlexey Lapshin return createStringError(object_error::parse_failed,
13425d7b4fbSAlexey Lapshin "section number out of range");
13525d7b4fbSAlexey Lapshin // For section definitions, check if it is comdat associative, and if
13625d7b4fbSAlexey Lapshin // it is, find the target section unique id.
13725d7b4fbSAlexey Lapshin const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
13825d7b4fbSAlexey Lapshin const coff_aux_weak_external *WE = SymRef.getWeakExternal();
13925d7b4fbSAlexey Lapshin if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
14025d7b4fbSAlexey Lapshin int32_t Index = SD->getNumber(IsBigObj);
14125d7b4fbSAlexey Lapshin if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
14225d7b4fbSAlexey Lapshin return createStringError(object_error::parse_failed,
14325d7b4fbSAlexey Lapshin "unexpected associative section index");
14425d7b4fbSAlexey Lapshin Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
14525d7b4fbSAlexey Lapshin } else if (WE) {
14625d7b4fbSAlexey Lapshin // This is a raw symbol index for now, but store it in the Symbol
14725d7b4fbSAlexey Lapshin // until we've added them to the Object, which assigns the final
14825d7b4fbSAlexey Lapshin // unique ids.
14925d7b4fbSAlexey Lapshin Sym.WeakTargetSymbolId = WE->TagIndex;
15025d7b4fbSAlexey Lapshin }
15125d7b4fbSAlexey Lapshin I += 1 + SymRef.getNumberOfAuxSymbols();
15225d7b4fbSAlexey Lapshin }
15325d7b4fbSAlexey Lapshin Obj.addSymbols(Symbols);
15425d7b4fbSAlexey Lapshin return Error::success();
15525d7b4fbSAlexey Lapshin }
15625d7b4fbSAlexey Lapshin
setSymbolTargets(Object & Obj) const15725d7b4fbSAlexey Lapshin Error COFFReader::setSymbolTargets(Object &Obj) const {
15825d7b4fbSAlexey Lapshin std::vector<const Symbol *> RawSymbolTable;
15925d7b4fbSAlexey Lapshin for (const Symbol &Sym : Obj.getSymbols()) {
16025d7b4fbSAlexey Lapshin RawSymbolTable.push_back(&Sym);
16125d7b4fbSAlexey Lapshin for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
16225d7b4fbSAlexey Lapshin RawSymbolTable.push_back(nullptr);
16325d7b4fbSAlexey Lapshin }
16425d7b4fbSAlexey Lapshin for (Symbol &Sym : Obj.getMutableSymbols()) {
16525d7b4fbSAlexey Lapshin // Convert WeakTargetSymbolId from the original raw symbol index to
16625d7b4fbSAlexey Lapshin // a proper unique id.
16725d7b4fbSAlexey Lapshin if (Sym.WeakTargetSymbolId) {
16825d7b4fbSAlexey Lapshin if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
16925d7b4fbSAlexey Lapshin return createStringError(object_error::parse_failed,
17025d7b4fbSAlexey Lapshin "weak external reference out of range");
17125d7b4fbSAlexey Lapshin const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
17225d7b4fbSAlexey Lapshin if (Target == nullptr)
17325d7b4fbSAlexey Lapshin return createStringError(object_error::parse_failed,
17425d7b4fbSAlexey Lapshin "invalid SymbolTableIndex");
17525d7b4fbSAlexey Lapshin Sym.WeakTargetSymbolId = Target->UniqueId;
17625d7b4fbSAlexey Lapshin }
17725d7b4fbSAlexey Lapshin }
17825d7b4fbSAlexey Lapshin for (Section &Sec : Obj.getMutableSections()) {
17925d7b4fbSAlexey Lapshin for (Relocation &R : Sec.Relocs) {
18025d7b4fbSAlexey Lapshin if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
18125d7b4fbSAlexey Lapshin return createStringError(object_error::parse_failed,
18225d7b4fbSAlexey Lapshin "SymbolTableIndex out of range");
18325d7b4fbSAlexey Lapshin const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
18425d7b4fbSAlexey Lapshin if (Sym == nullptr)
18525d7b4fbSAlexey Lapshin return createStringError(object_error::parse_failed,
18625d7b4fbSAlexey Lapshin "invalid SymbolTableIndex");
18725d7b4fbSAlexey Lapshin R.Target = Sym->UniqueId;
18825d7b4fbSAlexey Lapshin R.TargetName = Sym->Name;
18925d7b4fbSAlexey Lapshin }
19025d7b4fbSAlexey Lapshin }
19125d7b4fbSAlexey Lapshin return Error::success();
19225d7b4fbSAlexey Lapshin }
19325d7b4fbSAlexey Lapshin
create() const19425d7b4fbSAlexey Lapshin Expected<std::unique_ptr<Object>> COFFReader::create() const {
19525d7b4fbSAlexey Lapshin auto Obj = std::make_unique<Object>();
19625d7b4fbSAlexey Lapshin
19725d7b4fbSAlexey Lapshin bool IsBigObj = false;
19825d7b4fbSAlexey Lapshin if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {
19925d7b4fbSAlexey Lapshin Obj->CoffFileHeader = *CFH;
20025d7b4fbSAlexey Lapshin } else {
20125d7b4fbSAlexey Lapshin const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();
20225d7b4fbSAlexey Lapshin if (!CBFH)
20325d7b4fbSAlexey Lapshin return createStringError(object_error::parse_failed,
20425d7b4fbSAlexey Lapshin "no COFF file header returned");
20525d7b4fbSAlexey Lapshin // Only copying the few fields from the bigobj header that we need
20625d7b4fbSAlexey Lapshin // and won't recreate in the end.
20725d7b4fbSAlexey Lapshin Obj->CoffFileHeader.Machine = CBFH->Machine;
20825d7b4fbSAlexey Lapshin Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
20925d7b4fbSAlexey Lapshin IsBigObj = true;
21025d7b4fbSAlexey Lapshin }
21125d7b4fbSAlexey Lapshin
21225d7b4fbSAlexey Lapshin if (Error E = readExecutableHeaders(*Obj))
21325d7b4fbSAlexey Lapshin return std::move(E);
21425d7b4fbSAlexey Lapshin if (Error E = readSections(*Obj))
21525d7b4fbSAlexey Lapshin return std::move(E);
21625d7b4fbSAlexey Lapshin if (Error E = readSymbols(*Obj, IsBigObj))
21725d7b4fbSAlexey Lapshin return std::move(E);
21825d7b4fbSAlexey Lapshin if (Error E = setSymbolTargets(*Obj))
21925d7b4fbSAlexey Lapshin return std::move(E);
22025d7b4fbSAlexey Lapshin
22125d7b4fbSAlexey Lapshin return std::move(Obj);
22225d7b4fbSAlexey Lapshin }
22325d7b4fbSAlexey Lapshin
22425d7b4fbSAlexey Lapshin } // end namespace coff
22525d7b4fbSAlexey Lapshin } // end namespace objcopy
22625d7b4fbSAlexey Lapshin } // end namespace llvm
227