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