brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.1 KiB · 55c825d Raw
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