LLVM  6.0.0svn
COFFImportFile.cpp
Go to the documentation of this file.
1 //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the writeImportLibrary function.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/Object/Archive.h"
18 #include "llvm/Object/COFF.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/Path.h"
21 
22 #include <cstdint>
23 #include <map>
24 #include <set>
25 #include <string>
26 #include <vector>
27 
28 using namespace llvm::COFF;
29 using namespace llvm::object;
30 using namespace llvm;
31 
32 namespace llvm {
33 namespace object {
34 
36  switch (Machine) {
37  default:
38  llvm_unreachable("unsupported machine");
41  return false;
44  return true;
45  }
46 }
47 
49  switch (Machine) {
50  default:
51  llvm_unreachable("unsupported machine");
60  }
61 }
62 
63 template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
64  size_t S = B.size();
65  B.resize(S + sizeof(T));
66  memcpy(&B[S], &Data, sizeof(T));
67 }
68 
69 static void writeStringTable(std::vector<uint8_t> &B,
71  // The COFF string table consists of a 4-byte value which is the size of the
72  // table, including the length field itself. This value is followed by the
73  // string content itself, which is an array of null-terminated C-style
74  // strings. The termination is important as they are referenced to by offset
75  // by the symbol entity in the file format.
76 
77  size_t Pos = B.size();
78  size_t Offset = B.size();
79 
80  // Skip over the length field, we will fill it in later as we will have
81  // computed the length while emitting the string content itself.
82  Pos += sizeof(uint32_t);
83 
84  for (const auto &S : Strings) {
85  B.resize(Pos + S.length() + 1);
86  strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
87  Pos += S.length() + 1;
88  }
89 
90  // Backfill the length of the table now that it has been computed.
91  support::ulittle32_t Length(B.size() - Offset);
92  support::endian::write32le(&B[Offset], Length);
93 }
94 
97  if (Sym != ExtName)
99  if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
100  return IMPORT_NAME_NOPREFIX;
101  return IMPORT_NAME;
102 }
103 
105  StringRef To) {
106  size_t Pos = S.find(From);
107 
108  // From and To may be mangled, but substrings in S may not.
109  if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
110  From = From.substr(1);
111  To = To.substr(1);
112  Pos = S.find(From);
113  }
114 
115  if (Pos == StringRef::npos) {
116  return make_error<StringError>(
117  StringRef(Twine(S + ": replacing '" + From +
118  "' with '" + To + "' failed").str()), object_error::parse_failed);
119  }
120 
121  return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
122 }
123 
124 static const std::string NullImportDescriptorSymbolName =
125  "__NULL_IMPORT_DESCRIPTOR";
126 
127 namespace {
128 // This class constructs various small object files necessary to support linking
129 // symbols imported from a DLL. The contents are pretty strictly defined and
130 // nearly entirely static. The details of the structures files are defined in
131 // WINNT.h and the PE/COFF specification.
132 class ObjectFactory {
133  using u16 = support::ulittle16_t;
134  using u32 = support::ulittle32_t;
136  BumpPtrAllocator Alloc;
137  StringRef ImportName;
138  StringRef Library;
139  std::string ImportDescriptorSymbolName;
140  std::string NullThunkSymbolName;
141 
142 public:
143  ObjectFactory(StringRef S, MachineTypes M)
144  : Machine(M), ImportName(S), Library(S.drop_back(4)),
145  ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
146  NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
147 
148  // Creates an Import Descriptor. This is a small object file which contains a
149  // reference to the terminators and contains the library name (entry) for the
150  // import name table. It will force the linker to construct the necessary
151  // structure to import symbols from the DLL.
152  NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
153 
154  // Creates a NULL import descriptor. This is a small object file whcih
155  // contains a NULL import descriptor. It is used to terminate the imports
156  // from a specific DLL.
157  NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
158 
159  // Create a NULL Thunk Entry. This is a small object file which contains a
160  // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
161  // is used to terminate the IAT and ILT.
162  NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
163 
164  // Create a short import file which is described in PE/COFF spec 7. Import
165  // Library Format.
166  NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
167  ImportType Type, ImportNameType NameType);
168 
169  // Create a weak external file which is described in PE/COFF Aux Format 3.
170  NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
171 };
172 } // namespace
173 
175 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
176  const uint32_t NumberOfSections = 2;
177  const uint32_t NumberOfSymbols = 7;
178  const uint32_t NumberOfRelocations = 3;
179 
180  // COFF Header
181  coff_file_header Header{
182  u16(Machine),
183  u16(NumberOfSections),
184  u32(0),
185  u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
186  // .idata$2
188  NumberOfRelocations * sizeof(coff_relocation) +
189  // .idata$4
190  (ImportName.size() + 1)),
191  u32(NumberOfSymbols),
192  u16(0),
194  };
195  append(Buffer, Header);
196 
197  // Section Header Table
198  const coff_section SectionTable[NumberOfSections] = {
199  {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
200  u32(0),
201  u32(0),
203  u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
204  u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
206  u32(0),
207  u16(NumberOfRelocations),
208  u16(0),
211  {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
212  u32(0),
213  u32(0),
214  u32(ImportName.size() + 1),
215  u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
217  NumberOfRelocations * sizeof(coff_relocation)),
218  u32(0),
219  u32(0),
220  u16(0),
221  u16(0),
224  };
225  append(Buffer, SectionTable);
226 
227  // .idata$2
228  const coff_import_directory_table_entry ImportDescriptor{
229  u32(0), u32(0), u32(0), u32(0), u32(0),
230  };
231  append(Buffer, ImportDescriptor);
232 
233  const coff_relocation RelocationTable[NumberOfRelocations] = {
234  {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
236  {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
237  u32(3), u16(getImgRelRelocation(Machine))},
238  {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
239  u32(4), u16(getImgRelRelocation(Machine))},
240  };
241  append(Buffer, RelocationTable);
242 
243  // .idata$6
244  auto S = Buffer.size();
245  Buffer.resize(S + ImportName.size() + 1);
246  memcpy(&Buffer[S], ImportName.data(), ImportName.size());
247  Buffer[S + ImportName.size()] = '\0';
248 
249  // Symbol Table
250  coff_symbol16 SymbolTable[NumberOfSymbols] = {
251  {{{0, 0, 0, 0, 0, 0, 0, 0}},
252  u32(0),
253  u16(1),
254  u16(0),
256  0},
257  {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
258  u32(0),
259  u16(1),
260  u16(0),
262  0},
263  {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
264  u32(0),
265  u16(2),
266  u16(0),
268  0},
269  {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
270  u32(0),
271  u16(0),
272  u16(0),
274  0},
275  {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
276  u32(0),
277  u16(0),
278  u16(0),
280  0},
281  {{{0, 0, 0, 0, 0, 0, 0, 0}},
282  u32(0),
283  u16(0),
284  u16(0),
286  0},
287  {{{0, 0, 0, 0, 0, 0, 0, 0}},
288  u32(0),
289  u16(0),
290  u16(0),
292  0},
293  };
294  // TODO: Name.Offset.Offset here and in the all similar places below
295  // suggests a names refactoring. Maybe StringTableOffset.Value?
296  SymbolTable[0].Name.Offset.Offset =
297  sizeof(uint32_t);
298  SymbolTable[5].Name.Offset.Offset =
299  sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
300  SymbolTable[6].Name.Offset.Offset =
301  sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
302  NullImportDescriptorSymbolName.length() + 1;
303  append(Buffer, SymbolTable);
304 
305  // String Table
306  writeStringTable(Buffer,
307  {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
308  NullThunkSymbolName});
309 
310  StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
311  return {MemoryBufferRef(F, ImportName)};
312 }
313 
315 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
316  const uint32_t NumberOfSections = 1;
317  const uint32_t NumberOfSymbols = 1;
318 
319  // COFF Header
320  coff_file_header Header{
321  u16(Machine),
322  u16(NumberOfSections),
323  u32(0),
324  u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
325  // .idata$3
327  u32(NumberOfSymbols),
328  u16(0),
330  };
331  append(Buffer, Header);
332 
333  // Section Header Table
334  const coff_section SectionTable[NumberOfSections] = {
335  {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
336  u32(0),
337  u32(0),
339  u32(sizeof(coff_file_header) +
340  (NumberOfSections * sizeof(coff_section))),
341  u32(0),
342  u32(0),
343  u16(0),
344  u16(0),
347  };
348  append(Buffer, SectionTable);
349 
350  // .idata$3
351  const coff_import_directory_table_entry ImportDescriptor{
352  u32(0), u32(0), u32(0), u32(0), u32(0),
353  };
354  append(Buffer, ImportDescriptor);
355 
356  // Symbol Table
357  coff_symbol16 SymbolTable[NumberOfSymbols] = {
358  {{{0, 0, 0, 0, 0, 0, 0, 0}},
359  u32(0),
360  u16(1),
361  u16(0),
363  0},
364  };
365  SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
366  append(Buffer, SymbolTable);
367 
368  // String Table
369  writeStringTable(Buffer, {NullImportDescriptorSymbolName});
370 
371  StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
372  return {MemoryBufferRef(F, ImportName)};
373 }
374 
375 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
376  const uint32_t NumberOfSections = 2;
377  const uint32_t NumberOfSymbols = 1;
378  uint32_t VASize = is32bit(Machine) ? 4 : 8;
379 
380  // COFF Header
381  coff_file_header Header{
382  u16(Machine),
383  u16(NumberOfSections),
384  u32(0),
385  u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
386  // .idata$5
387  VASize +
388  // .idata$4
389  VASize),
390  u32(NumberOfSymbols),
391  u16(0),
393  };
394  append(Buffer, Header);
395 
396  // Section Header Table
397  const coff_section SectionTable[NumberOfSections] = {
398  {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
399  u32(0),
400  u32(0),
401  u32(VASize),
402  u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
403  u32(0),
404  u32(0),
405  u16(0),
406  u16(0),
411  {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
412  u32(0),
413  u32(0),
414  u32(VASize),
415  u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
416  VASize),
417  u32(0),
418  u32(0),
419  u16(0),
420  u16(0),
425  };
426  append(Buffer, SectionTable);
427 
428  // .idata$5, ILT
429  append(Buffer, u32(0));
430  if (!is32bit(Machine))
431  append(Buffer, u32(0));
432 
433  // .idata$4, IAT
434  append(Buffer, u32(0));
435  if (!is32bit(Machine))
436  append(Buffer, u32(0));
437 
438  // Symbol Table
439  coff_symbol16 SymbolTable[NumberOfSymbols] = {
440  {{{0, 0, 0, 0, 0, 0, 0, 0}},
441  u32(0),
442  u16(1),
443  u16(0),
445  0},
446  };
447  SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
448  append(Buffer, SymbolTable);
449 
450  // String Table
451  writeStringTable(Buffer, {NullThunkSymbolName});
452 
453  StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
454  return {MemoryBufferRef{F, ImportName}};
455 }
456 
457 NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
458  uint16_t Ordinal,
460  ImportNameType NameType) {
461  size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
462  size_t Size = sizeof(coff_import_header) + ImpSize;
463  char *Buf = Alloc.Allocate<char>(Size);
464  memset(Buf, 0, Size);
465  char *P = Buf;
466 
467  // Write short import library.
468  auto *Imp = reinterpret_cast<coff_import_header *>(P);
469  P += sizeof(*Imp);
470  Imp->Sig2 = 0xFFFF;
471  Imp->Machine = Machine;
472  Imp->SizeOfData = ImpSize;
473  if (Ordinal > 0)
474  Imp->OrdinalHint = Ordinal;
475  Imp->TypeInfo = (NameType << 2) | ImportType;
476 
477  // Write symbol name and DLL name.
478  memcpy(P, Sym.data(), Sym.size());
479  P += Sym.size() + 1;
480  memcpy(P, ImportName.data(), ImportName.size());
481 
482  return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
483 }
484 
485 NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
486  StringRef Weak, bool Imp) {
487  std::vector<uint8_t> Buffer;
488  const uint32_t NumberOfSections = 1;
489  const uint32_t NumberOfSymbols = 5;
490 
491  // COFF Header
492  coff_file_header Header{
493  u16(0),
494  u16(NumberOfSections),
495  u32(0),
496  u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
497  u32(NumberOfSymbols),
498  u16(0),
499  u16(0),
500  };
501  append(Buffer, Header);
502 
503  // Section Header Table
504  const coff_section SectionTable[NumberOfSections] = {
505  {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
506  u32(0),
507  u32(0),
508  u32(0),
509  u32(0),
510  u32(0),
511  u32(0),
512  u16(0),
513  u16(0),
515  append(Buffer, SectionTable);
516 
517  // Symbol Table
518  coff_symbol16 SymbolTable[NumberOfSymbols] = {
519  {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
520  u32(0),
521  u16(0xFFFF),
522  u16(0),
524  0},
525  {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
526  u32(0),
527  u16(0xFFFF),
528  u16(0),
530  0},
531  {{{0, 0, 0, 0, 0, 0, 0, 0}},
532  u32(0),
533  u16(0),
534  u16(0),
536  0},
537  {{{0, 0, 0, 0, 0, 0, 0, 0}},
538  u32(0),
539  u16(0),
540  u16(0),
542  1},
543  {{{2, 0, 0, 0, 3, 0, 0, 0}}, u32(0), u16(0), u16(0), uint8_t(0), 0},
544  };
545  SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
546 
547  //__imp_ String Table
548  StringRef Prefix = Imp ? "__imp_" : "";
549  SymbolTable[3].Name.Offset.Offset =
550  sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
551  append(Buffer, SymbolTable);
552  writeStringTable(Buffer, {(Prefix + Sym).str(),
553  (Prefix + Weak).str()});
554 
555  // Copied here so we can still use writeStringTable
556  char *Buf = Alloc.Allocate<char>(Buffer.size());
557  memcpy(Buf, Buffer.data(), Buffer.size());
558  return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
559 }
560 
563  MachineTypes Machine, bool MakeWeakAliases) {
564 
565  std::vector<NewArchiveMember> Members;
566  ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
567 
568  std::vector<uint8_t> ImportDescriptor;
569  Members.push_back(OF.createImportDescriptor(ImportDescriptor));
570 
571  std::vector<uint8_t> NullImportDescriptor;
572  Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
573 
574  std::vector<uint8_t> NullThunk;
575  Members.push_back(OF.createNullThunk(NullThunk));
576 
577  for (COFFShortExport E : Exports) {
578  if (E.Private)
579  continue;
580 
581  if (E.isWeak() && MakeWeakAliases) {
582  Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, false));
583  Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, true));
584  continue;
585  }
586 
587  ImportType ImportType = IMPORT_CODE;
588  if (E.Data)
589  ImportType = IMPORT_DATA;
590  if (E.Constant)
591  ImportType = IMPORT_CONST;
592 
593  StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
594  ImportNameType NameType = getNameType(SymbolName, E.Name, Machine);
595  Expected<std::string> Name = E.ExtName.empty()
596  ? SymbolName
597  : replace(SymbolName, E.Name, E.ExtName);
598 
599  if (!Name)
600  return Name.takeError();
601 
602  Members.push_back(
603  OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
604  }
605 
606  return writeArchive(Path, Members, /*WriteSymtab*/ true,
608  /*Deterministic*/ true, /*Thin*/ false);
609 }
610 
611 } // namespace object
612 } // namespace llvm
static const std::string NullImportDescriptorSymbolName
static ImportNameType getNameType(StringRef Sym, StringRef ExtName, MachineTypes Machine)
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
static void append(std::vector< uint8_t > &B, const T &Data)
ImportNameType
Definition: COFF.h:675
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const
size - Get the string size.
Definition: StringRef.h:138
void write32le(void *P, uint32_t V)
Definition: Endian.h:404
F(f)
Error takeError()
Take ownership of the stored error.
Definition: Error.h:537
detail::packed_endian_specific_integral< uint16_t, little, unaligned > ulittle16_t
Definition: Endian.h:269
static bool is32bit(MachineTypes Machine)
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:128
Error writeArchive(StringRef ArcName, ArrayRef< NewArchiveMember > NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr< MemoryBuffer > OldArchiveBuf=nullptr)
The import name is the public symbol name, but skipping the leading ?, @, or optionally _...
Definition: COFF.h:688
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The import name is identical to the public symbol name.
Definition: COFF.h:682
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
union llvm::object::coff_symbol::@245 Name
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:267
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:33
COFF::MachineTypes Machine
Definition: COFFYAML.cpp:363
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:598
Machine is based on a 32bit word architecture.
Definition: COFF.h:143
#define P(N)
Error writeImportLibrary(StringRef ImportName, StringRef Path, ArrayRef< COFFShortExport > Exports, COFF::MachineTypes Machine, bool MakeWeakAliases)
static uint16_t getImgRelRelocation(MachineTypes Machine)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:271
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:138
Line number, reformatted as symbol.
Definition: COFF.h:231
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * Allocate(size_t Size, size_t Alignment)
Allocate space at the specified alignment.
Definition: Allocator.h:212
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: COFF.h:530
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE StringRef drop_back(size_t N=1) const
Return a StringRef equal to &#39;this&#39; but with the last N elements dropped.
Definition: StringRef.h:654
static const size_t npos
Definition: StringRef.h:51
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:575
static void writeStringTable(std::vector< uint8_t > &B, ArrayRef< const std::string > Strings)
MachineTypes
Definition: COFF.h:94
constexpr char Size[]
Key for Kernel::Arg::Metadata::mSize.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
static Expected< std::string > replace(StringRef S, StringRef From, StringRef To)
The import name is the public symbol name, but skipping the leading ?, @, or optionally _...
Definition: COFF.h:685
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:298
StringTableOffset Offset
Definition: COFF.h:254
ImportType
Definition: COFF.h:673
support::ulittle32_t Offset
Definition: COFF.h:247