Commit 0f0f543a9a

YANG Xudong <yangxudong@ymatrix.cn>
2024-08-14 23:32:03
loongarch: add glibc start.S to make zig-bootstrap work for loongarch64-linux-gnu (#21015)
1 parent 9be10ea
Changed files (5)
lib
libc
glibc
sysdeps
loongarch
unix
sysv
linux
loongarch
src
lib/libc/glibc/sysdeps/loongarch/bits/endianness.h
@@ -0,0 +1,11 @@
+#ifndef _BITS_ENDIANNESS_H
+#define _BITS_ENDIANNESS_H 1
+
+#ifndef _BITS_ENDIAN_H
+#error "Never use <bits/endianness.h> directly; include <endian.h> instead."
+#endif
+
+/* LoongArch is little-endian.  */
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif /* bits/endianness.h */
lib/libc/glibc/sysdeps/loongarch/sys/regdef.h
@@ -0,0 +1,169 @@
+/* Register Macro definitions
+   Copyright (C) 2022-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _SYS_REGDEF_H
+#define _SYS_REGDEF_H
+
+#define zero $r0
+#define ra $r1
+#define tp $r2
+#define sp $r3
+#define a0 $r4
+#define a1 $r5
+#define a2 $r6
+#define a3 $r7
+#define a4 $r8
+#define a5 $r9
+#define a6 $r10
+#define a7 $r11
+#define v0 $r4
+#define v1 $r5
+#define t0 $r12
+#define t1 $r13
+#define t2 $r14
+#define t3 $r15
+#define t4 $r16
+#define t5 $r17
+#define t6 $r18
+#define t7 $r19
+#define t8 $r20
+#define x $r21
+#define fp $r22
+#define s0 $r23
+#define s1 $r24
+#define s2 $r25
+#define s3 $r26
+#define s4 $r27
+#define s5 $r28
+#define s6 $r29
+#define s7 $r30
+#define s8 $r31
+
+#define fa0 $f0
+#define fa1 $f1
+#define fa2 $f2
+#define fa3 $f3
+#define fa4 $f4
+#define fa5 $f5
+#define fa6 $f6
+#define fa7 $f7
+#define fv0 $f0
+#define fv1 $f1
+#define ft0 $f8
+#define ft1 $f9
+#define ft2 $f10
+#define ft3 $f11
+#define ft4 $f12
+#define ft5 $f13
+#define ft6 $f14
+#define ft7 $f15
+#define ft8 $f16
+#define ft9 $f17
+#define ft10 $f18
+#define ft11 $f19
+#define ft12 $f20
+#define ft13 $f21
+#define ft14 $f22
+#define ft15 $f23
+#define fs0 $f24
+#define fs1 $f25
+#define fs2 $f26
+#define fs3 $f27
+#define fs4 $f28
+#define fs5 $f29
+#define fs6 $f30
+#define fs7 $f31
+#define fcc0 $fcc0
+#define fcc1 $fcc1
+#define fcc2 $fcc2
+#define fcc3 $fcc3
+#define fcc4 $fcc4
+#define fcc5 $fcc5
+#define fcc6 $fcc6
+#define fcc7 $fcc7
+#define fcsr0 $fcsr0
+
+#define vr0 $vr0
+#define vr1 $vr1
+#define vr2 $vr2
+#define vr3 $vr3
+#define vr4 $vr4
+#define vr5 $vr5
+#define vr6 $vr6
+#define vr7 $vr7
+#define vr8 $vr8
+#define vr9 $vr9
+#define vr10 $vr10
+#define vr11 $vr11
+#define vr12 $vr12
+#define vr13 $vr13
+#define vr14 $vr14
+#define vr15 $vr15
+#define vr16 $vr16
+#define vr17 $vr17
+#define vr18 $vr18
+#define vr19 $vr19
+#define vr20 $vr20
+#define vr21 $vr21
+#define vr22 $vr22
+#define vr23 $vr23
+#define vr24 $vr24
+#define vr25 $vr25
+#define vr26 $vr26
+#define vr27 $vr27
+#define vr28 $vr28
+#define vr29 $vr29
+#define vr30 $vr30
+#define vr31 $vr31
+
+#define xr0 $xr0
+#define xr1 $xr1
+#define xr2 $xr2
+#define xr3 $xr3
+#define xr4 $xr4
+#define xr5 $xr5
+#define xr6 $xr6
+#define xr7 $xr7
+#define xr7 $xr7
+#define xr8 $xr8
+#define xr9 $xr9
+#define xr10 $xr10
+#define xr11 $xr11
+#define xr12 $xr12
+#define xr13 $xr13
+#define xr14 $xr14
+#define xr15 $xr15
+#define xr16 $xr16
+#define xr17 $xr17
+#define xr18 $xr18
+#define xr19 $xr19
+#define xr20 $xr20
+#define xr21 $xr21
+#define xr22 $xr22
+#define xr23 $xr23
+#define xr24 $xr24
+#define xr25 $xr25
+#define xr26 $xr26
+#define xr27 $xr27
+#define xr28 $xr28
+#define xr29 $xr29
+#define xr30 $xr30
+#define xr31 $xr31
+
+#endif /* _SYS_REGDEF_H */
lib/libc/glibc/sysdeps/loongarch/start.S
@@ -0,0 +1,79 @@
+/* Startup code compliant to the ELF LoongArch ABI.
+   Copyright (C) 2022-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#define __ASSEMBLY__ 1
+#include <entry.h>
+#include <sys/asm.h>
+
+/* The entry point's job is to call __libc_start_main.  Per the ABI,
+   a0 contains the address of a function to be passed to atexit.
+   __libc_start_main wants this in a5.  */
+
+/*
+int
+__libc_start_main (int (*main) (int, char **, char **),
+		   int argc,
+		   char **argv,
+		   __typeof (main) init,
+		   void (*fini) (void),
+		   void (*rtld_fini) (void),
+		   void *stack_end);
+ */
+
+ENTRY (ENTRY_POINT)
+
+/* Terminate call stack by noting ra is undefined.  Use a dummy
+   .cfi_label to force starting the FDE.  */
+	.cfi_label .Ldummy
+	cfi_undefined (1)
+	or		a5, a0, zero /* rtld_fini */
+
+	la.pcrel	a0, t0, main
+	REG_L		a1, sp, 0
+	ADDI		a2, sp, SZREG
+
+	/* Adjust $sp for 16-aligned */
+	BSTRINS		sp, zero, 3, 0
+
+	move		a3, zero /* used to be init */
+	move		a4, zero /* used to be fini */
+	or		a6, sp, zero /* stack_end */
+
+	la.pcrel	ra, t0, __libc_start_main
+	jirl		ra, ra, 0
+
+	la.pcrel	ra, t0, abort
+	jirl		ra, ra, 0
+END (ENTRY_POINT)
lib/libc/glibc/sysdeps/unix/sysv/linux/loongarch/sysdep.h
@@ -0,0 +1,318 @@
+/* Assembly macros for LoongArch.
+   Copyright (C) 2022-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _LINUX_LOONGARCH_SYSDEP_H
+#define _LINUX_LOONGARCH_SYSDEP_H 1
+
+#include <sysdeps/unix/sysv/linux/sysdep.h>
+#include <sysdeps/unix/sysdep.h>
+#include <tls.h>
+
+#ifdef __ASSEMBLER__
+
+#include <sys/asm.h>
+#define ret jirl zero, ra, 0
+#define L(label) .L##label
+
+/* Performs a system call, handling errors by setting errno.  Linux indicates
+   errors by setting a0 to a value between -1 and -4095.  */
+#undef PSEUDO
+#define PSEUDO(name, syscall_name, args) \
+  ENTRY (name); \
+  li.d a7, SYS_ify (syscall_name); \
+  syscall 0; \
+  li.d a7, -4096; \
+  bltu a7, a0, .Lsyscall_error##name;
+
+#undef PSEUDO_END
+#define PSEUDO_END(sym) \
+  SYSCALL_ERROR_HANDLER (sym); \
+  ret; \
+  END (sym);
+
+#if !IS_IN(libc)
+#if RTLD_PRIVATE_ERRNO
+
+#define SYSCALL_ERROR_HANDLER(name) \
+  .Lsyscall_error##name : la t0, rtld_errno; \
+  sub.w a0, zero, a0; \
+  st.w a0, t0, 0; \
+  li.d a0, -1;
+
+#else
+
+#define SYSCALL_ERROR_HANDLER(name) \
+  .Lsyscall_error##name : la.tls.ie t0, errno; \
+  add.d t0, tp, t0; \
+  sub.w a0, zero, a0; \
+  st.w a0, t0, 0; \
+  li.d a0, -1;
+
+#endif
+#else
+
+#define SYSCALL_ERROR_HANDLER(name) .Lsyscall_error##name : b __syscall_error;
+
+#endif
+
+/* Performs a system call, not setting errno.  */
+#undef PSEUDO_NEORRNO
+#define PSEUDO_NOERRNO(name, syscall_name, args) \
+  ENTRY (name); \
+  li.d a7, SYS_ify (syscall_name); \
+  syscall 0;
+
+#undef PSEUDO_END_NOERRNO
+#define PSEUDO_END_NOERRNO(name) END (name);
+
+#undef ret_NOERRNO
+#define ret_NOERRNO ret
+
+/* Performs a system call, returning the error code.  */
+#undef PSEUDO_ERRVAL
+#define PSEUDO_ERRVAL(name, syscall_name, args) \
+  PSEUDO_NOERRNO (name, syscall_name, args); \
+  slli.d a0, a0, 32; \
+  srai.d a0, a0, 32; /* sign_ext */ \
+  sub.d a0, zero, a0;
+
+#undef PSEUDO_END_ERRVAL
+#define PSEUDO_END_ERRVAL(name) END (name);
+
+#undef ret_ERRVAL
+#define ret_ERRVAL ret
+
+#endif /* __ASSEMBLER__ */
+
+/* In order to get __set_errno() definition in INLINE_SYSCALL.  */
+#ifndef __ASSEMBLER__
+#include <errno.h>
+#endif
+
+#include <sysdeps/unix/sysdep.h>
+
+#undef SYS_ify
+#define SYS_ify(syscall_name) __NR_##syscall_name
+
+#ifndef __ASSEMBLER__
+
+#define VDSO_NAME "LINUX_5.10"
+#define VDSO_HASH 182947696
+
+/* List of system calls which are supported as vsyscalls.  */
+#define HAVE_CLOCK_GETRES64_VSYSCALL "__vdso_clock_getres"
+#define HAVE_CLOCK_GETTIME64_VSYSCALL "__vdso_clock_gettime"
+#define HAVE_GETTIMEOFDAY_VSYSCALL "__vdso_gettimeofday"
+#define HAVE_GETCPU_VSYSCALL "__vdso_getcpu"
+
+#define HAVE_CLONE3_WRAPPER 1
+
+#define INTERNAL_SYSCALL(name, nr, args...) \
+  internal_syscall##nr (SYS_ify (name), args)
+
+#define INTERNAL_SYSCALL_NCS(number, nr, args...) \
+  internal_syscall##nr (number, args)
+
+#define internal_syscall0(number, dummy...) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0"); \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "=r"(__a0) \
+		       : "r"(__a7) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define internal_syscall1(number, arg0) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      long int _arg0 = (long int) (arg0); \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0") = _arg0; \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "+r"(__a0) \
+		       : "r"(__a7) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define internal_syscall2(number, arg0, arg1) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      long int _arg0 = (long int) (arg0); \
+      long int _arg1 = (long int) (arg1); \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0") = _arg0; \
+      register long int __a1 asm ("$a1") = _arg1; \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "+r"(__a0) \
+		       : "r"(__a7), "r"(__a1) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define internal_syscall3(number, arg0, arg1, arg2) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      long int _arg0 = (long int) (arg0); \
+      long int _arg1 = (long int) (arg1); \
+      long int _arg2 = (long int) (arg2); \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0") = _arg0; \
+      register long int __a1 asm ("$a1") = _arg1; \
+      register long int __a2 asm ("$a2") = _arg2; \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "+r"(__a0) \
+		       : "r"(__a7), "r"(__a1), "r"(__a2) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define internal_syscall4(number, arg0, arg1, arg2, arg3) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      long int _arg0 = (long int) (arg0); \
+      long int _arg1 = (long int) (arg1); \
+      long int _arg2 = (long int) (arg2); \
+      long int _arg3 = (long int) (arg3); \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0") = _arg0; \
+      register long int __a1 asm ("$a1") = _arg1; \
+      register long int __a2 asm ("$a2") = _arg2; \
+      register long int __a3 asm ("$a3") = _arg3; \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "+r"(__a0) \
+		       : "r"(__a7), "r"(__a1), "r"(__a2), "r"(__a3) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define internal_syscall5(number, arg0, arg1, arg2, arg3, arg4) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      long int _arg0 = (long int) (arg0); \
+      long int _arg1 = (long int) (arg1); \
+      long int _arg2 = (long int) (arg2); \
+      long int _arg3 = (long int) (arg3); \
+      long int _arg4 = (long int) (arg4); \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0") = _arg0; \
+      register long int __a1 asm ("$a1") = _arg1; \
+      register long int __a2 asm ("$a2") = _arg2; \
+      register long int __a3 asm ("$a3") = _arg3; \
+      register long int __a4 asm ("$a4") = _arg4; \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "+r"(__a0) \
+		       : "r"(__a7), "r"(__a1), "r"(__a2), \
+			 "r"(__a3), "r"(__a4) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define internal_syscall6(number, arg0, arg1, arg2, arg3, arg4, arg5) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      long int _arg0 = (long int) (arg0); \
+      long int _arg1 = (long int) (arg1); \
+      long int _arg2 = (long int) (arg2); \
+      long int _arg3 = (long int) (arg3); \
+      long int _arg4 = (long int) (arg4); \
+      long int _arg5 = (long int) (arg5); \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0") = _arg0; \
+      register long int __a1 asm ("$a1") = _arg1; \
+      register long int __a2 asm ("$a2") = _arg2; \
+      register long int __a3 asm ("$a3") = _arg3; \
+      register long int __a4 asm ("$a4") = _arg4; \
+      register long int __a5 asm ("$a5") = _arg5; \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "+r"(__a0) \
+		       : "r"(__a7), "r"(__a1), "r"(__a2), "r"(__a3), \
+			 "r"(__a4), "r"(__a5) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define internal_syscall7(number, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \
+  ({ \
+    long int _sys_result; \
+\
+    { \
+      long int _arg0 = (long int) (arg0); \
+      long int _arg1 = (long int) (arg1); \
+      long int _arg2 = (long int) (arg2); \
+      long int _arg3 = (long int) (arg3); \
+      long int _arg4 = (long int) (arg4); \
+      long int _arg5 = (long int) (arg5); \
+      long int _arg6 = (long int) (arg6); \
+      register long int __a7 asm ("$a7") = number; \
+      register long int __a0 asm ("$a0") = _arg0; \
+      register long int __a1 asm ("$a1") = _arg1; \
+      register long int __a2 asm ("$a2") = _arg2; \
+      register long int __a3 asm ("$a3") = _arg3; \
+      register long int __a4 asm ("$a4") = _arg4; \
+      register long int __a5 asm ("$a5") = _arg5; \
+      register long int __a6 asm ("$a6") = _arg6; \
+      __asm__ volatile ("syscall 0\n\t" \
+		       : "+r"(__a0) \
+		       : "r"(__a7), "r"(__a1), "r"(__a2), "r"(__a3), \
+			 "r"(__a4), "r"(__a5), "r"(__a6) \
+		       : __SYSCALL_CLOBBERS); \
+      _sys_result = __a0; \
+    } \
+    _sys_result; \
+  })
+
+#define __SYSCALL_CLOBBERS \
+  "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory"
+
+extern long int __syscall_error (long int neg_errno);
+
+#endif /* ! __ASSEMBLER__ */
+
+#endif /* linux/loongarch/sysdep.h */
src/glibc.zig
@@ -461,6 +461,8 @@ fn start_asm_path(comp: *Compilation, arena: Allocator, basename: []const u8) ![
         } else {
             try result.appendSlice("powerpc" ++ s ++ "powerpc32");
         }
+    } else if (arch.isLoongArch()) {
+        try result.appendSlice("loongarch");
     }
 
     try result.appendSlice(s);
@@ -649,6 +651,9 @@ fn add_include_dirs_arch(
             try args.append("-I");
             try args.append(try path.join(arena, &[_][]const u8{ dir, "riscv" }));
         }
+    } else if (arch.isLoongArch()) {
+        try args.append("-I");
+        try args.append(try path.join(arena, &[_][]const u8{ dir, "loongarch" }));
     }
 }