xref: /llvm-project/bolt/runtime/common.h (revision 1cf23e5ee8bfdea7f8418d81c060174f20b357c5)
1 #if !defined(__APPLE__)
2 
3 #include <cstddef>
4 #include <cstdint>
5 
6 #else
7 
8 typedef __SIZE_TYPE__ size_t;
9 #define __SSIZE_TYPE__                                                         \
10   __typeof__(_Generic((__SIZE_TYPE__)0, unsigned long long int                 \
11                       : (long long int)0, unsigned long int                    \
12                       : (long int)0, unsigned int                              \
13                       : (int)0, unsigned short                                 \
14                       : (short)0, unsigned char                                \
15                       : (signed char)0))
16 typedef __SSIZE_TYPE__ ssize_t;
17 
18 typedef unsigned long long uint64_t;
19 
20 #endif
21 
22 #include "config.h"
23 
24 #ifdef HAVE_ELF_H
25 #include <elf.h>
26 #endif
27 
28 // Save all registers while keeping 16B stack alignment
29 #define SAVE_ALL                                                               \
30   "push %%rax\n"                                                               \
31   "push %%rbx\n"                                                               \
32   "push %%rcx\n"                                                               \
33   "push %%rdx\n"                                                               \
34   "push %%rdi\n"                                                               \
35   "push %%rsi\n"                                                               \
36   "push %%rbp\n"                                                               \
37   "push %%r8\n"                                                                \
38   "push %%r9\n"                                                                \
39   "push %%r10\n"                                                               \
40   "push %%r11\n"                                                               \
41   "push %%r12\n"                                                               \
42   "push %%r13\n"                                                               \
43   "push %%r14\n"                                                               \
44   "push %%r15\n"                                                               \
45   "sub $8, %%rsp\n"
46 
47 // Mirrors SAVE_ALL
48 #define RESTORE_ALL                                                            \
49   "add $8, %%rsp\n"                                                            \
50   "pop %%r15\n"                                                                \
51   "pop %%r14\n"                                                                \
52   "pop %%r13\n"                                                                \
53   "pop %%r12\n"                                                                \
54   "pop %%r11\n"                                                                \
55   "pop %%r10\n"                                                                \
56   "pop %%r9\n"                                                                 \
57   "pop %%r8\n"                                                                 \
58   "pop %%rbp\n"                                                                \
59   "pop %%rsi\n"                                                                \
60   "pop %%rdi\n"                                                                \
61   "pop %%rdx\n"                                                                \
62   "pop %%rcx\n"                                                                \
63   "pop %%rbx\n"                                                                \
64   "pop %%rax\n"
65 
66 // Anonymous namespace covering everything but our library entry point
67 namespace {
68 
69 #if defined(__APPLE__)
70 
71 uint64_t __write(uint64_t fd, const void *buf, uint64_t count) {
72   uint64_t ret;
73   const long write = 0x2000004;
74   __asm__ __volatile__("syscall;\n"
75                        "movq %%rax, %0;\n"
76                        : "=g"(ret)
77                        : /* rax */ "a"(write), /* rdi */ "D"(fd),
78                          /* rsi */ "S"(buf), /* rdx */ "d"(count)
79                        : "memory");
80   return ret;
81 }
82 
83 #else
84 
85 // We use a stack-allocated buffer for string manipulation in many pieces of
86 // this code, including the code that prints each line of the fdata file. This
87 // buffer needs to accomodate large function names, but shouldn't be arbitrarily
88 // large (dynamically allocated) for simplicity of our memory space usage.
89 constexpr uint32_t BufSize = 10240;
90 
91 // Declare some syscall wrappers we use throughout this code to avoid linking
92 // against system libc.
93 uint64_t __open(const char *pathname, uint64_t flags, uint64_t mode) {
94   uint64_t ret;
95   __asm__ __volatile__("movq $2, %%rax\n"
96                        "syscall"
97                        : "=a"(ret)
98                        : "D"(pathname), "S"(flags), "d"(mode)
99                        : "cc", "rcx", "r11", "memory");
100   return ret;
101 }
102 
103 uint64_t __write(uint64_t fd, const void *buf, uint64_t count) {
104   uint64_t ret;
105   __asm__ __volatile__("movq $1, %%rax\n"
106                        "syscall\n"
107                        : "=a"(ret)
108                        : "D"(fd), "S"(buf), "d"(count)
109                        : "cc", "rcx", "r11", "memory");
110   return ret;
111 }
112 
113 uint64_t __lseek(uint64_t fd, uint64_t pos, uint64_t whence) {
114   uint64_t ret;
115   __asm__ __volatile__("movq $8, %%rax\n"
116                        "syscall\n"
117                        : "=a"(ret)
118                        : "D"(fd), "S"(pos), "d"(whence)
119                        : "cc", "rcx", "r11", "memory");
120   return ret;
121 }
122 
123 int __close(uint64_t fd) {
124   uint64_t ret;
125   __asm__ __volatile__("movq $3, %%rax\n"
126                        "syscall\n"
127                        : "=a"(ret)
128                        : "D"(fd)
129                        : "cc", "rcx", "r11", "memory");
130   return ret;
131 }
132 
133 int __madvise(void *addr, size_t length, int advice) {
134   int ret;
135   __asm__ __volatile__("movq $28, %%rax\n"
136                        "syscall\n"
137                        : "=a"(ret)
138                        : "D"(addr), "S"(length), "d"(advice)
139                        : "cc", "rcx", "r11", "memory");
140   return ret;
141 }
142 
143 /* Length of the entries in `struct utsname' is 65.  */
144 #define _UTSNAME_LENGTH 65
145 
146 struct utsname {
147   char sysname[_UTSNAME_LENGTH];  /* Operating system name (e.g., "Linux") */
148   char nodename[_UTSNAME_LENGTH]; /* Name within "some implementation-defined
149                       network" */
150   char release[_UTSNAME_LENGTH]; /* Operating system release (e.g., "2.6.28") */
151   char version[_UTSNAME_LENGTH]; /* Operating system version */
152   char machine[_UTSNAME_LENGTH]; /* Hardware identifier */
153   char domainname[_UTSNAME_LENGTH]; /* NIS or YP domain name */
154 };
155 
156 int __uname(struct utsname *buf) {
157   int ret;
158   __asm__ __volatile__("movq $63, %%rax\n"
159                        "syscall\n"
160                        : "=a"(ret)
161                        : "D"(buf)
162                        : "cc", "rcx", "r11", "memory");
163   return ret;
164 }
165 
166 struct timespec {
167   uint64_t tv_sec;  /* seconds */
168   uint64_t tv_nsec; /* nanoseconds */
169 };
170 
171 uint64_t __nanosleep(const timespec *req, timespec *rem) {
172   uint64_t ret;
173   __asm__ __volatile__("movq $35, %%rax\n"
174                        "syscall\n"
175                        : "=a"(ret)
176                        : "D"(req), "S"(rem)
177                        : "cc", "rcx", "r11", "memory");
178   return ret;
179 }
180 
181 int64_t __fork() {
182   uint64_t ret;
183   __asm__ __volatile__("movq $57, %%rax\n"
184                        "syscall\n"
185                        : "=a"(ret)
186                        :
187                        : "cc", "rcx", "r11", "memory");
188   return ret;
189 }
190 
191 void *__mmap(uint64_t addr, uint64_t size, uint64_t prot, uint64_t flags,
192              uint64_t fd, uint64_t offset) {
193   void *ret;
194   register uint64_t r8 asm("r8") = fd;
195   register uint64_t r9 asm("r9") = offset;
196   register uint64_t r10 asm("r10") = flags;
197   __asm__ __volatile__("movq $9, %%rax\n"
198                        "syscall\n"
199                        : "=a"(ret)
200                        : "D"(addr), "S"(size), "d"(prot), "r"(r10), "r"(r8),
201                          "r"(r9)
202                        : "cc", "rcx", "r11", "memory");
203   return ret;
204 }
205 
206 int __mprotect(void *addr, size_t len, int prot) {
207   int ret;
208   __asm__ __volatile__("movq $10, %%rax\n"
209                        "syscall\n"
210                        : "=a"(ret)
211                        : "D"(addr), "S"(len), "d"(prot)
212                        : "cc", "rcx", "r11", "memory");
213   return ret;
214 }
215 
216 uint64_t __munmap(void *addr, uint64_t size) {
217   uint64_t ret;
218   __asm__ __volatile__("movq $11, %%rax\n"
219                        "syscall\n"
220                        : "=a"(ret)
221                        : "D"(addr), "S"(size)
222                        : "cc", "rcx", "r11", "memory");
223   return ret;
224 }
225 
226 uint64_t __getpid() {
227   uint64_t ret;
228   __asm__ __volatile__("movq $39, %%rax\n"
229                        "syscall\n"
230                        : "=a"(ret)
231                        :
232                        : "cc", "rcx", "r11", "memory");
233   return ret;
234 }
235 
236 uint64_t __getppid() {
237   uint64_t ret;
238   __asm__ __volatile__("movq $110, %%rax\n"
239                        "syscall\n"
240                        : "=a"(ret)
241                        :
242                        : "cc", "rcx", "r11", "memory");
243   return ret;
244 }
245 
246 uint64_t __exit(uint64_t code) {
247   uint64_t ret;
248   __asm__ __volatile__("movq $231, %%rax\n"
249                        "syscall\n"
250                        : "=a"(ret)
251                        : "D"(code)
252                        : "cc", "rcx", "r11", "memory");
253   return ret;
254 }
255 
256 // Helper functions for writing strings to the .fdata file. We intentionally
257 // avoid using libc names (lowercase memset) to make it clear it is our impl.
258 
259 /// Write number Num using Base to the buffer in OutBuf, returns a pointer to
260 /// the end of the string.
261 char *intToStr(char *OutBuf, uint64_t Num, uint32_t Base) {
262   const char *Chars = "0123456789abcdef";
263   char Buf[21];
264   char *Ptr = Buf;
265   while (Num) {
266     *Ptr++ = *(Chars + (Num % Base));
267     Num /= Base;
268   }
269   if (Ptr == Buf) {
270     *OutBuf++ = '0';
271     return OutBuf;
272   }
273   while (Ptr != Buf) {
274     *OutBuf++ = *--Ptr;
275   }
276   return OutBuf;
277 }
278 
279 /// Copy Str to OutBuf, returns a pointer to the end of the copied string
280 char *strCopy(char *OutBuf, const char *Str, int32_t Size = BufSize) {
281   while (*Str) {
282     *OutBuf++ = *Str++;
283     if (--Size <= 0)
284       return OutBuf;
285   }
286   return OutBuf;
287 }
288 
289 void memSet(char *Buf, char C, uint32_t Size) {
290   for (int I = 0; I < Size; ++I)
291     *Buf++ = C;
292 }
293 
294 void *memCpy(void *Dest, const void *Src, size_t Len) {
295   char *d = static_cast<char *>(Dest);
296   const char *s = static_cast<const char *>(Src);
297   while (Len--)
298     *d++ = *s++;
299   return Dest;
300 }
301 
302 uint32_t strLen(const char *Str) {
303   uint32_t Size = 0;
304   while (*Str++)
305     ++Size;
306   return Size;
307 }
308 
309 void reportError(const char *Msg, uint64_t Size) {
310   __write(2, Msg, Size);
311   __exit(1);
312 }
313 
314 void assert(bool Assertion, const char *Msg) {
315   if (Assertion)
316     return;
317   char Buf[BufSize];
318   char *Ptr = Buf;
319   Ptr = strCopy(Ptr, "Assertion failed: ");
320   Ptr = strCopy(Ptr, Msg, BufSize - 40);
321   Ptr = strCopy(Ptr, "\n");
322   reportError(Buf, Ptr - Buf);
323 }
324 
325 void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
326   char Buf[BufSize];
327   char *Ptr = Buf;
328   Ptr = strCopy(Ptr, Msg, BufSize - 23);
329   Ptr = intToStr(Ptr, Num, Base);
330   Ptr = strCopy(Ptr, "\n");
331   __write(2, Buf, Ptr - Buf);
332 }
333 
334 void report(const char *Msg) { __write(2, Msg, strLen(Msg)); }
335 
336 /// 1B mutex accessed by lock xchg
337 class Mutex {
338   volatile bool InUse{false};
339 
340 public:
341   bool acquire() {
342     bool Result = true;
343     asm volatile("lock; xchg %0, %1" : "+m"(InUse), "=r"(Result) : : "cc");
344     return !Result;
345   }
346   void release() { InUse = false; }
347 };
348 
349 /// RAII wrapper for Mutex
350 class Lock {
351   Mutex &M;
352 
353 public:
354   Lock(Mutex &M) : M(M) {
355     while (!M.acquire()) {
356     }
357   }
358   ~Lock() { M.release(); }
359 };
360 
361 inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
362   return (Value + Align - 1) / Align * Align;
363 }
364 
365 #endif
366 
367 } // anonymous namespace
368