1 //===- COFFObject.h ---------------------------------------------*- C++ -*-===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIB_OBJCOPY_COFF_COFFOBJECT_H
10 #define LLVM_LIB_OBJCOPY_COFF_COFFOBJECT_H
11 
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/ADT/iterator_range.h"
17 #include "llvm/BinaryFormat/COFF.h"
18 #include "llvm/Object/COFF.h"
19 #include <cstddef>
20 #include <cstdint>
21 #include <vector>
22 
23 namespace llvm {
24 namespace objcopy {
25 namespace coff {
26 
27 struct Relocation {
28   Relocation() = default;
29   Relocation(const object::coff_relocation &R) : Reloc(R) {}
30 
31   object::coff_relocation Reloc;
32   size_t Target = 0;
33   StringRef TargetName; // Used for diagnostics only
34 };
35 
36 struct Section {
37   object::coff_section Header;
38   std::vector<Relocation> Relocs;
39   StringRef Name;
40   ssize_t UniqueId;
41   size_t Index;
42 
43   ArrayRef<uint8_t> getContents() const {
44     if (!OwnedContents.empty())
45       return OwnedContents;
46     return ContentsRef;
47   }
48 
49   void setContentsRef(ArrayRef<uint8_t> Data) {
50     OwnedContents.clear();
51     ContentsRef = Data;
52   }
53 
54   void setOwnedContents(std::vector<uint8_t> &&Data) {
55     ContentsRef = ArrayRef<uint8_t>();
56     OwnedContents = std::move(Data);
57     Header.SizeOfRawData = OwnedContents.size();
58   }
59 
60   void clearContents() {
61     ContentsRef = ArrayRef<uint8_t>();
62     OwnedContents.clear();
63   }
64 
65 private:
66   ArrayRef<uint8_t> ContentsRef;
67   std::vector<uint8_t> OwnedContents;
68 };
69 
70 struct AuxSymbol {
71   AuxSymbol(ArrayRef<uint8_t> In) {
72     assert(In.size() == sizeof(Opaque));
73     std::copy(In.begin(), In.end(), Opaque);
74   }
75 
76   ArrayRef<uint8_t> getRef() const {
77     return ArrayRef<uint8_t>(Opaque, sizeof(Opaque));
78   }
79 
80   uint8_t Opaque[sizeof(object::coff_symbol16)];
81 };
82 
83 struct Symbol {
84   object::coff_symbol32 Sym;
85   StringRef Name;
86   std::vector<AuxSymbol> AuxData;
87   StringRef AuxFile;
88   ssize_t TargetSectionId;
89   ssize_t AssociativeComdatTargetSectionId = 0;
90   Optional<size_t> WeakTargetSymbolId;
91   size_t UniqueId;
92   size_t RawIndex;
93   bool Referenced;
94 };
95 
96 struct Object {
97   bool IsPE = false;
98 
99   object::dos_header DosHeader;
100   ArrayRef<uint8_t> DosStub;
101 
102   object::coff_file_header CoffFileHeader;
103 
104   bool Is64 = false;
105   object::pe32plus_header PeHeader;
106   uint32_t BaseOfData = 0; // pe32plus_header lacks this field.
107 
108   std::vector<object::data_directory> DataDirectories;
109 
110   ArrayRef<Symbol> getSymbols() const { return Symbols; }
111   // This allows mutating individual Symbols, but not mutating the list
112   // of symbols itself.
113   iterator_range<std::vector<Symbol>::iterator> getMutableSymbols() {
114     return make_range(Symbols.begin(), Symbols.end());
115   }
116 
117   const Symbol *findSymbol(size_t UniqueId) const;
118 
119   void addSymbols(ArrayRef<Symbol> NewSymbols);
120   Error removeSymbols(function_ref<Expected<bool>(const Symbol &)> ToRemove);
121 
122   // Set the Referenced field on all Symbols, based on relocations in
123   // all sections.
124   Error markSymbols();
125 
126   ArrayRef<Section> getSections() const { return Sections; }
127   // This allows mutating individual Sections, but not mutating the list
128   // of sections itself.
129   iterator_range<std::vector<Section>::iterator> getMutableSections() {
130     return make_range(Sections.begin(), Sections.end());
131   }
132 
133   const Section *findSection(ssize_t UniqueId) const;
134 
135   void addSections(ArrayRef<Section> NewSections);
136   void removeSections(function_ref<bool(const Section &)> ToRemove);
137   void truncateSections(function_ref<bool(const Section &)> ToTruncate);
138 
139 private:
140   std::vector<Symbol> Symbols;
141   DenseMap<size_t, Symbol *> SymbolMap;
142 
143   size_t NextSymbolUniqueId = 0;
144 
145   std::vector<Section> Sections;
146   DenseMap<ssize_t, Section *> SectionMap;
147 
148   ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.
149 
150   // Update SymbolMap.
151   void updateSymbols();
152 
153   // Update SectionMap and Index in each Section.
154   void updateSections();
155 };
156 
157 // Copy between coff_symbol16 and coff_symbol32.
158 // The source and destination files can use either coff_symbol16 or
159 // coff_symbol32, while we always store them as coff_symbol32 in the
160 // intermediate data structure.
161 template <class Symbol1Ty, class Symbol2Ty>
162 void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src) {
163   static_assert(sizeof(Dest.Name.ShortName) == sizeof(Src.Name.ShortName),
164                 "Mismatched name sizes");
165   memcpy(Dest.Name.ShortName, Src.Name.ShortName, sizeof(Dest.Name.ShortName));
166   Dest.Value = Src.Value;
167   Dest.SectionNumber = Src.SectionNumber;
168   Dest.Type = Src.Type;
169   Dest.StorageClass = Src.StorageClass;
170   Dest.NumberOfAuxSymbols = Src.NumberOfAuxSymbols;
171 }
172 
173 // Copy between pe32_header and pe32plus_header.
174 // We store the intermediate state in a pe32plus_header.
175 template <class PeHeader1Ty, class PeHeader2Ty>
176 void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src) {
177   Dest.Magic = Src.Magic;
178   Dest.MajorLinkerVersion = Src.MajorLinkerVersion;
179   Dest.MinorLinkerVersion = Src.MinorLinkerVersion;
180   Dest.SizeOfCode = Src.SizeOfCode;
181   Dest.SizeOfInitializedData = Src.SizeOfInitializedData;
182   Dest.SizeOfUninitializedData = Src.SizeOfUninitializedData;
183   Dest.AddressOfEntryPoint = Src.AddressOfEntryPoint;
184   Dest.BaseOfCode = Src.BaseOfCode;
185   Dest.ImageBase = Src.ImageBase;
186   Dest.SectionAlignment = Src.SectionAlignment;
187   Dest.FileAlignment = Src.FileAlignment;
188   Dest.MajorOperatingSystemVersion = Src.MajorOperatingSystemVersion;
189   Dest.MinorOperatingSystemVersion = Src.MinorOperatingSystemVersion;
190   Dest.MajorImageVersion = Src.MajorImageVersion;
191   Dest.MinorImageVersion = Src.MinorImageVersion;
192   Dest.MajorSubsystemVersion = Src.MajorSubsystemVersion;
193   Dest.MinorSubsystemVersion = Src.MinorSubsystemVersion;
194   Dest.Win32VersionValue = Src.Win32VersionValue;
195   Dest.SizeOfImage = Src.SizeOfImage;
196   Dest.SizeOfHeaders = Src.SizeOfHeaders;
197   Dest.CheckSum = Src.CheckSum;
198   Dest.Subsystem = Src.Subsystem;
199   Dest.DLLCharacteristics = Src.DLLCharacteristics;
200   Dest.SizeOfStackReserve = Src.SizeOfStackReserve;
201   Dest.SizeOfStackCommit = Src.SizeOfStackCommit;
202   Dest.SizeOfHeapReserve = Src.SizeOfHeapReserve;
203   Dest.SizeOfHeapCommit = Src.SizeOfHeapCommit;
204   Dest.LoaderFlags = Src.LoaderFlags;
205   Dest.NumberOfRvaAndSize = Src.NumberOfRvaAndSize;
206 }
207 
208 } // end namespace coff
209 } // end namespace objcopy
210 } // end namespace llvm
211 
212 #endif // LLVM_LIB_OBJCOPY_COFF_COFFOBJECT_H
213