1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include "InputFiles.h" |
11 | #include "Chunks.h" |
12 | #include "Config.h" |
13 | #include "Driver.h" |
14 | #include "Error.h" |
15 | #include "Memory.h" |
16 | #include "SymbolTable.h" |
17 | #include "Symbols.h" |
18 | #include "llvm-c/lto.h" |
19 | #include "llvm/ADT/SmallVector.h" |
20 | #include "llvm/ADT/Triple.h" |
21 | #include "llvm/ADT/Twine.h" |
22 | #include "llvm/Object/Binary.h" |
23 | #include "llvm/Object/COFF.h" |
24 | #include "llvm/Support/COFF.h" |
25 | #include "llvm/Support/Casting.h" |
26 | #include "llvm/Support/Endian.h" |
27 | #include "llvm/Support/Error.h" |
28 | #include "llvm/Support/ErrorOr.h" |
29 | #include "llvm/Support/FileSystem.h" |
30 | #include "llvm/Target/TargetOptions.h" |
31 | #include <cstring> |
32 | #include <system_error> |
33 | #include <utility> |
34 | |
35 | using namespace llvm; |
36 | using namespace llvm::COFF; |
37 | using namespace llvm::object; |
38 | using namespace llvm::support::endian; |
39 | |
40 | using llvm::Triple; |
41 | using llvm::support::ulittle32_t; |
42 | |
43 | namespace lld { |
44 | namespace coff { |
45 | |
46 | |
47 | |
48 | |
49 | static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, |
50 | SymbolBody *Source, SymbolBody *Target) { |
51 | auto *U = dyn_cast<Undefined>(Source); |
52 | if (!U) |
53 | return; |
54 | else if (!U->WeakAlias) |
55 | U->WeakAlias = Target; |
56 | else if (U->WeakAlias != Target) |
57 | Symtab->reportDuplicate(Source->symbol(), F); |
58 | } |
59 | |
60 | ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} |
61 | |
62 | void ArchiveFile::parse() { |
63 | |
64 | File = check(Archive::create(MB), toString(this)); |
65 | |
66 | |
67 | for (const Archive::Symbol &Sym : File->symbols()) |
68 | Symtab->addLazy(this, Sym); |
69 | } |
70 | |
71 | |
72 | void ArchiveFile::addMember(const Archive::Symbol *Sym) { |
73 | const Archive::Child &C = |
74 | check(Sym->getMember(), |
75 | "could not get the member for symbol " + Sym->getName()); |
76 | |
77 | |
78 | if (!Seen.insert(C.getChildOffset()).second) |
79 | return; |
80 | |
81 | Driver->enqueueArchiveMember(C, Sym->getName(), getName()); |
82 | } |
83 | |
84 | void ObjectFile::parse() { |
85 | |
86 | std::unique_ptr<Binary> Bin = check(createBinary(MB), toString(this)); |
87 | |
88 | if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) { |
| 1 | Assuming 'Obj' is non-null | |
|
| |
89 | Bin.release(); |
90 | COFFObj.reset(Obj); |
91 | } else { |
92 | fatal(toString(this) + " is not a COFF file"); |
93 | } |
94 | |
95 | |
96 | initializeChunks(); |
97 | initializeSymbols(); |
| 3 | | Calling 'ObjectFile::initializeSymbols' | |
|
98 | initializeSEH(); |
99 | } |
100 | |
101 | void ObjectFile::initializeChunks() { |
102 | uint32_t NumSections = COFFObj->getNumberOfSections(); |
103 | Chunks.reserve(NumSections); |
104 | SparseChunks.resize(NumSections + 1); |
105 | for (uint32_t I = 1; I < NumSections + 1; ++I) { |
106 | const coff_section *Sec; |
107 | StringRef Name; |
108 | if (auto EC = COFFObj->getSection(I, Sec)) |
109 | fatal(EC, "getSection failed: #" + Twine(I)); |
110 | if (auto EC = COFFObj->getSectionName(Sec, Name)) |
111 | fatal(EC, "getSectionName failed: #" + Twine(I)); |
112 | if (Name == ".sxdata") { |
113 | SXData = Sec; |
114 | continue; |
115 | } |
116 | if (Name == ".drectve") { |
117 | ArrayRef<uint8_t> Data; |
118 | COFFObj->getSectionContents(Sec, Data); |
119 | Directives = std::string((const char *)Data.data(), Data.size()); |
120 | continue; |
121 | } |
122 | |
123 | |
124 | |
125 | |
126 | |
127 | |
128 | |
129 | |
130 | |
131 | |
132 | |
133 | |
134 | if (!Config->Debug && Name.startswith(".debug")) |
135 | continue; |
136 | |
137 | |
138 | |
139 | if (Name == ".debug" || Name.startswith(".debug$")) { |
140 | DebugChunks.push_back(new (Alloc) SectionChunk(this, Sec)); |
141 | continue; |
142 | } |
143 | |
144 | if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) |
145 | continue; |
146 | auto *C = new (Alloc) SectionChunk(this, Sec); |
147 | Chunks.push_back(C); |
148 | SparseChunks[I] = C; |
149 | } |
150 | } |
151 | |
152 | void ObjectFile::initializeSymbols() { |
153 | uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); |
154 | SymbolBodies.reserve(NumSymbols); |
155 | SparseSymbolBodies.resize(NumSymbols); |
156 | SmallVector<std::pair<SymbolBody *, uint32_t>, 8> WeakAliases; |
157 | int32_t LastSectionNumber = 0; |
158 | for (uint32_t I = 0; I < NumSymbols; ++I) { |
| 4 | | Assuming 'I' is < 'NumSymbols' | |
|
| 5 | | Loop condition is true. Entering loop body | |
|
| 12 | | Loop condition is true. Entering loop body | |
|
| 18 | | Loop condition is true. Entering loop body | |
|
| 24 | | Loop condition is true. Entering loop body | |
|
159 | |
160 | ErrorOr<COFFSymbolRef> SymOrErr = COFFObj->getSymbol(I); |
161 | if (!SymOrErr) |
| |
| |
| |
| |
162 | fatal(SymOrErr.getError(), "broken object file: " + toString(this)); |
163 | COFFSymbolRef Sym = *SymOrErr; |
164 | |
165 | const void *AuxP = nullptr; |
| 26 | | 'AuxP' initialized to a null pointer value | |
|
166 | if (Sym.getNumberOfAuxSymbols()) |
| |
| |
| |
| |
167 | AuxP = COFFObj->getSymbol(I + 1)->getRawPtr(); |
168 | bool IsFirst = (LastSectionNumber != Sym.getSectionNumber()); |
| 8 | | Assuming the condition is false | |
|
169 | |
170 | SymbolBody *Body = nullptr; |
171 | if (Sym.isUndefined()) { |
| |
| |
| |
| |
172 | Body = createUndefined(Sym); |
173 | } else if (Sym.isWeakExternal()) { |
| |
| |
| |
| |
174 | Body = createUndefined(Sym); |
175 | uint32_t TagIndex = |
176 | static_cast<const coff_aux_weak_external *>(AuxP)->TagIndex; |
| 30 | | Called C++ object pointer is null |
|
177 | WeakAliases.emplace_back(Body, TagIndex); |
178 | } else { |
179 | Body = createDefined(Sym, AuxP, IsFirst); |
180 | } |
181 | if (Body) { |
| |
| |
| |
182 | SymbolBodies.push_back(Body); |
183 | SparseSymbolBodies[I] = Body; |
184 | } |
185 | I += Sym.getNumberOfAuxSymbols(); |
186 | LastSectionNumber = Sym.getSectionNumber(); |
187 | } |
188 | for (auto WeakAlias : WeakAliases) |
189 | checkAndSetWeakAlias(Symtab, this, WeakAlias.first, |
190 | SparseSymbolBodies[WeakAlias.second]); |
191 | } |
192 | |
193 | SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { |
194 | StringRef Name; |
195 | COFFObj->getSymbolName(Sym, Name); |
196 | return Symtab->addUndefined(Name, this, Sym.isWeakExternal())->body(); |
197 | } |
198 | |
199 | SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, |
200 | bool IsFirst) { |
201 | StringRef Name; |
202 | if (Sym.isCommon()) { |
203 | auto *C = new (Alloc) CommonChunk(Sym); |
204 | Chunks.push_back(C); |
205 | COFFObj->getSymbolName(Sym, Name); |
206 | Symbol *S = |
207 | Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); |
208 | return S->body(); |
209 | } |
210 | if (Sym.isAbsolute()) { |
211 | COFFObj->getSymbolName(Sym, Name); |
212 | |
213 | if (Name == "@comp.id") |
214 | return nullptr; |
215 | |
216 | if (Name == "@feat.00") { |
217 | if (Sym.getValue() & 1) |
218 | SEHCompat = true; |
219 | return nullptr; |
220 | } |
221 | if (Sym.isExternal()) |
222 | return Symtab->addAbsolute(Name, Sym)->body(); |
223 | else |
224 | return new (Alloc) DefinedAbsolute(Name, Sym); |
225 | } |
226 | int32_t SectionNumber = Sym.getSectionNumber(); |
227 | if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) |
228 | return nullptr; |
229 | |
230 | |
231 | if (llvm::COFF::isReservedSectionNumber(SectionNumber)) |
232 | fatal("broken object file: " + toString(this)); |
233 | |
234 | |
235 | |
236 | if ((uint32_t)SectionNumber >= SparseChunks.size()) |
237 | fatal("broken object file: " + toString(this)); |
238 | |
239 | |
240 | auto *SC = cast_or_null<SectionChunk>(SparseChunks[SectionNumber]); |
241 | if (!SC) |
242 | return nullptr; |
243 | |
244 | |
245 | if (IsFirst && AuxP) { |
246 | auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP); |
247 | if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) |
248 | if (auto *ParentSC = cast_or_null<SectionChunk>( |
249 | SparseChunks[Aux->getNumber(Sym.isBigObj())])) |
250 | ParentSC->addAssociative(SC); |
251 | SC->Checksum = Aux->CheckSum; |
252 | } |
253 | |
254 | DefinedRegular *B; |
255 | if (Sym.isExternal()) { |
256 | COFFObj->getSymbolName(Sym, Name); |
257 | Symbol *S = |
258 | Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC); |
259 | B = cast<DefinedRegular>(S->body()); |
260 | } else |
261 | B = new (Alloc) DefinedRegular(this, "", SC->isCOMDAT(), |
262 | false, Sym.getGeneric(), SC); |
263 | if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) |
264 | SC->setSymbol(B); |
265 | |
266 | return B; |
267 | } |
268 | |
269 | void ObjectFile::initializeSEH() { |
270 | if (!SEHCompat || !SXData) |
271 | return; |
272 | ArrayRef<uint8_t> A; |
273 | COFFObj->getSectionContents(SXData, A); |
274 | if (A.size() % 4 != 0) |
275 | fatal(".sxdata must be an array of symbol table indices"); |
276 | auto *I = reinterpret_cast<const ulittle32_t *>(A.data()); |
277 | auto *E = reinterpret_cast<const ulittle32_t *>(A.data() + A.size()); |
278 | for (; I != E; ++I) |
279 | SEHandlers.insert(SparseSymbolBodies[*I]); |
280 | } |
281 | |
282 | MachineTypes ObjectFile::getMachineType() { |
283 | if (COFFObj) |
284 | return static_cast<MachineTypes>(COFFObj->getMachine()); |
285 | return IMAGE_FILE_MACHINE_UNKNOWN; |
286 | } |
287 | |
288 | StringRef ltrim1(StringRef S, const char *Chars) { |
289 | if (!S.empty() && strchr(Chars, S[0])) |
290 | return S.substr(1); |
291 | return S; |
292 | } |
293 | |
294 | void ImportFile::parse() { |
295 | const char *Buf = MB.getBufferStart(); |
296 | const char *End = MB.getBufferEnd(); |
297 | const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf); |
298 | |
299 | |
300 | if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) |
301 | fatal("broken import library"); |
302 | |
303 | |
304 | StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr))); |
305 | StringRef ImpName = StringAlloc.save("__imp_" + Name); |
306 | const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; |
307 | DLLName = StringRef(NameStart); |
308 | StringRef ExtName; |
309 | switch (Hdr->getNameType()) { |
310 | case IMPORT_ORDINAL: |
311 | ExtName = ""; |
312 | break; |
313 | case IMPORT_NAME: |
314 | ExtName = Name; |
315 | break; |
316 | case IMPORT_NAME_NOPREFIX: |
317 | ExtName = ltrim1(Name, "?@_"); |
318 | break; |
319 | case IMPORT_NAME_UNDECORATE: |
320 | ExtName = ltrim1(Name, "?@_"); |
321 | ExtName = ExtName.substr(0, ExtName.find('@')); |
322 | break; |
323 | } |
324 | |
325 | this->Hdr = Hdr; |
326 | ExternalName = ExtName; |
327 | |
328 | ImpSym = cast<DefinedImportData>( |
329 | Symtab->addImportData(ImpName, this)->body()); |
330 | if (Hdr->getType() == llvm::COFF::IMPORT_CONST) |
331 | ConstSym = |
332 | cast<DefinedImportData>(Symtab->addImportData(Name, this)->body()); |
333 | |
334 | |
335 | |
336 | |
337 | if (Hdr->getType() != llvm::COFF::IMPORT_CODE) |
338 | return; |
339 | ThunkSym = cast<DefinedImportThunk>( |
340 | Symtab->addImportThunk(Name, ImpSym, Hdr->Machine)->body()); |
341 | } |
342 | |
343 | void BitcodeFile::parse() { |
344 | Obj = check(lto::InputFile::create(MemoryBufferRef( |
345 | MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier())))); |
346 | for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { |
347 | StringRef SymName = Saver.save(ObjSym.getName()); |
348 | Symbol *Sym; |
349 | if (ObjSym.isUndefined()) { |
350 | Sym = Symtab->addUndefined(SymName, this, false); |
351 | } else if (ObjSym.isCommon()) { |
352 | Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize()); |
353 | } else if (ObjSym.isWeak() && ObjSym.isIndirect()) { |
354 | |
355 | Sym = Symtab->addUndefined(SymName, this, true); |
356 | std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); |
357 | SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback)); |
358 | checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias); |
359 | } else { |
360 | bool IsCOMDAT = ObjSym.getComdatIndex() != -1; |
361 | Sym = Symtab->addRegular(this, SymName, IsCOMDAT); |
362 | } |
363 | SymbolBodies.push_back(Sym->body()); |
364 | } |
365 | Directives = Obj->getCOFFLinkerOpts(); |
366 | } |
367 | |
368 | MachineTypes BitcodeFile::getMachineType() { |
369 | switch (Triple(Obj->getTargetTriple()).getArch()) { |
370 | case Triple::x86_64: |
371 | return AMD64; |
372 | case Triple::x86: |
373 | return I386; |
374 | case Triple::arm: |
375 | return ARMNT; |
376 | default: |
377 | return IMAGE_FILE_MACHINE_UNKNOWN; |
378 | } |
379 | } |
380 | } |
381 | } |
382 | |
383 | |
384 | static StringRef getBasename(StringRef Path) { |
385 | size_t Pos = Path.find_last_of("\\/"); |
386 | if (Pos == StringRef::npos) |
387 | return Path; |
388 | return Path.substr(Pos + 1); |
389 | } |
390 | |
391 | |
392 | std::string lld::toString(coff::InputFile *File) { |
393 | if (!File) |
394 | return "(internal)"; |
395 | if (File->ParentName.empty()) |
396 | return File->getName().lower(); |
397 | |
398 | std::string Res = |
399 | (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") |
400 | .str(); |
401 | return StringRef(Res).lower(); |
402 | } |