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