xref: /freebsd/contrib/llvm-project/llvm/lib/ObjCopy/COFF/COFFObject.h (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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/StringRef.h"
15 #include "llvm/ADT/iterator_range.h"
16 #include "llvm/BinaryFormat/COFF.h"
17 #include "llvm/Object/COFF.h"
18 #include <cstddef>
19 #include <cstdint>
20 #include <vector>
21 
22 namespace llvm {
23 namespace objcopy {
24 namespace coff {
25 
26 struct Relocation {
27   Relocation() = default;
RelocationRelocation28   Relocation(const object::coff_relocation &R) : Reloc(R) {}
29 
30   object::coff_relocation Reloc;
31   size_t Target = 0;
32   StringRef TargetName; // Used for diagnostics only
33 };
34 
35 struct Section {
36   object::coff_section Header;
37   std::vector<Relocation> Relocs;
38   StringRef Name;
39   ssize_t UniqueId;
40   size_t Index;
41 
getContentsSection42   ArrayRef<uint8_t> getContents() const {
43     if (!OwnedContents.empty())
44       return OwnedContents;
45     return ContentsRef;
46   }
47 
setContentsRefSection48   void setContentsRef(ArrayRef<uint8_t> Data) {
49     OwnedContents.clear();
50     ContentsRef = Data;
51   }
52 
setOwnedContentsSection53   void setOwnedContents(std::vector<uint8_t> &&Data) {
54     ContentsRef = ArrayRef<uint8_t>();
55     OwnedContents = std::move(Data);
56     Header.SizeOfRawData = OwnedContents.size();
57   }
58 
clearContentsSection59   void clearContents() {
60     ContentsRef = ArrayRef<uint8_t>();
61     OwnedContents.clear();
62   }
63 
64 private:
65   ArrayRef<uint8_t> ContentsRef;
66   std::vector<uint8_t> OwnedContents;
67 };
68 
69 struct AuxSymbol {
AuxSymbolAuxSymbol70   AuxSymbol(ArrayRef<uint8_t> In) {
71     assert(In.size() == sizeof(Opaque));
72     std::copy(In.begin(), In.end(), Opaque);
73   }
74 
getRefAuxSymbol75   ArrayRef<uint8_t> getRef() const {
76     return ArrayRef<uint8_t>(Opaque, sizeof(Opaque));
77   }
78 
79   uint8_t Opaque[sizeof(object::coff_symbol16)];
80 };
81 
82 struct Symbol {
83   object::coff_symbol32 Sym;
84   StringRef Name;
85   std::vector<AuxSymbol> AuxData;
86   StringRef AuxFile;
87   ssize_t TargetSectionId;
88   ssize_t AssociativeComdatTargetSectionId = 0;
89   std::optional<size_t> WeakTargetSymbolId;
90   size_t UniqueId;
91   size_t RawIndex;
92   size_t OriginalRawIndex;
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 
getSymbolsObject110   ArrayRef<Symbol> getSymbols() const { return Symbols; }
111   // This allows mutating individual Symbols, but not mutating the list
112   // of symbols itself.
getMutableSymbolsObject113   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 
getSectionsObject126   ArrayRef<Section> getSections() const { return Sections; }
127   // This allows mutating individual Sections, but not mutating the list
128   // of sections itself.
getMutableSectionsObject129   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   size_t NextSymbolOriginalIndex = 0;
145 
146   std::vector<Section> Sections;
147   DenseMap<ssize_t, Section *> SectionMap;
148 
149   ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.
150 
151   // Update SymbolMap.
152   void updateSymbols();
153 
154   // Update SectionMap and Index in each Section.
155   void updateSections();
156 };
157 
158 // Copy between coff_symbol16 and coff_symbol32.
159 // The source and destination files can use either coff_symbol16 or
160 // coff_symbol32, while we always store them as coff_symbol32 in the
161 // intermediate data structure.
162 template <class Symbol1Ty, class Symbol2Ty>
copySymbol(Symbol1Ty & Dest,const Symbol2Ty & Src)163 void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src) {
164   static_assert(sizeof(Dest.Name.ShortName) == sizeof(Src.Name.ShortName),
165                 "Mismatched name sizes");
166   memcpy(Dest.Name.ShortName, Src.Name.ShortName, sizeof(Dest.Name.ShortName));
167   Dest.Value = Src.Value;
168   Dest.SectionNumber = Src.SectionNumber;
169   Dest.Type = Src.Type;
170   Dest.StorageClass = Src.StorageClass;
171   Dest.NumberOfAuxSymbols = Src.NumberOfAuxSymbols;
172 }
173 
174 // Copy between pe32_header and pe32plus_header.
175 // We store the intermediate state in a pe32plus_header.
176 template <class PeHeader1Ty, class PeHeader2Ty>
copyPeHeader(PeHeader1Ty & Dest,const PeHeader2Ty & Src)177 void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src) {
178   Dest.Magic = Src.Magic;
179   Dest.MajorLinkerVersion = Src.MajorLinkerVersion;
180   Dest.MinorLinkerVersion = Src.MinorLinkerVersion;
181   Dest.SizeOfCode = Src.SizeOfCode;
182   Dest.SizeOfInitializedData = Src.SizeOfInitializedData;
183   Dest.SizeOfUninitializedData = Src.SizeOfUninitializedData;
184   Dest.AddressOfEntryPoint = Src.AddressOfEntryPoint;
185   Dest.BaseOfCode = Src.BaseOfCode;
186   Dest.ImageBase = Src.ImageBase;
187   Dest.SectionAlignment = Src.SectionAlignment;
188   Dest.FileAlignment = Src.FileAlignment;
189   Dest.MajorOperatingSystemVersion = Src.MajorOperatingSystemVersion;
190   Dest.MinorOperatingSystemVersion = Src.MinorOperatingSystemVersion;
191   Dest.MajorImageVersion = Src.MajorImageVersion;
192   Dest.MinorImageVersion = Src.MinorImageVersion;
193   Dest.MajorSubsystemVersion = Src.MajorSubsystemVersion;
194   Dest.MinorSubsystemVersion = Src.MinorSubsystemVersion;
195   Dest.Win32VersionValue = Src.Win32VersionValue;
196   Dest.SizeOfImage = Src.SizeOfImage;
197   Dest.SizeOfHeaders = Src.SizeOfHeaders;
198   Dest.CheckSum = Src.CheckSum;
199   Dest.Subsystem = Src.Subsystem;
200   Dest.DLLCharacteristics = Src.DLLCharacteristics;
201   Dest.SizeOfStackReserve = Src.SizeOfStackReserve;
202   Dest.SizeOfStackCommit = Src.SizeOfStackCommit;
203   Dest.SizeOfHeapReserve = Src.SizeOfHeapReserve;
204   Dest.SizeOfHeapCommit = Src.SizeOfHeapCommit;
205   Dest.LoaderFlags = Src.LoaderFlags;
206   Dest.NumberOfRvaAndSize = Src.NumberOfRvaAndSize;
207 }
208 
209 } // end namespace coff
210 } // end namespace objcopy
211 } // end namespace llvm
212 
213 #endif // LLVM_LIB_OBJCOPY_COFF_COFFOBJECT_H
214