1 //===- MinGW.cpp ----------------------------------------------------------===// 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 #include "MinGW.h" 10 #include "COFFLinkerContext.h" 11 #include "Driver.h" 12 #include "InputFiles.h" 13 #include "SymbolTable.h" 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/ADT/DenseSet.h" 16 #include "llvm/Object/COFF.h" 17 #include "llvm/Support/Parallel.h" 18 #include "llvm/Support/Path.h" 19 #include "llvm/Support/TimeProfiler.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 using namespace llvm; 23 using namespace llvm::COFF; 24 using namespace lld; 25 using namespace lld::coff; 26 27 AutoExporter::AutoExporter( 28 COFFLinkerContext &ctx, 29 const llvm::DenseSet<StringRef> &manualExcludeSymbols) 30 : manualExcludeSymbols(manualExcludeSymbols), ctx(ctx) { 31 excludeLibs = { 32 "libgcc", 33 "libgcc_s", 34 "libstdc++", 35 "libmingw32", 36 "libmingwex", 37 "libg2c", 38 "libsupc++", 39 "libobjc", 40 "libgcj", 41 "libclang_rt.builtins", 42 "libclang_rt.builtins-aarch64", 43 "libclang_rt.builtins-arm", 44 "libclang_rt.builtins-i386", 45 "libclang_rt.builtins-x86_64", 46 "libclang_rt.profile", 47 "libclang_rt.profile-aarch64", 48 "libclang_rt.profile-arm", 49 "libclang_rt.profile-i386", 50 "libclang_rt.profile-x86_64", 51 "libc++", 52 "libc++abi", 53 "libFortran_main", 54 "libFortranRuntime", 55 "libFortranDecimal", 56 "libunwind", 57 "libmsvcrt", 58 "libucrtbase", 59 }; 60 61 excludeObjects = { 62 "crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o", 63 "dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o", 64 }; 65 66 excludeSymbolPrefixes = { 67 // Import symbols 68 "__imp_", 69 "__IMPORT_DESCRIPTOR_", 70 // Extra import symbols from GNU import libraries 71 "__nm_", 72 // C++ symbols 73 "__rtti_", 74 "__builtin_", 75 // Artificial symbols such as .refptr 76 ".", 77 // profile generate symbols 78 "__profc_", 79 "__profd_", 80 "__profvp_", 81 }; 82 83 excludeSymbolSuffixes = { 84 "_iname", 85 "_NULL_THUNK_DATA", 86 }; 87 88 if (ctx.config.machine == I386) { 89 excludeSymbols = { 90 "__NULL_IMPORT_DESCRIPTOR", 91 "__pei386_runtime_relocator", 92 "_do_pseudo_reloc", 93 "_impure_ptr", 94 "__impure_ptr", 95 "__fmode", 96 "_environ", 97 "___dso_handle", 98 // These are the MinGW names that differ from the standard 99 // ones (lacking an extra underscore). 100 "_DllMain@12", 101 "_DllEntryPoint@12", 102 "_DllMainCRTStartup@12", 103 }; 104 excludeSymbolPrefixes.insert("__head_"); 105 } else { 106 excludeSymbols = { 107 "__NULL_IMPORT_DESCRIPTOR", 108 "_pei386_runtime_relocator", 109 "do_pseudo_reloc", 110 "impure_ptr", 111 "_impure_ptr", 112 "_fmode", 113 "environ", 114 "__dso_handle", 115 // These are the MinGW names that differ from the standard 116 // ones (lacking an extra underscore). 117 "DllMain", 118 "DllEntryPoint", 119 "DllMainCRTStartup", 120 }; 121 excludeSymbolPrefixes.insert("_head_"); 122 } 123 } 124 125 void AutoExporter::addWholeArchive(StringRef path) { 126 StringRef libName = sys::path::filename(path); 127 // Drop the file extension, to match the processing below. 128 libName = libName.substr(0, libName.rfind('.')); 129 excludeLibs.erase(libName); 130 } 131 132 void AutoExporter::addExcludedSymbol(StringRef symbol) { 133 excludeSymbols.insert(symbol); 134 } 135 136 bool AutoExporter::shouldExport(Defined *sym) const { 137 if (!sym || !sym->getChunk()) 138 return false; 139 140 // Only allow the symbol kinds that make sense to export; in particular, 141 // disallow import symbols. 142 if (!isa<DefinedRegular>(sym) && !isa<DefinedCommon>(sym)) 143 return false; 144 if (excludeSymbols.count(sym->getName()) || manualExcludeSymbols.count(sym->getName())) 145 return false; 146 147 for (StringRef prefix : excludeSymbolPrefixes.keys()) 148 if (sym->getName().starts_with(prefix)) 149 return false; 150 for (StringRef suffix : excludeSymbolSuffixes.keys()) 151 if (sym->getName().ends_with(suffix)) 152 return false; 153 154 // If a corresponding __imp_ symbol exists and is defined, don't export it. 155 if (ctx.symtab.find(("__imp_" + sym->getName()).str())) 156 return false; 157 158 // Check that file is non-null before dereferencing it, symbols not 159 // originating in regular object files probably shouldn't be exported. 160 if (!sym->getFile()) 161 return false; 162 163 StringRef libName = sys::path::filename(sym->getFile()->parentName); 164 165 // Drop the file extension. 166 libName = libName.substr(0, libName.rfind('.')); 167 if (!libName.empty()) 168 return !excludeLibs.count(libName); 169 170 StringRef fileName = sys::path::filename(sym->getFile()->getName()); 171 return !excludeObjects.count(fileName); 172 } 173 174 void lld::coff::writeDefFile(StringRef name, 175 const std::vector<Export> &exports) { 176 llvm::TimeTraceScope timeScope("Write .def file"); 177 std::error_code ec; 178 raw_fd_ostream os(name, ec, sys::fs::OF_None); 179 if (ec) 180 fatal("cannot open " + name + ": " + ec.message()); 181 182 os << "EXPORTS\n"; 183 for (const Export &e : exports) { 184 os << " " << e.exportName << " " 185 << "@" << e.ordinal; 186 if (auto *def = dyn_cast_or_null<Defined>(e.sym)) { 187 if (def && def->getChunk() && 188 !(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) 189 os << " DATA"; 190 } 191 os << "\n"; 192 } 193 } 194 195 static StringRef mangle(Twine sym, MachineTypes machine) { 196 assert(machine != IMAGE_FILE_MACHINE_UNKNOWN); 197 if (machine == I386) 198 return saver().save("_" + sym); 199 return saver().save(sym); 200 } 201 202 // Handles -wrap option. 203 // 204 // This function instantiates wrapper symbols. At this point, they seem 205 // like they are not being used at all, so we explicitly set some flags so 206 // that LTO won't eliminate them. 207 std::vector<WrappedSymbol> 208 lld::coff::addWrappedSymbols(COFFLinkerContext &ctx, opt::InputArgList &args) { 209 std::vector<WrappedSymbol> v; 210 DenseSet<StringRef> seen; 211 212 for (auto *arg : args.filtered(OPT_wrap)) { 213 StringRef name = arg->getValue(); 214 if (!seen.insert(name).second) 215 continue; 216 217 Symbol *sym = ctx.symtab.findUnderscore(name); 218 if (!sym) 219 continue; 220 221 Symbol *real = 222 ctx.symtab.addUndefined(mangle("__real_" + name, ctx.config.machine)); 223 Symbol *wrap = 224 ctx.symtab.addUndefined(mangle("__wrap_" + name, ctx.config.machine)); 225 v.push_back({sym, real, wrap}); 226 227 // These symbols may seem undefined initially, but don't bail out 228 // at symtab.reportUnresolvable() due to them, but let wrapSymbols 229 // below sort things out before checking finally with 230 // symtab.resolveRemainingUndefines(). 231 sym->deferUndefined = true; 232 real->deferUndefined = true; 233 // We want to tell LTO not to inline symbols to be overwritten 234 // because LTO doesn't know the final symbol contents after renaming. 235 real->canInline = false; 236 sym->canInline = false; 237 238 // Tell LTO not to eliminate these symbols. 239 sym->isUsedInRegularObj = true; 240 if (!isa<Undefined>(wrap)) 241 wrap->isUsedInRegularObj = true; 242 } 243 return v; 244 } 245 246 // Do renaming for -wrap by updating pointers to symbols. 247 // 248 // When this function is executed, only InputFiles and symbol table 249 // contain pointers to symbol objects. We visit them to replace pointers, 250 // so that wrapped symbols are swapped as instructed by the command line. 251 void lld::coff::wrapSymbols(COFFLinkerContext &ctx, 252 ArrayRef<WrappedSymbol> wrapped) { 253 DenseMap<Symbol *, Symbol *> map; 254 for (const WrappedSymbol &w : wrapped) { 255 map[w.sym] = w.wrap; 256 map[w.real] = w.sym; 257 if (Defined *d = dyn_cast<Defined>(w.wrap)) { 258 Symbol *imp = ctx.symtab.find(("__imp_" + w.sym->getName()).str()); 259 // Create a new defined local import for the wrap symbol. If 260 // no imp prefixed symbol existed, there's no need for it. 261 // (We can't easily distinguish whether any object file actually 262 // referenced it or not, though.) 263 if (imp) { 264 DefinedLocalImport *wrapimp = make<DefinedLocalImport>( 265 ctx, saver().save("__imp_" + w.wrap->getName()), d); 266 ctx.symtab.localImportChunks.push_back(wrapimp->getChunk()); 267 map[imp] = wrapimp; 268 } 269 } 270 } 271 272 // Update pointers in input files. 273 parallelForEach(ctx.objFileInstances, [&](ObjFile *file) { 274 MutableArrayRef<Symbol *> syms = file->getMutableSymbols(); 275 for (auto &sym : syms) 276 if (Symbol *s = map.lookup(sym)) 277 sym = s; 278 }); 279 } 280