| #ifndef LLVM_TOOLS_LLVM_BOLT_SYS_RISCV |
| #define LLVM_TOOLS_LLVM_BOLT_SYS_RISCV |
| |
| // Save all registers while keeping 16B stack alignment |
| #define SAVE_ALL \ |
| "addi sp, sp, -16\n" \ |
| "sd x0, 0(sp)\n" \ |
| "sd x1, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x2, 0(sp)\n" \ |
| "sd x3, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x4, 0(sp)\n" \ |
| "sd x5, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x6, 0(sp)\n" \ |
| "sd x7, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x8, 0(sp)\n" \ |
| "sd x9, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x10, 0(sp)\n" \ |
| "sd x11, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x12, 0(sp)\n" \ |
| "sd x13, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x14, 0(sp)\n" \ |
| "sd x15, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x16, 0(sp)\n" \ |
| "sd x17, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x18, 0(sp)\n" \ |
| "sd x19, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x20, 0(sp)\n" \ |
| "sd x21, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x22, 0(sp)\n" \ |
| "sd x23, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x24, 0(sp)\n" \ |
| "sd x25, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x26, 0(sp)\n" \ |
| "sd x27, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x28, 0(sp)\n" \ |
| "sd x29, 8(sp)\n" \ |
| "addi sp, sp, -16\n" \ |
| "sd x30, 0(sp)\n" \ |
| "sd x31, 8(sp)\n" |
| // Mirrors SAVE_ALL |
| #define RESTORE_ALL \ |
| "ld x30, 0(sp)\n" \ |
| "ld x31, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x28, 0(sp)\n" \ |
| "ld x29, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x26, 0(sp)\n" \ |
| "ld x27, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x24, 0(sp)\n" \ |
| "ld x25, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x22, 0(sp)\n" \ |
| "ld x23, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x20, 0(sp)\n" \ |
| "ld x21, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x18, 0(sp)\n" \ |
| "ld x19, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x16, 0(sp)\n" \ |
| "ld x17, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x14, 0(sp)\n" \ |
| "ld x15, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x12, 0(sp)\n" \ |
| "ld x13, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x10, 0(sp)\n" \ |
| "ld x11, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x8, 0(sp)\n" \ |
| "ld x9, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x6, 0(sp)\n" \ |
| "ld x7, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x4, 0(sp)\n" \ |
| "ld x5, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x2, 0(sp)\n" \ |
| "ld x3, 8(sp)\n" \ |
| "addi sp, sp, 16\n" \ |
| "ld x0, 0(sp)\n" \ |
| "ld x1, 8(sp)\n" \ |
| "addi sp, sp, 16\n" |
| |
| // Anonymous namespace covering everything but our library entry point |
| namespace { |
| |
| // Get the difference between runtime addrress of .text section and |
| // static address in section header table. Can be extracted from arbitrary |
| // pc value recorded at runtime to get the corresponding static address, which |
| // in turn can be used to search for indirect call description. Needed because |
| // indirect call descriptions are read-only non-relocatable data. |
| uint64_t getTextBaseAddress() { |
| uint64_t DynAddr; |
| uint64_t StaticAddr; |
| __asm__ volatile("lla %0, __hot_end\n\t" |
| "lui %1, %%hi(__hot_end)\n\t" |
| "addi %1, %1, %%lo(__hot_end)\n\t" |
| : "=r"(DynAddr), "=r"(StaticAddr)); |
| return DynAddr - StaticAddr; |
| } |
| |
| uint64_t __read(uint64_t fd, const void *buf, uint64_t count) { |
| uint64_t ret; |
| register uint64_t a0 __asm__("a0") = fd; |
| register const void *a1 __asm__("a1") = buf; |
| register uint64_t a2 __asm__("a2") = count; |
| register uint64_t a7 __asm__("a7") = |
| 63; // Assuming 63 is the syscall number for read |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret) |
| : "r"(a0), "r"(a1), "r"(a2), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __write(uint64_t fd, const void *buf, uint64_t count) { |
| uint64_t ret; |
| register uint64_t a0 __asm__("a0") = fd; |
| register const void *a1 __asm__("a1") = buf; |
| register uint64_t a2 __asm__("a2") = count; |
| register uint32_t a7 __asm__("a7") = |
| 64; // Assuming 64 is the syscall number for write |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret) |
| : "r"(a0), "r"(a1), "r"(a2), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| void *__mmap(uint64_t addr, uint64_t size, uint64_t prot, uint64_t flags, |
| uint64_t fd, uint64_t offset) { |
| void *ret; |
| register uint64_t a0 __asm__("a0") = addr; |
| register uint64_t a1 __asm__("a1") = size; |
| register uint64_t a2 __asm__("a2") = prot; |
| register uint64_t a3 __asm__("a3") = flags; |
| register uint64_t a4 __asm__("a4") = fd; |
| register uint64_t a5 __asm__("a5") = offset; |
| register uint32_t a7 __asm__("a7") = |
| 222; // Assuming 222 is the syscall number for mmap |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret) |
| : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), |
| "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __munmap(void *addr, uint64_t size) { |
| uint64_t ret; |
| register void *a0 __asm__("a0") = addr; |
| register uint64_t a1 __asm__("a1") = size; |
| register uint32_t a7 __asm__("a7") = 215; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __exit(uint64_t code) { |
| uint64_t ret; |
| register uint64_t a0 __asm__("a0") = code; |
| register uint32_t a7 __asm__("a7") = 94; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __open(const char *pathname, uint64_t flags, uint64_t mode) { |
| uint64_t ret; |
| register int a0 __asm__("a0") = |
| -100; // Assuming -100 is an invalid file descriptor |
| register const char *a1 __asm__("a1") = pathname; |
| register uint64_t a2 __asm__("a2") = flags; |
| register uint64_t a3 __asm__("a3") = mode; |
| register uint64_t a7 __asm__("a7") = |
| 56; // Assuming 56 is the syscall number for open |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret) |
| : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| long __getdents64(unsigned int fd, dirent64 *dirp, size_t count) { |
| long ret; |
| register unsigned int a0 __asm__("a0") = fd; |
| register dirent64 *a1 __asm__("a1") = dirp; |
| register size_t a2 __asm__("a2") = count; |
| register uint32_t a7 __asm__("a7") = 61; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __readlink(const char *pathname, char *buf, size_t bufsize) { |
| uint64_t ret; |
| register int a0 __asm__("a0") = -100; |
| register const char *a1 __asm__("a1") = pathname; |
| register char *a2 __asm__("a2") = buf; |
| register size_t a3 __asm__("a3") = bufsize; |
| register uint32_t a7 __asm__("a7") = 78; // readlinkat |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a3), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __lseek(uint64_t fd, uint64_t pos, uint64_t whence) { |
| uint64_t ret; |
| register uint64_t a0 __asm__("a0") = fd; |
| register uint64_t a1 __asm__("a1") = pos; |
| register uint64_t a2 __asm__("a2") = whence; |
| register uint32_t a7 __asm__("a7") = 62; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __ftruncate(uint64_t fd, uint64_t length) { |
| int ret; |
| register uint64_t a0 __asm__("a0") = fd; |
| register uint64_t a1 __asm__("a1") = length; |
| register uint32_t a7 __asm__("a7") = 46; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __close(uint64_t fd) { |
| int ret; |
| register uint64_t a0 __asm__("a0") = fd; |
| register uint32_t a7 __asm__("a7") = |
| 57; // Assuming 57 is the syscall number for close |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret) |
| : "r"(a0), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __madvise(void *addr, size_t length, int advice) { |
| int ret; |
| register void *a0 __asm__("a0") = addr; |
| register size_t a1 __asm__("a1") = length; |
| register int a2 __asm__("a2") = advice; |
| register uint32_t a7 __asm__("a7") = 233; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __uname(struct UtsNameTy *buf) { |
| int ret; |
| register UtsNameTy *a0 __asm__("a0") = buf; |
| register uint32_t a7 __asm__("a7") = 160; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __nanosleep(const timespec *req, timespec *rem) { |
| uint64_t ret; |
| register const timespec *a0 __asm__("a0") = req; |
| register timespec *a1 __asm__("a1") = rem; |
| register uint32_t a7 __asm__("a7") = 101; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int64_t __fork() { |
| uint64_t ret; |
| // clone instead of fork with flags |
| // "CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD" |
| register uint64_t a0 __asm__("a0") = 0x1200011; |
| register uint64_t a1 __asm__("a1") = 0; |
| register uint64_t a2 __asm__("a2") = 0; |
| register uint64_t a3 __asm__("a3") = 0; |
| register uint64_t a4 __asm__("a4") = 0; |
| register uint32_t a7 __asm__("a7") = 220; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a3), "r"(a4), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __mprotect(void *addr, size_t len, int prot) { |
| int ret; |
| register void *a0 __asm__("a0") = addr; |
| register size_t a1 __asm__("a1") = len; |
| register int a2 __asm__("a2") = prot; |
| register uint32_t a7 __asm__("a7") = 226; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __getpid() { |
| uint64_t ret; |
| register uint32_t a7 __asm__("a7") = 172; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __getppid() { |
| uint64_t ret; |
| register uint32_t a7 __asm__("a7") = 173; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __setpgid(uint64_t pid, uint64_t pgid) { |
| int ret; |
| register uint64_t a0 __asm__("a0") = pid; |
| register uint64_t a1 __asm__("a1") = pgid; |
| register uint32_t a7 __asm__("a7") = 154; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __getpgid(uint64_t pid) { |
| uint64_t ret; |
| register uint64_t a0 __asm__("a0") = pid; |
| register uint32_t a7 __asm__("a7") = 155; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __kill(uint64_t pid, int sig) { |
| int ret; |
| register uint64_t a0 __asm__("a0") = pid; |
| register int a1 __asm__("a1") = sig; |
| register uint32_t a7 __asm__("a7") = 129; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __fsync(int fd) { |
| int ret; |
| register int a0 __asm__("a0") = fd; |
| register uint32_t a7 __asm__("a7") = 82; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0) |
| : "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| uint64_t __sigprocmask(int how, const void *set, void *oldset) { |
| uint64_t ret; |
| register int a0 __asm__("a0") = how; |
| register const void *a1 __asm__("a1") = set; |
| register void *a2 __asm__("a2") = oldset; |
| register long a3 asm("a3") = 8; |
| register uint32_t a7 __asm__("a7") = 135; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a3), "r"(a7) |
| : "memory"); |
| return ret; |
| } |
| |
| int __prctl(int option, unsigned long arg2, unsigned long arg3, |
| unsigned long arg4, unsigned long arg5) { |
| int ret; |
| register int a0 __asm__("a0") = option; |
| register unsigned long a1 __asm__("a1") = arg2; |
| register unsigned long a2 __asm__("a2") = arg3; |
| register unsigned long a3 __asm__("a3") = arg4; |
| register unsigned long a4 __asm__("a4") = arg5; |
| register uint32_t a7 __asm__("a7") = 167; |
| __asm__ __volatile__("ecall\n\t" |
| "mv %0, a0" |
| : "=r"(ret), "+r"(a0), "+r"(a1) |
| : "r"(a2), "r"(a3), "r"(a4), "r"(a7) |
| : "cc", "memory"); |
| return ret; |
| } |
| } // anonymous namespace |
| |
| #endif |