1 | //===- COFFImportFile.h - COFF short import file implementation -*- 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 | // COFF short import file is a special kind of file which contains |
10 | // only symbol names for DLL-exported symbols. This class implements |
11 | // exporting of Symbols to create libraries and a SymbolicFile |
12 | // interface for the file type. |
13 | // |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | #ifndef LLVM_OBJECT_COFFIMPORTFILE_H |
17 | #define LLVM_OBJECT_COFFIMPORTFILE_H |
18 | |
19 | #include "llvm/ADT/ArrayRef.h" |
20 | #include "llvm/IR/Mangler.h" |
21 | #include "llvm/Object/COFF.h" |
22 | #include "llvm/Object/ObjectFile.h" |
23 | #include "llvm/Object/SymbolicFile.h" |
24 | #include "llvm/Support/MemoryBufferRef.h" |
25 | #include "llvm/Support/raw_ostream.h" |
26 | |
27 | namespace llvm { |
28 | namespace object { |
29 | |
30 | constexpr std::string_view ImportDescriptorPrefix = "__IMPORT_DESCRIPTOR_" ; |
31 | constexpr std::string_view NullImportDescriptorSymbolName = |
32 | "__NULL_IMPORT_DESCRIPTOR" ; |
33 | constexpr std::string_view NullThunkDataPrefix = "\x7f" ; |
34 | constexpr std::string_view NullThunkDataSuffix = "_NULL_THUNK_DATA" ; |
35 | |
36 | class COFFImportFile : public SymbolicFile { |
37 | private: |
38 | enum SymbolIndex { ImpSymbol, ThunkSymbol, ECAuxSymbol, ECThunkSymbol }; |
39 | |
40 | public: |
41 | COFFImportFile(MemoryBufferRef Source) |
42 | : SymbolicFile(ID_COFFImportFile, Source) {} |
43 | |
44 | static bool classof(Binary const *V) { return V->isCOFFImportFile(); } |
45 | |
46 | void moveSymbolNext(DataRefImpl &Symb) const override { ++Symb.p; } |
47 | |
48 | Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override; |
49 | |
50 | Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override { |
51 | return SymbolRef::SF_Global; |
52 | } |
53 | |
54 | basic_symbol_iterator symbol_begin() const override { |
55 | return BasicSymbolRef(DataRefImpl(), this); |
56 | } |
57 | |
58 | basic_symbol_iterator symbol_end() const override { |
59 | DataRefImpl Symb; |
60 | if (isData()) |
61 | Symb.p = ImpSymbol + 1; |
62 | else if (COFF::isArm64EC(Machine: getMachine())) |
63 | Symb.p = ECThunkSymbol + 1; |
64 | else |
65 | Symb.p = ThunkSymbol + 1; |
66 | return BasicSymbolRef(Symb, this); |
67 | } |
68 | |
69 | bool is64Bit() const override { return false; } |
70 | |
71 | const coff_import_header *() const { |
72 | return reinterpret_cast<const object::coff_import_header *>( |
73 | Data.getBufferStart()); |
74 | } |
75 | |
76 | uint16_t getMachine() const { return getCOFFImportHeader()->Machine; } |
77 | |
78 | StringRef getFileFormatName() const; |
79 | StringRef getExportName() const; |
80 | |
81 | private: |
82 | bool isData() const { |
83 | return getCOFFImportHeader()->getType() == COFF::IMPORT_DATA; |
84 | } |
85 | }; |
86 | |
87 | struct COFFShortExport { |
88 | /// The name of the export as specified in the .def file or on the command |
89 | /// line, i.e. "foo" in "/EXPORT:foo", and "bar" in "/EXPORT:foo=bar". This |
90 | /// may lack mangling, such as underscore prefixing and stdcall suffixing. |
91 | std::string Name; |
92 | |
93 | /// The external, exported name. Only non-empty when export renaming is in |
94 | /// effect, i.e. "foo" in "/EXPORT:foo=bar". |
95 | std::string ExtName; |
96 | |
97 | /// The real, mangled symbol name from the object file. Given |
98 | /// "/export:foo=bar", this could be "_bar@8" if bar is stdcall. |
99 | std::string SymbolName; |
100 | |
101 | /// Creates an import library entry that imports from a DLL export with a |
102 | /// different name. This is the name of the DLL export that should be |
103 | /// referenced when linking against this import library entry. In a .def |
104 | /// file, this is "baz" in "EXPORTS\nfoo = bar == baz". |
105 | std::string ImportName; |
106 | |
107 | /// Specifies EXPORTAS name. In a .def file, this is "bar" in |
108 | /// "EXPORTS\nfoo EXPORTAS bar". |
109 | std::string ExportAs; |
110 | |
111 | uint16_t Ordinal = 0; |
112 | bool Noname = false; |
113 | bool Data = false; |
114 | bool Private = false; |
115 | bool Constant = false; |
116 | |
117 | friend bool operator==(const COFFShortExport &L, const COFFShortExport &R) { |
118 | return L.Name == R.Name && L.ExtName == R.ExtName && |
119 | L.Ordinal == R.Ordinal && L.Noname == R.Noname && |
120 | L.Data == R.Data && L.Private == R.Private; |
121 | } |
122 | |
123 | friend bool operator!=(const COFFShortExport &L, const COFFShortExport &R) { |
124 | return !(L == R); |
125 | } |
126 | }; |
127 | |
128 | /// Writes a COFF import library containing entries described by the Exports |
129 | /// array. |
130 | /// |
131 | /// For hybrid targets such as ARM64EC, additional native entry points can be |
132 | /// exposed using the NativeExports parameter. When NativeExports is used, the |
133 | /// output import library will expose these native ARM64 imports alongside the |
134 | /// entries described in the Exports array. Such a library can be used for |
135 | /// linking both ARM64EC and pure ARM64 objects, and the linker will pick only |
136 | /// the exports relevant to the target platform. For non-hybrid targets, |
137 | /// the NativeExports parameter should not be used. |
138 | Error writeImportLibrary( |
139 | StringRef ImportName, StringRef Path, ArrayRef<COFFShortExport> Exports, |
140 | COFF::MachineTypes Machine, bool MinGW, |
141 | ArrayRef<COFFShortExport> NativeExports = std::nullopt); |
142 | |
143 | } // namespace object |
144 | } // namespace llvm |
145 | |
146 | #endif |
147 | |