aboutsummaryrefslogtreecommitdiffstats
path: root/lib/sanitizer_common/sanitizer_win_defs.h
blob: bfe38a3323674626bb33e48657bf19b744320171 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//===-- sanitizer_win_defs.h ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Common definitions for Windows-specific code.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_WIN_DEFS_H
#define SANITIZER_WIN_DEFS_H

#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS

#ifndef WINAPI
#if defined(_M_IX86) || defined(__i386__)
#define WINAPI __stdcall
#else
#define WINAPI
#endif
#endif

#if defined(_M_IX86) || defined(__i386__)
#define WIN_SYM_PREFIX "_"
#else
#define WIN_SYM_PREFIX
#endif

// For MinGW, the /export: directives contain undecorated symbols, contrary to
// link/lld-link. The GNU linker doesn't support /alternatename and /include
// though, thus lld-link in MinGW mode interprets them in the same way as
// in the default mode.
#ifdef __MINGW32__
#define WIN_EXPORT_PREFIX
#else
#define WIN_EXPORT_PREFIX WIN_SYM_PREFIX
#endif

// Intermediate macro to ensure the parameter is expanded before stringified.
#define STRINGIFY_(A) #A
#define STRINGIFY(A) STRINGIFY_(A)

#if !SANITIZER_GO

// ----------------- A workaround for the absence of weak symbols --------------
// We don't have a direct equivalent of weak symbols when using MSVC, but we can
// use the /alternatename directive to tell the linker to default a specific
// symbol to a specific value.
// Take into account that this is a pragma directive for the linker, so it will
// be ignored by the compiler and the function will be marked as UNDEF in the
// symbol table of the resulting object file. The linker won't find the default
// implementation until it links with that object file.
// So, suppose we provide a default implementation "fundef" for "fun", and this
// is compiled into the object file "test.obj" including the pragma directive.
// If we have some code with references to "fun" and we link that code with
// "test.obj", it will work because the linker always link object files.
// But, if "test.obj" is included in a static library, like "test.lib", then the
// liker will only link to "test.obj" if necessary. If we only included the
// definition of "fun", it won't link to "test.obj" (from test.lib) because
// "fun" appears as UNDEF, so it doesn't resolve the symbol "fun", and will
// result in a link error (the linker doesn't find the pragma directive).
// So, a workaround is to force linkage with the modules that include weak
// definitions, with the following macro: WIN_FORCE_LINK()

#define WIN_WEAK_ALIAS(Name, Default)                                          \
  __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY(Name) "="\
                                             WIN_SYM_PREFIX STRINGIFY(Default)))

#define WIN_FORCE_LINK(Name)                                                   \
  __pragma(comment(linker, "/include:" WIN_SYM_PREFIX STRINGIFY(Name)))

#define WIN_EXPORT(ExportedName, Name)                                         \
  __pragma(comment(linker, "/export:" WIN_EXPORT_PREFIX STRINGIFY(ExportedName)\
                                  "=" WIN_EXPORT_PREFIX STRINGIFY(Name)))

// We cannot define weak functions on Windows, but we can use WIN_WEAK_ALIAS()
// which defines an alias to a default implementation, and only works when
// linking statically.
// So, to define a weak function "fun", we define a default implementation with
// a different name "fun__def" and we create a "weak alias" fun = fun__def.
// Then, users can override it just defining "fun".
// We impose "extern "C"" because otherwise WIN_WEAK_ALIAS() will fail because
// of name mangling.

// Dummy name for default implementation of weak function.
# define WEAK_DEFAULT_NAME(Name) Name##__def
// Name for exported implementation of weak function.
# define WEAK_EXPORT_NAME(Name) Name##__dll

// Use this macro when you need to define and export a weak function from a
// library. For example:
//   WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
# define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...)                            \
  WIN_WEAK_ALIAS(Name, WEAK_DEFAULT_NAME(Name))                                \
  WIN_EXPORT(WEAK_EXPORT_NAME(Name), Name)                                     \
  extern "C" ReturnType Name(__VA_ARGS__);                                     \
  extern "C" ReturnType WEAK_DEFAULT_NAME(Name)(__VA_ARGS__)

// Use this macro when you need to import a weak function from a library. It
// defines a weak alias to the imported function from the dll. For example:
//   WIN_WEAK_IMPORT_DEF(compare)
# define WIN_WEAK_IMPORT_DEF(Name)                                             \
  WIN_WEAK_ALIAS(Name, WEAK_EXPORT_NAME(Name))

// So, for Windows we provide something similar to weak symbols in Linux, with
// some differences:
// + A default implementation must always be provided.
//
// + When linking statically it works quite similarly. For example:
//
//   // libExample.cc
//   WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
//
//   // client.cc
//   // We can use the default implementation from the library:
//   compare(1, 2);
//   // Or we can override it:
//   extern "C" bool compare (int a, int b) { return a >= b; }
//
//  And it will work fine. If we don't override the function, we need to ensure
//  that the linker includes the object file with the default implementation.
//  We can do so with the linker option "-wholearchive:".
//
// + When linking dynamically with a library (dll), weak functions are exported
//  with "__dll" suffix. Clients can use the macro WIN_WEAK_IMPORT_DEF(fun)
//  which defines a "weak alias" fun = fun__dll.
//
//   // libExample.cc
//   WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
//
//   // client.cc
//   WIN_WEAK_IMPORT_DEF(compare)
//   // We can use the default implementation from the library:
//   compare(1, 2);
//   // Or we can override it:
//   extern "C" bool compare (int a, int b) { return a >= b; }
//
//  But if we override the function, the dlls don't have access to it (which
//  is different in linux). If that is desired, the strong definition must be
//  exported and interception can be used from the rest of the dlls.
//
//   // libExample.cc
//   WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
//   // When initialized, check if the main executable defined "compare".
//   int libExample_init() {
//     uptr fnptr = __interception::InternalGetProcAddress(
//         (void *)GetModuleHandleA(0), "compare");
//     if (fnptr && !__interception::OverrideFunction((uptr)compare, fnptr, 0))
//       abort();
//     return 0;
//   }
//
//   // client.cc
//   WIN_WEAK_IMPORT_DEF(compare)
//   // We override and export compare:
//   extern "C" __declspec(dllexport) bool compare (int a, int b) {
//     return a >= b;
//   }
//

#else // SANITIZER_GO

// Go neither needs nor wants weak references.
// The shenanigans above don't work for gcc.
# define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...)                            \
  extern "C" ReturnType Name(__VA_ARGS__)

#endif // SANITIZER_GO

#endif // SANITIZER_WINDOWS
#endif // SANITIZER_WIN_DEFS_H