350 lines · cpp
1//===-- Mangler.cpp - Self-contained c/asm llvm name mangler --------------===//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// Unified name mangler for assembly backends.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/IR/Mangler.h"14#include "llvm/ADT/SmallString.h"15#include "llvm/ADT/StringExtras.h"16#include "llvm/ADT/Twine.h"17#include "llvm/Demangle/Demangle.h"18#include "llvm/IR/DataLayout.h"19#include "llvm/IR/DerivedTypes.h"20#include "llvm/IR/Function.h"21#include "llvm/IR/Module.h"22#include "llvm/Support/raw_ostream.h"23#include "llvm/TargetParser/Triple.h"24 25using namespace llvm;26 27namespace {28enum ManglerPrefixTy {29 Default, ///< Emit default string before each symbol.30 Private, ///< Emit "private" prefix before each symbol.31 LinkerPrivate ///< Emit "linker private" prefix before each symbol.32};33}34 35static void getNameWithPrefixImpl(raw_ostream &OS, const Twine &GVName,36 ManglerPrefixTy PrefixTy,37 const DataLayout &DL, char Prefix) {38 SmallString<256> TmpData;39 StringRef Name = GVName.toStringRef(TmpData);40 assert(!Name.empty() && "getNameWithPrefix requires non-empty name");41 42 // No need to do anything special if the global has the special "do not43 // mangle" flag in the name.44 if (Name[0] == '\1') {45 OS << Name.substr(1);46 return;47 }48 49 if (DL.doNotMangleLeadingQuestionMark() && Name[0] == '?')50 Prefix = '\0';51 52 if (PrefixTy == Private)53 OS << DL.getPrivateGlobalPrefix();54 else if (PrefixTy == LinkerPrivate)55 OS << DL.getLinkerPrivateGlobalPrefix();56 57 if (Prefix != '\0')58 OS << Prefix;59 60 // If this is a simple string that doesn't need escaping, just append it.61 OS << Name;62}63 64static void getNameWithPrefixImpl(raw_ostream &OS, const Twine &GVName,65 const DataLayout &DL,66 ManglerPrefixTy PrefixTy) {67 char Prefix = DL.getGlobalPrefix();68 return getNameWithPrefixImpl(OS, GVName, PrefixTy, DL, Prefix);69}70 71void Mangler::getNameWithPrefix(raw_ostream &OS, const Twine &GVName,72 const DataLayout &DL) {73 return getNameWithPrefixImpl(OS, GVName, DL, Default);74}75 76void Mangler::getNameWithPrefix(SmallVectorImpl<char> &OutName,77 const Twine &GVName, const DataLayout &DL) {78 raw_svector_ostream OS(OutName);79 char Prefix = DL.getGlobalPrefix();80 return getNameWithPrefixImpl(OS, GVName, Default, DL, Prefix);81}82 83static bool hasByteCountSuffix(CallingConv::ID CC) {84 switch (CC) {85 case CallingConv::X86_FastCall:86 case CallingConv::X86_StdCall:87 case CallingConv::X86_VectorCall:88 return true;89 default:90 return false;91 }92}93 94/// Microsoft fastcall and stdcall functions require a suffix on their name95/// indicating the number of words of arguments they take.96static void addByteCountSuffix(raw_ostream &OS, const Function *F,97 const DataLayout &DL) {98 // Calculate arguments size total.99 unsigned ArgWords = 0;100 101 const unsigned PtrSize = DL.getPointerSize();102 103 for (const Argument &A : F->args()) {104 // For the purposes of the byte count suffix, structs returned by pointer105 // do not count as function arguments.106 if (A.hasStructRetAttr())107 continue;108 109 // 'Dereference' type in case of byval or inalloca parameter attribute.110 uint64_t AllocSize = A.hasPassPointeeByValueCopyAttr() ?111 A.getPassPointeeByValueCopySize(DL) :112 DL.getTypeAllocSize(A.getType());113 114 // Size should be aligned to pointer size.115 ArgWords += alignTo(AllocSize, PtrSize);116 }117 118 OS << '@' << ArgWords;119}120 121void Mangler::getNameWithPrefix(raw_ostream &OS, const GlobalValue *GV,122 bool CannotUsePrivateLabel) const {123 ManglerPrefixTy PrefixTy = Default;124 assert(GV != nullptr && "Invalid Global Value");125 if (GV->hasPrivateLinkage()) {126 if (CannotUsePrivateLabel)127 PrefixTy = LinkerPrivate;128 else129 PrefixTy = Private;130 }131 132 const DataLayout &DL = GV->getDataLayout();133 if (!GV->hasName()) {134 // Get the ID for the global, assigning a new one if we haven't got one135 // already.136 unsigned &ID = AnonGlobalIDs[GV];137 if (ID == 0)138 ID = AnonGlobalIDs.size();139 140 // Must mangle the global into a unique ID.141 getNameWithPrefixImpl(OS, "__unnamed_" + Twine(ID), DL, PrefixTy);142 return;143 }144 145 StringRef Name = GV->getName();146 char Prefix = DL.getGlobalPrefix();147 148 // Mangle functions with Microsoft calling conventions specially. Only do149 // this mangling for x86_64 vectorcall and 32-bit x86.150 const Function *MSFunc = dyn_cast_or_null<Function>(GV->getAliaseeObject());151 152 // Don't add byte count suffixes when '\01' or '?' are in the first153 // character.154 if (Name.starts_with("\01") ||155 (DL.doNotMangleLeadingQuestionMark() && Name.starts_with("?")))156 MSFunc = nullptr;157 158 CallingConv::ID CC =159 MSFunc ? MSFunc->getCallingConv() : (unsigned)CallingConv::C;160 if (!DL.hasMicrosoftFastStdCallMangling() &&161 CC != CallingConv::X86_VectorCall)162 MSFunc = nullptr;163 if (MSFunc) {164 if (CC == CallingConv::X86_FastCall)165 Prefix = '@'; // fastcall functions have an @ prefix instead of _.166 else if (CC == CallingConv::X86_VectorCall)167 Prefix = '\0'; // vectorcall functions have no prefix.168 }169 170 getNameWithPrefixImpl(OS, Name, PrefixTy, DL, Prefix);171 172 if (!MSFunc)173 return;174 175 // If we are supposed to add a microsoft-style suffix for stdcall, fastcall,176 // or vectorcall, add it. These functions have a suffix of @N where N is the177 // cumulative byte size of all of the parameters to the function in decimal.178 if (CC == CallingConv::X86_VectorCall)179 OS << '@'; // vectorcall functions use a double @ suffix.180 FunctionType *FT = MSFunc->getFunctionType();181 if (hasByteCountSuffix(CC) &&182 // "Pure" variadic functions do not receive @0 suffix.183 (!FT->isVarArg() || FT->getNumParams() == 0 ||184 (FT->getNumParams() == 1 && MSFunc->hasStructRetAttr())))185 addByteCountSuffix(OS, MSFunc, DL);186}187 188void Mangler::getNameWithPrefix(SmallVectorImpl<char> &OutName,189 const GlobalValue *GV,190 bool CannotUsePrivateLabel) const {191 raw_svector_ostream OS(OutName);192 getNameWithPrefix(OS, GV, CannotUsePrivateLabel);193}194 195// Check if the name needs quotes to be safe for the linker to interpret.196static bool canBeUnquotedInDirective(char C) {197 return isAlnum(C) || C == '_' || C == '@' || C == '#';198}199 200static bool canBeUnquotedInDirective(StringRef Name) {201 if (Name.empty())202 return false;203 204 // If any of the characters in the string is an unacceptable character, force205 // quotes.206 for (char C : Name) {207 if (!canBeUnquotedInDirective(C))208 return false;209 }210 211 return true;212}213 214void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV,215 const Triple &TT, Mangler &Mangler) {216 if (GV->hasDLLExportStorageClass() && !GV->isDeclaration()) {217 218 if (TT.isWindowsMSVCEnvironment() || TT.isUEFI())219 OS << " /EXPORT:";220 else221 OS << " -export:";222 223 bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName());224 if (NeedQuotes)225 OS << "\"";226 if (TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) {227 std::string Flag;228 raw_string_ostream FlagOS(Flag);229 Mangler.getNameWithPrefix(FlagOS, GV, false);230 FlagOS.flush();231 if (Flag[0] == GV->getDataLayout().getGlobalPrefix())232 OS << Flag.substr(1);233 else234 OS << Flag;235 } else {236 Mangler.getNameWithPrefix(OS, GV, false);237 }238 if (TT.isWindowsArm64EC()) {239 // Use EXPORTAS for mangled ARM64EC symbols.240 // FIXME: During LTO, we're invoked prior to the EC lowering pass,241 // so symbols are not yet mangled. Emitting the unmangled name242 // typically functions correctly; the linker can resolve the export243 // with the demangled alias.244 if (std::optional<std::string> demangledName =245 getArm64ECDemangledFunctionName(GV->getName()))246 OS << ",EXPORTAS," << *demangledName;247 }248 if (NeedQuotes)249 OS << "\"";250 251 if (!GV->getValueType()->isFunctionTy()) {252 if (TT.isWindowsMSVCEnvironment() || TT.isUEFI())253 OS << ",DATA";254 else255 OS << ",data";256 }257 }258 if (GV->hasHiddenVisibility() && !GV->isDeclaration() && TT.isOSCygMing()) {259 260 OS << " -exclude-symbols:";261 262 bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName());263 if (NeedQuotes)264 OS << "\"";265 266 std::string Flag;267 raw_string_ostream FlagOS(Flag);268 Mangler.getNameWithPrefix(FlagOS, GV, false);269 FlagOS.flush();270 if (Flag[0] == GV->getDataLayout().getGlobalPrefix())271 OS << Flag.substr(1);272 else273 OS << Flag;274 275 if (NeedQuotes)276 OS << "\"";277 }278}279 280void llvm::emitLinkerFlagsForUsedCOFF(raw_ostream &OS, const GlobalValue *GV,281 const Triple &T, Mangler &M) {282 if (!T.isWindowsMSVCEnvironment())283 return;284 285 OS << " /INCLUDE:";286 bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName());287 if (NeedQuotes)288 OS << "\"";289 M.getNameWithPrefix(OS, GV, false);290 if (NeedQuotes)291 OS << "\"";292}293 294std::optional<std::string> llvm::getArm64ECMangledFunctionName(StringRef Name) {295 assert(!Name.empty() &&296 "getArm64ECMangledFunctionName requires non-empty name");297 298 if (Name[0] != '?') {299 // For non-C++ symbols, prefix the name with "#" unless it's already300 // mangled.301 if (Name[0] == '#')302 return std::nullopt;303 return std::optional<std::string>(("#" + Name).str());304 }305 306 // If the name contains $$h, then it is already mangled.307 if (Name.contains("$$h"))308 return std::nullopt;309 310 // Handle MD5 mangled names, which use a slightly different rule from311 // other C++ manglings.312 //313 // A non-Arm64EC function:314 //315 // ??@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@316 //317 // An Arm64EC function:318 //319 // ??@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@$$h@320 if (Name.starts_with("??@") && Name.ends_with("@"))321 return (Name + "$$h@").str();322 323 // Ask the demangler where we should insert "$$h".324 auto InsertIdx = getArm64ECInsertionPointInMangledName(Name);325 if (!InsertIdx)326 return std::nullopt;327 328 return std::optional<std::string>(329 (Name.substr(0, *InsertIdx) + "$$h" + Name.substr(*InsertIdx)).str());330}331 332std::optional<std::string>333llvm::getArm64ECDemangledFunctionName(StringRef Name) {334 // For non-C++ names, drop the "#" prefix.335 if (Name[0] == '#')336 return std::optional<std::string>(Name.substr(1));337 if (Name[0] != '?')338 return std::nullopt;339 340 // MD5 mangled name; see comment in getArm64ECMangledFunctionName.341 if (Name.starts_with("??@") && Name.ends_with("@$$h@"))342 return Name.drop_back(4).str();343 344 // Drop the ARM64EC "$$h" tag.345 std::pair<StringRef, StringRef> Pair = Name.split("$$h");346 if (Pair.second.empty())347 return std::nullopt;348 return std::optional<std::string>((Pair.first + Pair.second).str());349}350