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