mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
87e9c42495
This commit adds support for AArch64 in instrumentation runtime library, including AArch64 system calls. Also this commit divides syscalls into target-specific files. Reviewed By: rafauler, yota9 Differential Revision: https://reviews.llvm.org/D151942
395 lines
14 KiB
C
395 lines
14 KiB
C
#ifndef LLVM_TOOLS_LLVM_BOLT_SYS_AARCH64
|
|
#define LLVM_TOOLS_LLVM_BOLT_SYS_AARCH64
|
|
|
|
// Save all registers while keeping 16B stack alignment
|
|
#define SAVE_ALL \
|
|
"stp x0, x1, [sp, #-16]!\n" \
|
|
"stp x2, x3, [sp, #-16]!\n" \
|
|
"stp x4, x5, [sp, #-16]!\n" \
|
|
"stp x6, x7, [sp, #-16]!\n" \
|
|
"stp x8, x9, [sp, #-16]!\n" \
|
|
"stp x10, x11, [sp, #-16]!\n" \
|
|
"stp x12, x13, [sp, #-16]!\n" \
|
|
"stp x14, x15, [sp, #-16]!\n" \
|
|
"stp x16, x17, [sp, #-16]!\n" \
|
|
"stp x18, x19, [sp, #-16]!\n" \
|
|
"stp x20, x21, [sp, #-16]!\n" \
|
|
"stp x22, x23, [sp, #-16]!\n" \
|
|
"stp x24, x25, [sp, #-16]!\n" \
|
|
"stp x26, x27, [sp, #-16]!\n" \
|
|
"stp x28, x29, [sp, #-16]!\n" \
|
|
"str x30, [sp,#-16]!\n"
|
|
// Mirrors SAVE_ALL
|
|
#define RESTORE_ALL \
|
|
"ldr x30, [sp], #16\n" \
|
|
"ldp x28, x29, [sp], #16\n" \
|
|
"ldp x26, x27, [sp], #16\n" \
|
|
"ldp x24, x25, [sp], #16\n" \
|
|
"ldp x22, x23, [sp], #16\n" \
|
|
"ldp x20, x21, [sp], #16\n" \
|
|
"ldp x18, x19, [sp], #16\n" \
|
|
"ldp x16, x17, [sp], #16\n" \
|
|
"ldp x14, x15, [sp], #16\n" \
|
|
"ldp x12, x13, [sp], #16\n" \
|
|
"ldp x10, x11, [sp], #16\n" \
|
|
"ldp x8, x9, [sp], #16\n" \
|
|
"ldp x6, x7, [sp], #16\n" \
|
|
"ldp x4, x5, [sp], #16\n" \
|
|
"ldp x2, x3, [sp], #16\n" \
|
|
"ldp x0, x1, [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("b .instr%=\n\t"
|
|
".StaticAddr%=:\n\t"
|
|
".dword __hot_end\n\t"
|
|
".instr%=:\n\t"
|
|
"ldr %0, .StaticAddr%=\n\t"
|
|
"adrp %1, __hot_end\n\t"
|
|
"add %1, %1, :lo12:__hot_end\n\t"
|
|
: "=r"(StaticAddr), "=r"(DynAddr));
|
|
return DynAddr - StaticAddr;
|
|
}
|
|
|
|
uint64_t __read(uint64_t fd, const void *buf, uint64_t count) {
|
|
uint64_t ret;
|
|
register uint64_t x0 __asm__("x0") = fd;
|
|
register const void *x1 __asm__("x1") = buf;
|
|
register uint64_t x2 __asm__("x2") = count;
|
|
register uint32_t w8 __asm__("w8") = 63;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __write(uint64_t fd, const void *buf, uint64_t count) {
|
|
uint64_t ret;
|
|
register uint64_t x0 __asm__("x0") = fd;
|
|
register const void *x1 __asm__("x1") = buf;
|
|
register uint64_t x2 __asm__("x2") = count;
|
|
register uint32_t w8 __asm__("w8") = 64;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(w8)
|
|
: "cc", "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 x0 __asm__("x0") = addr;
|
|
register uint64_t x1 __asm__("x1") = size;
|
|
register uint64_t x2 __asm__("x2") = prot;
|
|
register uint64_t x3 __asm__("x3") = flags;
|
|
register uint64_t x4 __asm__("x4") = fd;
|
|
register uint64_t x5 __asm__("x5") = offset;
|
|
register uint32_t w8 __asm__("w8") = 222;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(x3), "r"(x4), "r"(x5), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __munmap(void *addr, uint64_t size) {
|
|
uint64_t ret;
|
|
register void *x0 __asm__("x0") = addr;
|
|
register uint64_t x1 __asm__("x1") = size;
|
|
register uint32_t w8 __asm__("w8") = 215;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __exit(uint64_t code) {
|
|
uint64_t ret;
|
|
register uint64_t x0 __asm__("x0") = code;
|
|
register uint32_t w8 __asm__("w8") = 94;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0)
|
|
: "r"(w8)
|
|
: "cc", "memory", "x1");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __open(const char *pathname, uint64_t flags, uint64_t mode) {
|
|
uint64_t ret;
|
|
register int x0 __asm__("x0") = -100;
|
|
register const char *x1 __asm__("x1") = pathname;
|
|
register uint64_t x2 __asm__("x2") = flags;
|
|
register uint64_t x3 __asm__("x3") = mode;
|
|
register uint32_t w8 __asm__("w8") = 56;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(x3), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
long __getdents64(unsigned int fd, dirent64 *dirp, size_t count) {
|
|
long ret;
|
|
register unsigned int x0 __asm__("x0") = fd;
|
|
register dirent64 *x1 __asm__("x1") = dirp;
|
|
register size_t x2 __asm__("x2") = count;
|
|
register uint32_t w8 __asm__("w8") = 61;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __readlink(const char *pathname, char *buf, size_t bufsize) {
|
|
uint64_t ret;
|
|
register int x0 __asm__("x0") = -100;
|
|
register const char *x1 __asm__("x1") = pathname;
|
|
register char *x2 __asm__("x2") = buf;
|
|
register size_t x3 __asm__("x3") = bufsize;
|
|
register uint32_t w8 __asm__("w8") = 78; // readlinkat
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(x3), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __lseek(uint64_t fd, uint64_t pos, uint64_t whence) {
|
|
uint64_t ret;
|
|
register uint64_t x0 __asm__("x0") = fd;
|
|
register uint64_t x1 __asm__("x1") = pos;
|
|
register uint64_t x2 __asm__("x2") = whence;
|
|
register uint32_t w8 __asm__("w8") = 62;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
int __ftruncate(uint64_t fd, uint64_t length) {
|
|
int ret;
|
|
register uint64_t x0 __asm__("x0") = fd;
|
|
register uint64_t x1 __asm__("x1") = length;
|
|
register uint32_t w8 __asm__("w8") = 46;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
int __close(uint64_t fd) {
|
|
int ret;
|
|
register uint64_t x0 __asm__("x0") = fd;
|
|
register uint32_t w8 __asm__("w8") = 57;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0)
|
|
: "r"(w8)
|
|
: "cc", "memory", "x1");
|
|
return ret;
|
|
}
|
|
|
|
int __madvise(void *addr, size_t length, int advice) {
|
|
int ret;
|
|
register void *x0 __asm__("x0") = addr;
|
|
register size_t x1 __asm__("x1") = length;
|
|
register int x2 __asm__("x2") = advice;
|
|
register uint32_t w8 __asm__("w8") = 233;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
int __uname(struct UtsNameTy *buf) {
|
|
int ret;
|
|
register UtsNameTy *x0 __asm__("x0") = buf;
|
|
register uint32_t w8 __asm__("w8") = 160;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0)
|
|
: "r"(w8)
|
|
: "cc", "memory", "x1");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __nanosleep(const timespec *req, timespec *rem) {
|
|
uint64_t ret;
|
|
register const timespec *x0 __asm__("x0") = req;
|
|
register timespec *x1 __asm__("x1") = rem;
|
|
register uint32_t w8 __asm__("w8") = 101;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(w8)
|
|
: "cc", "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 x0 __asm__("x0") = 0x1200011;
|
|
register uint64_t x1 __asm__("x1") = 0;
|
|
register uint64_t x2 __asm__("x2") = 0;
|
|
register uint64_t x3 __asm__("x3") = 0;
|
|
register uint64_t x4 __asm__("x4") = 0;
|
|
register uint32_t w8 __asm__("w8") = 220;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(x3), "r"(x4), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
int __mprotect(void *addr, size_t len, int prot) {
|
|
int ret;
|
|
register void *x0 __asm__("x0") = addr;
|
|
register size_t x1 __asm__("x1") = len;
|
|
register int x2 __asm__("x2") = prot;
|
|
register uint32_t w8 __asm__("w8") = 226;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __getpid() {
|
|
uint64_t ret;
|
|
register uint32_t w8 __asm__("w8") = 172;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret)
|
|
: "r"(w8)
|
|
: "cc", "memory", "x0", "x1");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __getppid() {
|
|
uint64_t ret;
|
|
register uint32_t w8 __asm__("w8") = 173;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret)
|
|
: "r"(w8)
|
|
: "cc", "memory", "x0", "x1");
|
|
return ret;
|
|
}
|
|
|
|
int __setpgid(uint64_t pid, uint64_t pgid) {
|
|
int ret;
|
|
register uint64_t x0 __asm__("x0") = pid;
|
|
register uint64_t x1 __asm__("x1") = pgid;
|
|
register uint32_t w8 __asm__("w8") = 154;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __getpgid(uint64_t pid) {
|
|
uint64_t ret;
|
|
register uint64_t x0 __asm__("x0") = pid;
|
|
register uint32_t w8 __asm__("w8") = 155;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0)
|
|
: "r"(w8)
|
|
: "cc", "memory", "x1");
|
|
return ret;
|
|
}
|
|
|
|
int __kill(uint64_t pid, int sig) {
|
|
int ret;
|
|
register uint64_t x0 __asm__("x0") = pid;
|
|
register int x1 __asm__("x1") = sig;
|
|
register uint32_t w8 __asm__("w8") = 129;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
int __fsync(int fd) {
|
|
int ret;
|
|
register int x0 __asm__("x0") = fd;
|
|
register uint32_t w8 __asm__("w8") = 82;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0)
|
|
: "r"(w8)
|
|
: "cc", "memory", "x1");
|
|
return ret;
|
|
}
|
|
|
|
uint64_t __sigprocmask(int how, const void *set, void *oldset) {
|
|
uint64_t ret;
|
|
register int x0 __asm__("x0") = how;
|
|
register const void *x1 __asm__("x1") = set;
|
|
register void *x2 __asm__("x2") = oldset;
|
|
register long x3 asm("x3") = 8;
|
|
register uint32_t w8 __asm__("w8") = 135;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %0, x0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(x3), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
int __prctl(int option, unsigned long arg2, unsigned long arg3,
|
|
unsigned long arg4, unsigned long arg5) {
|
|
int ret;
|
|
register int x0 __asm__("x0") = option;
|
|
register unsigned long x1 __asm__("x1") = arg2;
|
|
register unsigned long x2 __asm__("x2") = arg3;
|
|
register unsigned long x3 __asm__("x3") = arg4;
|
|
register unsigned long x4 __asm__("x4") = arg5;
|
|
register uint32_t w8 __asm__("w8") = 167;
|
|
__asm__ __volatile__("svc #0\n"
|
|
"mov %w0, w0"
|
|
: "=r"(ret), "+r"(x0), "+r"(x1)
|
|
: "r"(x2), "r"(x3), "r"(x4), "r"(w8)
|
|
: "cc", "memory");
|
|
return ret;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
#endif
|