1 //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the writeImportLibrary function.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/Object/COFFImportFile.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/Twine.h"
18 #include "llvm/Object/Archive.h"
19 #include "llvm/Object/ArchiveWriter.h"
20 #include "llvm/Object/COFF.h"
21 #include "llvm/Support/Allocator.h"
22 #include "llvm/Support/Endian.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include "llvm/Support/Path.h"
31 using namespace llvm::COFF
;
32 using namespace llvm::object
;
38 StringRef
COFFImportFile::getFileFormatName() const {
39 switch (getMachine()) {
40 case COFF::IMAGE_FILE_MACHINE_I386
:
41 return "COFF-import-file-i386";
42 case COFF::IMAGE_FILE_MACHINE_AMD64
:
43 return "COFF-import-file-x86-64";
44 case COFF::IMAGE_FILE_MACHINE_ARMNT
:
45 return "COFF-import-file-ARM";
46 case COFF::IMAGE_FILE_MACHINE_ARM64
:
47 return "COFF-import-file-ARM64";
48 case COFF::IMAGE_FILE_MACHINE_ARM64EC
:
49 return "COFF-import-file-ARM64EC";
50 case COFF::IMAGE_FILE_MACHINE_ARM64X
:
51 return "COFF-import-file-ARM64X";
53 return "COFF-import-file-<unknown arch>";
57 static StringRef
applyNameType(ImportNameType Type
, StringRef name
) {
58 auto ltrim1
= [](StringRef s
, StringRef chars
) {
59 return !s
.empty() && chars
.contains(s
[0]) ? s
.substr(1) : s
;
63 case IMPORT_NAME_NOPREFIX
:
64 name
= ltrim1(name
, "?@_");
66 case IMPORT_NAME_UNDECORATE
:
67 name
= ltrim1(name
, "?@_");
68 name
= name
.substr(0, name
.find('@'));
76 StringRef
COFFImportFile::getExportName() const {
77 const coff_import_header
*hdr
= getCOFFImportHeader();
78 StringRef name
= Data
.getBuffer().substr(sizeof(*hdr
)).split('\0').first
;
80 switch (hdr
->getNameType()) {
84 case IMPORT_NAME_NOPREFIX
:
85 case IMPORT_NAME_UNDECORATE
:
86 name
= applyNameType(static_cast<ImportNameType
>(hdr
->getNameType()), name
);
88 case IMPORT_NAME_EXPORTAS
: {
90 name
= Data
.getBuffer().substr(sizeof(*hdr
) + name
.size() + 1);
91 name
= name
.split('\0').second
.split('\0').first
;
101 Error
COFFImportFile::printSymbolName(raw_ostream
&OS
, DataRefImpl Symb
) const {
110 const char *Name
= Data
.getBufferStart() + sizeof(coff_import_header
);
111 if (Symb
.p
!= ECThunkSymbol
&& COFF::isArm64EC(getMachine())) {
112 if (std::optional
<std::string
> DemangledName
=
113 getArm64ECDemangledFunctionName(Name
)) {
114 OS
<< StringRef(*DemangledName
);
115 return Error::success();
118 OS
<< StringRef(Name
);
119 return Error::success();
122 static uint16_t getImgRelRelocation(MachineTypes Machine
) {
125 llvm_unreachable("unsupported machine");
126 case IMAGE_FILE_MACHINE_AMD64
:
127 return IMAGE_REL_AMD64_ADDR32NB
;
128 case IMAGE_FILE_MACHINE_ARMNT
:
129 return IMAGE_REL_ARM_ADDR32NB
;
130 case IMAGE_FILE_MACHINE_ARM64
:
131 case IMAGE_FILE_MACHINE_ARM64EC
:
132 case IMAGE_FILE_MACHINE_ARM64X
:
133 return IMAGE_REL_ARM64_ADDR32NB
;
134 case IMAGE_FILE_MACHINE_I386
:
135 return IMAGE_REL_I386_DIR32NB
;
136 case IMAGE_FILE_MACHINE_R4000
:
137 return IMAGE_REL_MIPS_REFWORDNB
;
141 template <class T
> static void append(std::vector
<uint8_t> &B
, const T
&Data
) {
143 B
.resize(S
+ sizeof(T
));
144 memcpy(&B
[S
], &Data
, sizeof(T
));
147 static void writeStringTable(std::vector
<uint8_t> &B
,
148 ArrayRef
<const std::string_view
> Strings
) {
149 // The COFF string table consists of a 4-byte value which is the size of the
150 // table, including the length field itself. This value is followed by the
151 // string content itself, which is an array of null-terminated C-style
152 // strings. The termination is important as they are referenced to by offset
153 // by the symbol entity in the file format.
155 size_t Pos
= B
.size();
156 size_t Offset
= B
.size();
158 // Skip over the length field, we will fill it in later as we will have
159 // computed the length while emitting the string content itself.
160 Pos
+= sizeof(uint32_t);
162 for (const auto &S
: Strings
) {
163 B
.resize(Pos
+ S
.length() + 1);
164 std::copy(S
.begin(), S
.end(), std::next(B
.begin(), Pos
));
165 B
[Pos
+ S
.length()] = 0;
166 Pos
+= S
.length() + 1;
169 // Backfill the length of the table now that it has been computed.
170 support::ulittle32_t
Length(B
.size() - Offset
);
171 support::endian::write32le(&B
[Offset
], Length
);
174 static ImportNameType
getNameType(StringRef Sym
, StringRef ExtName
,
175 MachineTypes Machine
, bool MinGW
) {
176 // A decorated stdcall function in MSVC is exported with the
177 // type IMPORT_NAME, and the exported function name includes the
178 // the leading underscore. In MinGW on the other hand, a decorated
179 // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
180 // See the comment in isDecorated in COFFModuleDefinition.cpp for more
182 if (ExtName
.starts_with("_") && ExtName
.contains('@') && !MinGW
)
185 return IMPORT_NAME_UNDECORATE
;
186 if (Machine
== IMAGE_FILE_MACHINE_I386
&& Sym
.starts_with("_"))
187 return IMPORT_NAME_NOPREFIX
;
191 static Expected
<std::string
> replace(StringRef S
, StringRef From
,
193 size_t Pos
= S
.find(From
);
195 // From and To may be mangled, but substrings in S may not.
196 if (Pos
== StringRef::npos
&& From
.starts_with("_") && To
.starts_with("_")) {
197 From
= From
.substr(1);
202 if (Pos
== StringRef::npos
) {
203 return make_error
<StringError
>(
204 StringRef(Twine(S
+ ": replacing '" + From
+
205 "' with '" + To
+ "' failed").str()), object_error::parse_failed
);
208 return (Twine(S
.substr(0, Pos
)) + To
+ S
.substr(Pos
+ From
.size())).str();
212 // This class constructs various small object files necessary to support linking
213 // symbols imported from a DLL. The contents are pretty strictly defined and
214 // nearly entirely static. The details of the structures files are defined in
215 // WINNT.h and the PE/COFF specification.
216 class ObjectFactory
{
217 using u16
= support::ulittle16_t
;
218 using u32
= support::ulittle32_t
;
219 MachineTypes NativeMachine
;
220 BumpPtrAllocator Alloc
;
221 StringRef ImportName
;
223 std::string ImportDescriptorSymbolName
;
224 std::string NullThunkSymbolName
;
227 ObjectFactory(StringRef S
, MachineTypes M
)
228 : NativeMachine(M
), ImportName(S
), Library(llvm::sys::path::stem(S
)),
229 ImportDescriptorSymbolName((ImportDescriptorPrefix
+ Library
).str()),
231 (NullThunkDataPrefix
+ Library
+ NullThunkDataSuffix
).str()) {}
233 // Creates an Import Descriptor. This is a small object file which contains a
234 // reference to the terminators and contains the library name (entry) for the
235 // import name table. It will force the linker to construct the necessary
236 // structure to import symbols from the DLL.
237 NewArchiveMember
createImportDescriptor(std::vector
<uint8_t> &Buffer
);
239 // Creates a NULL import descriptor. This is a small object file whcih
240 // contains a NULL import descriptor. It is used to terminate the imports
241 // from a specific DLL.
242 NewArchiveMember
createNullImportDescriptor(std::vector
<uint8_t> &Buffer
);
244 // Create a NULL Thunk Entry. This is a small object file which contains a
245 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
246 // is used to terminate the IAT and ILT.
247 NewArchiveMember
createNullThunk(std::vector
<uint8_t> &Buffer
);
249 // Create a short import file which is described in PE/COFF spec 7. Import
251 NewArchiveMember
createShortImport(StringRef Sym
, uint16_t Ordinal
,
252 ImportType Type
, ImportNameType NameType
,
253 StringRef ExportName
,
254 MachineTypes Machine
);
256 // Create a weak external file which is described in PE/COFF Aux Format 3.
257 NewArchiveMember
createWeakExternal(StringRef Sym
, StringRef Weak
, bool Imp
,
258 MachineTypes Machine
);
260 bool is64Bit() const { return COFF::is64Bit(NativeMachine
); }
265 ObjectFactory::createImportDescriptor(std::vector
<uint8_t> &Buffer
) {
266 const uint32_t NumberOfSections
= 2;
267 const uint32_t NumberOfSymbols
= 7;
268 const uint32_t NumberOfRelocations
= 3;
271 coff_file_header Header
{
273 u16(NumberOfSections
),
275 u32(sizeof(Header
) + (NumberOfSections
* sizeof(coff_section
)) +
277 sizeof(coff_import_directory_table_entry
) +
278 NumberOfRelocations
* sizeof(coff_relocation
) +
280 (ImportName
.size() + 1)),
281 u32(NumberOfSymbols
),
283 u16(is64Bit() ? C_Invalid
: IMAGE_FILE_32BIT_MACHINE
),
285 append(Buffer
, Header
);
287 // Section Header Table
288 const coff_section SectionTable
[NumberOfSections
] = {
289 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
292 u32(sizeof(coff_import_directory_table_entry
)),
293 u32(sizeof(coff_file_header
) + NumberOfSections
* sizeof(coff_section
)),
294 u32(sizeof(coff_file_header
) + NumberOfSections
* sizeof(coff_section
) +
295 sizeof(coff_import_directory_table_entry
)),
297 u16(NumberOfRelocations
),
299 u32(IMAGE_SCN_ALIGN_4BYTES
| IMAGE_SCN_CNT_INITIALIZED_DATA
|
300 IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)},
301 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
304 u32(ImportName
.size() + 1),
305 u32(sizeof(coff_file_header
) + NumberOfSections
* sizeof(coff_section
) +
306 sizeof(coff_import_directory_table_entry
) +
307 NumberOfRelocations
* sizeof(coff_relocation
)),
312 u32(IMAGE_SCN_ALIGN_2BYTES
| IMAGE_SCN_CNT_INITIALIZED_DATA
|
313 IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)},
315 append(Buffer
, SectionTable
);
318 const coff_import_directory_table_entry ImportDescriptor
{
319 u32(0), u32(0), u32(0), u32(0), u32(0),
321 append(Buffer
, ImportDescriptor
);
323 const coff_relocation RelocationTable
[NumberOfRelocations
] = {
324 {u32(offsetof(coff_import_directory_table_entry
, NameRVA
)), u32(2),
325 u16(getImgRelRelocation(NativeMachine
))},
326 {u32(offsetof(coff_import_directory_table_entry
, ImportLookupTableRVA
)),
327 u32(3), u16(getImgRelRelocation(NativeMachine
))},
328 {u32(offsetof(coff_import_directory_table_entry
, ImportAddressTableRVA
)),
329 u32(4), u16(getImgRelRelocation(NativeMachine
))},
331 append(Buffer
, RelocationTable
);
334 auto S
= Buffer
.size();
335 Buffer
.resize(S
+ ImportName
.size() + 1);
336 memcpy(&Buffer
[S
], ImportName
.data(), ImportName
.size());
337 Buffer
[S
+ ImportName
.size()] = '\0';
340 coff_symbol16 SymbolTable
[NumberOfSymbols
] = {
341 {{{0, 0, 0, 0, 0, 0, 0, 0}},
345 IMAGE_SYM_CLASS_EXTERNAL
,
347 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
351 IMAGE_SYM_CLASS_SECTION
,
353 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
357 IMAGE_SYM_CLASS_STATIC
,
359 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
363 IMAGE_SYM_CLASS_SECTION
,
365 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
369 IMAGE_SYM_CLASS_SECTION
,
371 {{{0, 0, 0, 0, 0, 0, 0, 0}},
375 IMAGE_SYM_CLASS_EXTERNAL
,
377 {{{0, 0, 0, 0, 0, 0, 0, 0}},
381 IMAGE_SYM_CLASS_EXTERNAL
,
384 // TODO: Name.Offset.Offset here and in the all similar places below
385 // suggests a names refactoring. Maybe StringTableOffset.Value?
386 SymbolTable
[0].Name
.Offset
.Offset
=
388 SymbolTable
[5].Name
.Offset
.Offset
=
389 sizeof(uint32_t) + ImportDescriptorSymbolName
.length() + 1;
390 SymbolTable
[6].Name
.Offset
.Offset
=
391 sizeof(uint32_t) + ImportDescriptorSymbolName
.length() + 1 +
392 NullImportDescriptorSymbolName
.length() + 1;
393 append(Buffer
, SymbolTable
);
396 writeStringTable(Buffer
,
397 {ImportDescriptorSymbolName
, NullImportDescriptorSymbolName
,
398 NullThunkSymbolName
});
400 StringRef F
{reinterpret_cast<const char *>(Buffer
.data()), Buffer
.size()};
401 return {MemoryBufferRef(F
, ImportName
)};
405 ObjectFactory::createNullImportDescriptor(std::vector
<uint8_t> &Buffer
) {
406 const uint32_t NumberOfSections
= 1;
407 const uint32_t NumberOfSymbols
= 1;
410 coff_file_header Header
{
412 u16(NumberOfSections
),
414 u32(sizeof(Header
) + (NumberOfSections
* sizeof(coff_section
)) +
416 sizeof(coff_import_directory_table_entry
)),
417 u32(NumberOfSymbols
),
419 u16(is64Bit() ? C_Invalid
: IMAGE_FILE_32BIT_MACHINE
),
421 append(Buffer
, Header
);
423 // Section Header Table
424 const coff_section SectionTable
[NumberOfSections
] = {
425 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
428 u32(sizeof(coff_import_directory_table_entry
)),
429 u32(sizeof(coff_file_header
) +
430 (NumberOfSections
* sizeof(coff_section
))),
435 u32(IMAGE_SCN_ALIGN_4BYTES
| IMAGE_SCN_CNT_INITIALIZED_DATA
|
436 IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_WRITE
)},
438 append(Buffer
, SectionTable
);
441 const coff_import_directory_table_entry ImportDescriptor
{
442 u32(0), u32(0), u32(0), u32(0), u32(0),
444 append(Buffer
, ImportDescriptor
);
447 coff_symbol16 SymbolTable
[NumberOfSymbols
] = {
448 {{{0, 0, 0, 0, 0, 0, 0, 0}},
452 IMAGE_SYM_CLASS_EXTERNAL
,
455 SymbolTable
[0].Name
.Offset
.Offset
= sizeof(uint32_t);
456 append(Buffer
, SymbolTable
);
459 writeStringTable(Buffer
, {NullImportDescriptorSymbolName
});
461 StringRef F
{reinterpret_cast<const char *>(Buffer
.data()), Buffer
.size()};
462 return {MemoryBufferRef(F
, ImportName
)};
465 NewArchiveMember
ObjectFactory::createNullThunk(std::vector
<uint8_t> &Buffer
) {
466 const uint32_t NumberOfSections
= 2;
467 const uint32_t NumberOfSymbols
= 1;
468 uint32_t VASize
= is64Bit() ? 8 : 4;
471 coff_file_header Header
{
473 u16(NumberOfSections
),
475 u32(sizeof(Header
) + (NumberOfSections
* sizeof(coff_section
)) +
480 u32(NumberOfSymbols
),
482 u16(is64Bit() ? C_Invalid
: IMAGE_FILE_32BIT_MACHINE
),
484 append(Buffer
, Header
);
486 // Section Header Table
487 const coff_section SectionTable
[NumberOfSections
] = {
488 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
492 u32(sizeof(coff_file_header
) + NumberOfSections
* sizeof(coff_section
)),
497 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES
: IMAGE_SCN_ALIGN_4BYTES
) |
498 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
|
499 IMAGE_SCN_MEM_WRITE
)},
500 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
504 u32(sizeof(coff_file_header
) + NumberOfSections
* sizeof(coff_section
) +
510 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES
: IMAGE_SCN_ALIGN_4BYTES
) |
511 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
|
512 IMAGE_SCN_MEM_WRITE
)},
514 append(Buffer
, SectionTable
);
517 append(Buffer
, u32(0));
519 append(Buffer
, u32(0));
522 append(Buffer
, u32(0));
524 append(Buffer
, u32(0));
527 coff_symbol16 SymbolTable
[NumberOfSymbols
] = {
528 {{{0, 0, 0, 0, 0, 0, 0, 0}},
532 IMAGE_SYM_CLASS_EXTERNAL
,
535 SymbolTable
[0].Name
.Offset
.Offset
= sizeof(uint32_t);
536 append(Buffer
, SymbolTable
);
539 writeStringTable(Buffer
, {NullThunkSymbolName
});
541 StringRef F
{reinterpret_cast<const char *>(Buffer
.data()), Buffer
.size()};
542 return {MemoryBufferRef
{F
, ImportName
}};
546 ObjectFactory::createShortImport(StringRef Sym
, uint16_t Ordinal
,
547 ImportType ImportType
, ImportNameType NameType
,
548 StringRef ExportName
, MachineTypes Machine
) {
549 size_t ImpSize
= ImportName
.size() + Sym
.size() + 2; // +2 for NULs
550 if (!ExportName
.empty())
551 ImpSize
+= ExportName
.size() + 1;
552 size_t Size
= sizeof(coff_import_header
) + ImpSize
;
553 char *Buf
= Alloc
.Allocate
<char>(Size
);
554 memset(Buf
, 0, Size
);
557 // Write short import library.
558 auto *Imp
= reinterpret_cast<coff_import_header
*>(P
);
561 Imp
->Machine
= Machine
;
562 Imp
->SizeOfData
= ImpSize
;
564 Imp
->OrdinalHint
= Ordinal
;
565 Imp
->TypeInfo
= (NameType
<< 2) | ImportType
;
567 // Write symbol name and DLL name.
568 memcpy(P
, Sym
.data(), Sym
.size());
570 memcpy(P
, ImportName
.data(), ImportName
.size());
571 if (!ExportName
.empty()) {
572 P
+= ImportName
.size() + 1;
573 memcpy(P
, ExportName
.data(), ExportName
.size());
576 return {MemoryBufferRef(StringRef(Buf
, Size
), ImportName
)};
579 NewArchiveMember
ObjectFactory::createWeakExternal(StringRef Sym
,
580 StringRef Weak
, bool Imp
,
581 MachineTypes Machine
) {
582 std::vector
<uint8_t> Buffer
;
583 const uint32_t NumberOfSections
= 1;
584 const uint32_t NumberOfSymbols
= 5;
587 coff_file_header Header
{
589 u16(NumberOfSections
),
591 u32(sizeof(Header
) + (NumberOfSections
* sizeof(coff_section
))),
592 u32(NumberOfSymbols
),
596 append(Buffer
, Header
);
598 // Section Header Table
599 const coff_section SectionTable
[NumberOfSections
] = {
600 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
609 u32(IMAGE_SCN_LNK_INFO
| IMAGE_SCN_LNK_REMOVE
)}};
610 append(Buffer
, SectionTable
);
613 coff_symbol16 SymbolTable
[NumberOfSymbols
] = {
614 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
618 IMAGE_SYM_CLASS_STATIC
,
620 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
624 IMAGE_SYM_CLASS_STATIC
,
626 {{{0, 0, 0, 0, 0, 0, 0, 0}},
630 IMAGE_SYM_CLASS_EXTERNAL
,
632 {{{0, 0, 0, 0, 0, 0, 0, 0}},
636 IMAGE_SYM_CLASS_WEAK_EXTERNAL
,
638 {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS
, 0, 0, 0}},
642 IMAGE_SYM_CLASS_NULL
,
645 SymbolTable
[2].Name
.Offset
.Offset
= sizeof(uint32_t);
647 //__imp_ String Table
648 StringRef Prefix
= Imp
? "__imp_" : "";
649 SymbolTable
[3].Name
.Offset
.Offset
=
650 sizeof(uint32_t) + Sym
.size() + Prefix
.size() + 1;
651 append(Buffer
, SymbolTable
);
652 writeStringTable(Buffer
, {(Prefix
+ Sym
).str(),
653 (Prefix
+ Weak
).str()});
655 // Copied here so we can still use writeStringTable
656 char *Buf
= Alloc
.Allocate
<char>(Buffer
.size());
657 memcpy(Buf
, Buffer
.data(), Buffer
.size());
658 return {MemoryBufferRef(StringRef(Buf
, Buffer
.size()), ImportName
)};
661 Error
writeImportLibrary(StringRef ImportName
, StringRef Path
,
662 ArrayRef
<COFFShortExport
> Exports
,
663 MachineTypes Machine
, bool MinGW
,
664 ArrayRef
<COFFShortExport
> NativeExports
) {
666 MachineTypes NativeMachine
= Machine
;
667 if (isArm64EC(Machine
)) {
668 NativeMachine
= IMAGE_FILE_MACHINE_ARM64
;
669 Machine
= IMAGE_FILE_MACHINE_ARM64EC
;
672 std::vector
<NewArchiveMember
> Members
;
673 ObjectFactory
OF(llvm::sys::path::filename(ImportName
), NativeMachine
);
675 std::vector
<uint8_t> ImportDescriptor
;
676 Members
.push_back(OF
.createImportDescriptor(ImportDescriptor
));
678 std::vector
<uint8_t> NullImportDescriptor
;
679 Members
.push_back(OF
.createNullImportDescriptor(NullImportDescriptor
));
681 std::vector
<uint8_t> NullThunk
;
682 Members
.push_back(OF
.createNullThunk(NullThunk
));
684 auto addExports
= [&](ArrayRef
<COFFShortExport
> Exp
,
685 MachineTypes M
) -> Error
{
686 StringMap
<std::string
> RegularImports
;
690 const COFFShortExport
*Export
;
692 SmallVector
<Deferred
, 0> Renames
;
693 for (const COFFShortExport
&E
: Exp
) {
697 ImportType ImportType
= IMPORT_CODE
;
699 ImportType
= IMPORT_DATA
;
701 ImportType
= IMPORT_CONST
;
703 StringRef SymbolName
= E
.SymbolName
.empty() ? E
.Name
: E
.SymbolName
;
706 if (E
.ExtName
.empty()) {
707 Name
= std::string(SymbolName
);
709 Expected
<std::string
> ReplacedName
=
710 object::replace(SymbolName
, E
.Name
, E
.ExtName
);
712 return ReplacedName
.takeError();
713 Name
.swap(*ReplacedName
);
716 ImportNameType NameType
;
717 std::string ExportName
;
719 NameType
= IMPORT_ORDINAL
;
720 } else if (!E
.ExportAs
.empty()) {
721 NameType
= IMPORT_NAME_EXPORTAS
;
722 ExportName
= E
.ExportAs
;
723 } else if (!E
.ImportName
.empty()) {
724 // If we need to import from a specific ImportName, we may need to use
725 // a weak alias (which needs another import to point at). But if we can
726 // express ImportName based on the symbol name and a specific NameType,
727 // prefer that over an alias.
728 if (Machine
== IMAGE_FILE_MACHINE_I386
&&
729 applyNameType(IMPORT_NAME_UNDECORATE
, Name
) == E
.ImportName
)
730 NameType
= IMPORT_NAME_UNDECORATE
;
731 else if (Machine
== IMAGE_FILE_MACHINE_I386
&&
732 applyNameType(IMPORT_NAME_NOPREFIX
, Name
) == E
.ImportName
)
733 NameType
= IMPORT_NAME_NOPREFIX
;
734 else if (isArm64EC(M
)) {
735 NameType
= IMPORT_NAME_EXPORTAS
;
736 ExportName
= E
.ImportName
;
737 } else if (Name
== E
.ImportName
)
738 NameType
= IMPORT_NAME
;
742 D
.ImpType
= ImportType
;
744 Renames
.push_back(D
);
748 NameType
= getNameType(SymbolName
, E
.Name
, M
, MinGW
);
751 // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols.
752 if (ImportType
== IMPORT_CODE
&& isArm64EC(M
)) {
753 if (std::optional
<std::string
> MangledName
=
754 getArm64ECMangledFunctionName(Name
)) {
755 if (!E
.Noname
&& ExportName
.empty()) {
756 NameType
= IMPORT_NAME_EXPORTAS
;
757 ExportName
.swap(Name
);
759 Name
= std::move(*MangledName
);
760 } else if (!E
.Noname
&& ExportName
.empty()) {
761 std::optional
<std::string
> DemangledName
=
762 getArm64ECDemangledFunctionName(Name
);
764 return make_error
<StringError
>(
765 StringRef(Twine("Invalid ARM64EC function name '" + Name
+ "'")
767 object_error::parse_failed
);
768 NameType
= IMPORT_NAME_EXPORTAS
;
769 ExportName
= std::move(*DemangledName
);
773 RegularImports
[applyNameType(NameType
, Name
)] = Name
;
774 Members
.push_back(OF
.createShortImport(Name
, E
.Ordinal
, ImportType
,
775 NameType
, ExportName
, M
));
777 for (const auto &D
: Renames
) {
778 auto It
= RegularImports
.find(D
.Export
->ImportName
);
779 if (It
!= RegularImports
.end()) {
780 // We have a regular import entry for a symbol with the name we
781 // want to reference; produce an alias pointing at that.
782 StringRef Symbol
= It
->second
;
783 if (D
.ImpType
== IMPORT_CODE
)
784 Members
.push_back(OF
.createWeakExternal(Symbol
, D
.Name
, false, M
));
785 Members
.push_back(OF
.createWeakExternal(Symbol
, D
.Name
, true, M
));
787 Members
.push_back(OF
.createShortImport(D
.Name
, D
.Export
->Ordinal
,
788 D
.ImpType
, IMPORT_NAME_EXPORTAS
,
789 D
.Export
->ImportName
, M
));
792 return Error::success();
795 if (Error e
= addExports(Exports
, Machine
))
797 if (Error e
= addExports(NativeExports
, NativeMachine
))
800 return writeArchive(Path
, Members
, SymtabWritingMode::NormalSymtab
,
801 object::Archive::K_COFF
,
802 /*Deterministic*/ true, /*Thin*/ false,
803 /*OldArchiveBuf*/ nullptr, isArm64EC(Machine
));
806 } // namespace object