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