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-exception
6//
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(Out&: 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 not
43 // mangle" flag in the name.
44 if (Name[0] == '\1') {
45 OS << Name.substr(Start: 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, PrefixTy: 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, PrefixTy: 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 name
95/// 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 pointer
105 // 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(Ty: A.getType());
113
114 // Size should be aligned to pointer size.
115 ArgWords += alignTo(Value: AllocSize, Align: 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 else
129 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 one
135 // 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, GVName: "__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 do
149 // this mangling for x86_64 vectorcall and 32-bit x86.
150 const Function *MSFunc = dyn_cast_or_null<Function>(Val: GV->getAliaseeObject());
151
152 // Don't add byte count suffixes when '\01' or '?' are in the first
153 // character.
154 if (Name.starts_with(Prefix: "\01") ||
155 (DL.doNotMangleLeadingQuestionMark() && Name.starts_with(Prefix: "?")))
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, GVName: 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 the
177 // 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, F: 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, force
205 // 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 else
221 OS << " -export:";
222
223 bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(Name: 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(OS&: FlagOS, GV, CannotUsePrivateLabel: false);
230 FlagOS.flush();
231 if (Flag[0] == GV->getDataLayout().getGlobalPrefix())
232 OS << Flag.substr(pos: 1);
233 else
234 OS << Flag;
235 } else {
236 Mangler.getNameWithPrefix(OS, GV, CannotUsePrivateLabel: 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 name
242 // typically functions correctly; the linker can resolve the export
243 // with the demangled alias.
244 if (std::optional<std::string> demangledName =
245 getArm64ECDemangledFunctionName(Name: 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 else
255 OS << ",data";
256 }
257 }
258 if (GV->hasHiddenVisibility() && !GV->isDeclaration() && TT.isOSCygMing()) {
259
260 OS << " -exclude-symbols:";
261
262 bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(Name: GV->getName());
263 if (NeedQuotes)
264 OS << "\"";
265
266 std::string Flag;
267 raw_string_ostream FlagOS(Flag);
268 Mangler.getNameWithPrefix(OS&: FlagOS, GV, CannotUsePrivateLabel: false);
269 FlagOS.flush();
270 if (Flag[0] == GV->getDataLayout().getGlobalPrefix())
271 OS << Flag.substr(pos: 1);
272 else
273 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(Name: GV->getName());
287 if (NeedQuotes)
288 OS << "\"";
289 M.getNameWithPrefix(OS, GV, CannotUsePrivateLabel: false);
290 if (NeedQuotes)
291 OS << "\"";
292}
293
294std::optional<std::string> llvm::getArm64ECMangledFunctionName(StringRef Name) {
295 if (Name[0] != '?') {
296 // For non-C++ symbols, prefix the name with "#" unless it's already
297 // mangled.
298 if (Name[0] == '#')
299 return std::nullopt;
300 return std::optional<std::string>(("#" + Name).str());
301 }
302
303 // If the name contains $$h, then it is already mangled.
304 if (Name.contains(Other: "$$h"))
305 return std::nullopt;
306
307 // Ask the demangler where we should insert "$$h".
308 auto InsertIdx = getArm64ECInsertionPointInMangledName(MangledName: Name);
309 if (!InsertIdx)
310 return std::nullopt;
311
312 return std::optional<std::string>(
313 (Name.substr(Start: 0, N: *InsertIdx) + "$$h" + Name.substr(Start: *InsertIdx)).str());
314}
315
316std::optional<std::string>
317llvm::getArm64ECDemangledFunctionName(StringRef Name) {
318 // For non-C++ names, drop the "#" prefix.
319 if (Name[0] == '#')
320 return std::optional<std::string>(Name.substr(Start: 1));
321 if (Name[0] != '?')
322 return std::nullopt;
323
324 // Drop the ARM64EC "$$h" tag.
325 std::pair<StringRef, StringRef> Pair = Name.split(Separator: "$$h");
326 if (Pair.second.empty())
327 return std::nullopt;
328 return std::optional<std::string>((Pair.first + Pair.second).str());
329}
330