Add support for loongarch64

Bug: https://crbug.com/linux-syscall-support/64
Change-Id: I820c339d2746c8487f0942e86d0dc245ee0e1e50
Reviewed-on: https://chromium-review.googlesource.com/c/linux-syscall-support/+/3824867
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/README.md b/README.md
index b0cd129..e25abdd 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,7 @@
 * MIPS 32-bit o32 ABI
 * MIPS 32-bit n32 ABI
 * MIPS 64-bit n64 ABI
+* LOONGARCH 64-bit ABI
 
 ## API
 
diff --git a/linux_syscall_support.h b/linux_syscall_support.h
index 5ea1295..2664b72 100644
--- a/linux_syscall_support.h
+++ b/linux_syscall_support.h
@@ -89,7 +89,7 @@
 #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) ||   \
      defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \
      defined(__aarch64__) || defined(__s390__) || defined(__e2k__) ||  \
-     (defined(__riscv) && __riscv_xlen == 64))                         \
+     (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch_lp64))  \
   && (defined(__linux) || defined(__ANDROID__))
 
 #ifndef SYS_CPLUSPLUS
@@ -309,8 +309,8 @@
 } __attribute__((packed,aligned(4)));
 #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
   #define kernel_old_sigaction kernel_sigaction
-#elif defined(__aarch64__) || defined(__riscv)
-  // No kernel_old_sigaction defined for arm64 or riscv.
+#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
+  // No kernel_old_sigaction defined for arm64 riscv and loongarch64.
 #endif
 
 /* Some kernel functions (e.g. sigaction() in 2.6.23) require that the
@@ -349,7 +349,7 @@
     void             (*sa_sigaction_)(int, siginfo_t *, void *);
   };
   unsigned long      sa_flags;
-#ifndef __riscv
+#if !defined(__riscv) && !defined(__loongarch_lp64)
   void               (*sa_restorer)(void);
 #endif
   struct kernel_sigset_t sa_mask;
@@ -551,7 +551,7 @@
   int                st_blocks;
   int                st_pad4[14];
 };
-#elif defined(__aarch64__) || defined(__riscv)
+#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
 struct kernel_stat {
   unsigned long      st_dev;
   unsigned long      st_ino;
@@ -752,6 +752,37 @@
 };
 #endif
 
+struct kernel_statx_timestamp {
+  int64_t   tv_sec;
+  uint32_t  tv_nsec;
+  int32_t   __reserved;
+};
+
+struct kernel_statx {
+  uint32_t  stx_mask;
+  uint32_t  stx_blksize;
+  uint64_t  stx_attributes;
+  uint32_t  stx_nlink;
+  uint32_t  stx_uid;
+  uint32_t  stx_gid;
+  uint16_t  stx_mode;
+  uint16_t  __spare0[1];
+  uint64_t  stx_ino;
+  uint64_t  stx_size;
+  uint64_t  stx_blocks;
+  uint64_t  stx_attributes_mask;
+  struct kernel_statx_timestamp  stx_atime;
+  struct kernel_statx_timestamp  stx_btime;
+  struct kernel_statx_timestamp  stx_ctime;
+  struct kernel_statx_timestamp  stx_mtime;
+  uint32_t  stx_rdev_major;
+  uint32_t  stx_rdev_minor;
+  uint32_t  stx_dev_major;
+  uint32_t  stx_dev_minor;
+  uint64_t  stx_mnt_id;
+  uint64_t  __spare2;
+  uint64_t  __spare3[12];
+};
 
 /* Definitions missing from the standard header files                        */
 #ifndef O_DIRECTORY
@@ -788,6 +819,18 @@
 #ifndef AT_REMOVEDIR
 #define AT_REMOVEDIR            0x200
 #endif
+#ifndef AT_NO_AUTOMOUNT
+#define AT_NO_AUTOMOUNT         0x800
+#endif
+#ifndef AT_EMPTY_PATH
+#define AT_EMPTY_PATH           0x1000
+#endif
+#ifndef STATX_BASIC_STATS
+#define STATX_BASIC_STATS       0x000007ffU
+#endif
+#ifndef AT_STATX_SYNC_AS_STAT
+#define AT_STATX_SYNC_AS_STAT   0x0000
+#endif
 #ifndef MREMAP_FIXED
 #define MREMAP_FIXED            2
 #endif
@@ -1119,7 +1162,7 @@
 #define __NR_getrandom          (__NR_SYSCALL_BASE + 384)
 #endif
 /* End of ARM 3/EABI definitions                                             */
-#elif defined(__aarch64__) || defined(__riscv)
+#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
 #ifndef __NR_setxattr
 #define __NR_setxattr             5
 #endif
@@ -1175,9 +1218,11 @@
 #ifndef __NR_readlinkat
 #define __NR_readlinkat          78
 #endif
+#if !defined(__loongarch_lp64)
 #ifndef __NR_newfstatat
 #define __NR_newfstatat          79
 #endif
+#endif
 #ifndef __NR_set_tid_address
 #define __NR_set_tid_address     96
 #endif
@@ -1218,7 +1263,9 @@
 #ifndef __NR_getrandom
 #define __NR_getrandom          278
 #endif
-/* End of aarch64 definitions                                                */
+#ifndef __NR_statx
+#define __NR_statx              291
+#endif
 #elif defined(__x86_64__)
 #ifndef __NR_pread64
 #define __NR_pread64             17
@@ -1935,7 +1982,7 @@
   #undef  LSS_RETURN
   #if defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \
        || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) \
-       || defined(__e2k__) || defined(__riscv)
+       || defined(__e2k__) || defined(__riscv) || defined(__loongarch_lp64)
   /* Failing system calls return a negative result in the range of
    * -1..-4095. These are "errno" values with the sign inverted.
    */
@@ -3796,6 +3843,134 @@
                               "b[4]", "b[5]", "pred0");
       LSS_RETURN(int, __res);
     }
+  #elif defined(__loongarch_lp64)
+    /* Most definitions of _syscallX() neglect to mark "memory" as being
+     * clobbered. This causes problems with compilers, that do a better job
+     * at optimizing across __asm__ calls.
+     * So, we just have to redefine all of the _syscallX() macros.
+     */
+    #undef LSS_REG
+    #define LSS_REG(ar,a) register int64_t __r##ar __asm__("a"#ar) = (int64_t)a
+    /* syscall is like subroutine calls, all caller-saved registers may be
+     * clobbered, we should add them to the |Clobbers| list.
+     * a0 is not included because it's in the output list.
+     */
+    #define LSS_SYSCALL_CLOBBERS "t0", "t1", "t2", "t3", "t4", "t5", "t6",    \
+                                 "t7", "t8", "memory"
+    #undef  LSS_BODY
+    #define LSS_BODY(type,name,args...)                                       \
+          register int64_t __res_a0 __asm__("a0");                            \
+          int64_t __res;                                                      \
+          __asm__ __volatile__ ("li.d $a7, %1\n"                              \
+                                "syscall 0x0\n"                               \
+                                : "=r"(__res_a0)                              \
+                                : "i"(__NR_##name) , ## args                  \
+                                : LSS_SYSCALL_CLOBBERS);                      \
+          __res = __res_a0;                                                   \
+          LSS_RETURN(type, __res)
+    #undef _syscall0
+    #define _syscall0(type, name)                                             \
+      type LSS_NAME(name)(void) {                                             \
+        LSS_BODY(type, name);                                                 \
+      }
+    #undef _syscall1
+    #define _syscall1(type, name, type1, arg1)                                \
+      type LSS_NAME(name)(type1 arg1) {                                       \
+        LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0));                    \
+      }
+    #undef _syscall2
+    #define _syscall2(type, name, type1, arg1, type2, arg2)                   \
+      type LSS_NAME(name)(type1 arg1, type2 arg2) {                           \
+        LSS_REG(0, arg1); LSS_REG(1, arg2);                                   \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1));                           \
+      }
+    #undef _syscall3
+    #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3)      \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) {               \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2));                \
+      }
+    #undef _syscall4
+    #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)  \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {   \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_REG(3, arg4);                                                     \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3));     \
+      }
+    #undef _syscall5
+    #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,  \
+                      type5,arg5)                                             \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4,     \
+                          type5 arg5) {                                       \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_REG(3, arg4); LSS_REG(4, arg5);                                   \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3),      \
+                             "r"(__r4));                                      \
+      }
+    #undef _syscall6
+    #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,  \
+                      type5,arg5,type6,arg6)                                  \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4,     \
+                          type5 arg5, type6 arg6) {                           \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6);                 \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3),      \
+                             "r"(__r4), "r"(__r5));                           \
+      }
+
+    LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
+                                   int flags, void *arg, int *parent_tidptr,
+                                   void *newtls, int *child_tidptr) {
+      int64_t __res;
+      {
+        register int64_t __res_a0 __asm__("a0");
+        register uint64_t __flags __asm__("a0") = flags;
+        register void *__stack __asm__("a1") = child_stack;
+        register void *__ptid  __asm__("a2") = parent_tidptr;
+        register void *__tls   __asm__("a3") = newtls;
+        register int  *__ctid  __asm__("a4") = child_tidptr;
+        __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be
+                              * used by the child.
+                              */
+                             "addi.d  %2, %2, -16\n"
+                             "st.d    %1, %2, 8\n"
+                             "st.d    %4, %2, 0\n"
+
+                             /* %a0 = syscall(%a0 = flags,
+                              *               %a1 = child_stack,
+                              *               %a2 = parent_tidptr,
+                              *               %a3 = newtls,
+                              *               %a4 = child_tidptr)
+                              */
+                             "li.d      $a7, %8\n"
+                             "syscall   0x0\n"
+
+                             /* if (%a0 != 0)
+                              *   return %a0;
+                              */
+                             "bnez    $a0, 1f\n"
+
+                             /* In the child, now. Call "fn(arg)".
+                              */
+                             "ld.d    $a0, $sp, 0\n"
+                             "ld.d    $a1, $sp, 8\n"
+                             "addi.d  $sp, $sp, 16\n"
+                             "jirl    $ra, $a1, 0\n"
+
+                             /* Call _exit(%a0).
+                              */
+                             "li.d     $a7, %9\n"
+                             "syscall  0x0\n"
+                           "1:\n"
+                             : "=r" (__res_a0)
+                             : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg),
+                               "r"(__ptid), "r"(__tls), "r"(__ctid),
+                               "i"(__NR_clone), "i"(__NR_exit)
+                             : LSS_SYSCALL_CLOBBERS);
+      __res = __res_a0;
+      }
+      LSS_RETURN(int, __res);
+    }
 
   #endif
   #define __NR__exit   __NR_exit
@@ -3827,8 +4002,10 @@
     // fork is polyfilled below when not available.
     LSS_INLINE _syscall0(pid_t,   fork)
   #endif
+  #if defined(__NR_fstat)
   LSS_INLINE _syscall2(int,     fstat,           int,         f,
                       struct kernel_stat*,   b)
+  #endif
   LSS_INLINE _syscall2(int,     fstatfs,         int,         f,
                       struct kernel_statfs*, b)
   #if defined(__x86_64__)
@@ -3863,10 +4040,10 @@
                        gid_t *,         e,       gid_t *,     s)
   LSS_INLINE _syscall3(int,     getresuid,       uid_t *,     r,
                        uid_t *,         e,       uid_t *,     s)
-#if !defined(__ARM_EABI__)
+  #if defined(__NR_getrlimit)
   LSS_INLINE _syscall2(int,     getrlimit,       int,         r,
                       struct kernel_rlimit*, l)
-#endif
+  #endif
   LSS_INLINE _syscall1(pid_t,   getsid,          pid_t,       p)
   LSS_INLINE _syscall0(pid_t,   _gettid)
   LSS_INLINE _syscall2(pid_t,   gettimeofday,    struct kernel_timeval*, t,
@@ -3984,8 +4161,10 @@
                        gid_t,          e, gid_t,  s)
   LSS_INLINE _syscall3(int,     setresuid,       uid_t,       r,
                        uid_t,          e, uid_t,  s)
+  #if defined(__NR_setrlimit)
   LSS_INLINE _syscall2(int,     setrlimit,       int,         r,
                        const struct kernel_rlimit*, l)
+  #endif
   LSS_INLINE _syscall0(pid_t,    setsid)
   LSS_INLINE _syscall2(int,     sigaltstack,     const stack_t*, s,
                        const stack_t*, o)
@@ -4019,23 +4198,6 @@
     LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu,
                          unsigned *, node, void *, unused)
   #endif
-  #if defined(__x86_64__) || defined(__e2k__) ||                              \
-     (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32)
-    LSS_INLINE _syscall3(int, recvmsg,            int,   s,
-                        struct kernel_msghdr*,     m, int, f)
-    LSS_INLINE _syscall3(int, sendmsg,            int,   s,
-                         const struct kernel_msghdr*, m, int, f)
-    LSS_INLINE _syscall6(int, sendto,             int,   s,
-                         const void*,             m, size_t, l,
-                         int,                     f,
-                         const struct kernel_sockaddr*, a, int, t)
-    LSS_INLINE _syscall2(int, shutdown,           int,   s,
-                         int,                     h)
-    LSS_INLINE _syscall3(int, socket,             int,   d,
-                         int,                     t, int,       p)
-    LSS_INLINE _syscall4(int, socketpair,         int,   d,
-                         int,                     t, int,       p, int*, s)
-  #endif
   #if defined(__NR_fadvise64)
     #if defined(__x86_64__)
     /* Need to make sure loff_t isn't truncated to 32-bits under x32.  */
@@ -4118,6 +4280,12 @@
                          const char *,            p,
                          struct kernel_stat*,     b, int, f)
   #endif
+  #if defined(__NR_statx)
+    LSS_INLINE _syscall5(int, statx,              int,   d,
+                         const char *,            p,
+                         int, f,                  int,   m,
+                         struct kernel_statx*,    b)
+  #endif
   #if defined(__x86_64__) || defined(__s390x__)
     LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid,
                                          gid_t *egid,
@@ -4614,23 +4782,31 @@
       LSS_SC_BODY(4, int, 8, d, type, protocol, sv);
     }
   #endif
-  #if defined(__ARM_EABI__) || defined (__aarch64__) || defined(__riscv)
+  #if defined(__NR_recvmsg)
     LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg,
                          int, flags)
+  #endif
+  #if defined(__NR_sendmsg)
     LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*,
                          msg, int, flags)
+  #endif
+  #if defined(__NR_sendto)
     LSS_INLINE _syscall6(ssize_t, sendto, int, s, const void*, buf, size_t,len,
                          int, flags, const struct kernel_sockaddr*, to,
                          unsigned int, tolen)
+  #endif
+  #if defined(__NR_shutdown)
     LSS_INLINE _syscall2(int, shutdown, int, s, int, how)
+  #endif
+  #if defined(__NR_socket)
     LSS_INLINE _syscall3(int, socket, int, domain, int, type, int, protocol)
+  #endif
+  #if defined(__NR_socketpair)
     LSS_INLINE _syscall4(int, socketpair, int, d, int, type, int, protocol,
                          int*, sv)
   #endif
-  #if defined(__i386__) || defined(__ARM_ARCH_3__) ||                         \
-      (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) ||                  \
-      defined(__s390__)
-    #define __NR__socketcall  __NR_socketcall
+
+  #if defined(__NR_socketcall)
     LSS_INLINE _syscall2(int,      _socketcall,    int,   c,
                          va_list,                  a)
     LSS_INLINE int LSS_NAME(socketcall)(int op, ...) {
@@ -4642,36 +4818,43 @@
       return rc;
     }
 
+  # if !defined(__NR_recvmsg)
     LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg,
                                          int flags){
       return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags);
     }
-
+  # endif
+  # if !defined(__NR_sendmsg)
     LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s,
                                          const struct kernel_msghdr *msg,
                                          int flags) {
       return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags);
     }
-
+  # endif
+  # if !defined(__NR_sendto)
     LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len,
                                         int flags,
                                         const struct kernel_sockaddr *to,
                                         unsigned int tolen) {
       return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen);
     }
-
+  # endif
+  # if !defined(__NR_shutdown)
     LSS_INLINE int LSS_NAME(shutdown)(int s, int how) {
       return LSS_NAME(socketcall)(13, s, how);
     }
-
+  # endif
+  # if !defined(__NR_socket)
     LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) {
       return LSS_NAME(socketcall)(1, domain, type, protocol);
     }
-
+  # endif
+  # if !defined(__NR_socketpair)
     LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol,
                                         int sv[2]) {
       return LSS_NAME(socketcall)(8, d, type, protocol, sv);
     }
+  # endif
   #endif
   #if defined(__NR_fstatat64)
     LSS_INLINE _syscall4(int,   fstatat64,        int,   d,
@@ -4920,16 +5103,79 @@
   }
 #endif
 
+#if defined(__NR_statx)
+  /* copy the contents of kernel_statx to the kernel_stat structure.  */
+  LSS_INLINE void LSS_NAME(cp_stat_statx)(struct kernel_stat  *to,
+                                          struct kernel_statx *from) {
+    memset(to, 0, sizeof(struct kernel_stat));
+    to->st_dev = ((from->stx_dev_minor & 0xff) |
+                 ((from->stx_dev_major & 0xfff) << 8) |
+                 ((from->stx_dev_minor & ~0xff) << 12));
+    to->st_rdev = ((from->stx_rdev_minor & 0xff) |
+                  ((from->stx_rdev_major & 0xfff) << 8) |
+                  ((from->stx_rdev_minor & ~0xff) << 12));
+    to->st_ino = from->stx_ino;
+    to->st_mode = from->stx_mode;
+    to->st_nlink = from->stx_nlink;
+    to->st_uid = from->stx_uid;
+    to->st_gid = from->stx_gid;
+    to->st_atime_ = from->stx_atime.tv_sec;
+    to->st_atime_nsec_ = from->stx_atime.tv_nsec;
+    to->st_mtime_ = from->stx_mtime.tv_sec;
+    to->st_mtime_nsec_ = from->stx_mtime.tv_nsec;
+    to->st_ctime_ = from->stx_ctime.tv_sec;
+    to->st_ctime_nsec_ = from->stx_ctime.tv_nsec;
+    to->st_size = from->stx_size;
+    to->st_blocks = from->stx_blocks;
+    to->st_blksize = from->stx_blksize;
+  }
+#endif
+
+#if !defined(__NR_fstat)
+  LSS_INLINE int LSS_NAME(fstat)(int fd,
+                                 struct kernel_stat *buf) {
+    #if defined(__NR_newfstatat)
+      return LSS_NAME(newfstatat)(fd, "", buf, AT_EMPTY_PATH);
+    #elif defined(__NR_statx)
+      struct kernel_statx stx;
+      int flags = AT_NO_AUTOMOUNT | AT_EMPTY_PATH;
+      int mask = STATX_BASIC_STATS;
+      int res = LSS_NAME(statx)(fd, "", flags, mask, &stx);
+      LSS_NAME(cp_stat_statx)(buf, &stx);
+      return res;
+    #endif
+  }
+#endif
+
 #if !defined(__NR_stat)
   LSS_INLINE int LSS_NAME(stat)(const char *pathname,
                                 struct kernel_stat *buf) {
-    return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0);
+    #if defined(__NR_newfstatat)
+      return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0);
+    #elif defined(__NR_statx)
+      struct kernel_statx stx;
+      int flags = AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT;
+      int mask = STATX_BASIC_STATS;
+      int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx);
+      LSS_NAME(cp_stat_statx)(buf, &stx);
+      return res;
+    #endif
   }
 #endif
+
 #if !defined(__NR_lstat)
   LSS_INLINE int LSS_NAME(lstat)(const char *pathname,
                                  struct kernel_stat *buf) {
-    return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, AT_SYMLINK_NOFOLLOW);
+    #if defined(__NR_newfstatat)
+      return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, AT_SYMLINK_NOFOLLOW);
+    #elif defined(__NR_statx)
+      struct kernel_statx stx;
+      int flags = AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW;
+      int mask = STATX_BASIC_STATS;
+      int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx);
+      LSS_NAME(cp_stat_statx)(buf, &stx);
+      return res;
+    #endif
   }
 #endif
 
@@ -4943,7 +5189,7 @@
 // TODO: define this in an arch-independant way instead of inlining the clone
 //       syscall body.
 
-# if defined(__aarch64__) || defined(__riscv)
+# if defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
   LSS_INLINE pid_t LSS_NAME(fork)(void) {
     // No fork syscall on aarch64 - implement by means of the clone syscall.
     // Note that this does not reset glibc's cached view of the PID/TID, so
diff --git a/tests/Makefile b/tests/Makefile
index 7b18ed2..b54e0f5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -116,6 +116,7 @@
 		"mips64-unknown-linux-gnu-gcc -mabi=n32" \
 		"s390-ibm-linux-gnu-gcc" \
 		"s390x-ibm-linux-gnu-gcc" \
+		"loongarch64-unknown-linux-gnu-gcc" \
 	; do \
 		cxx=`echo "$$cc" | sed 's:-gcc:-g++:'`; \
 		$(MAKE) --no-print-directory CC="$$cc" CXX="$$cxx" cross_compile; \