Browse Source

xtensa: support call0 ABI

Most changes are mechanical replacement of 'retw' instruction with
'abi_ret' macro, defined to 'retw' or 'ret' according to ABI.
Assembly code that makes calls is duplicated for call0 ABI with changed
register numbers for parameters/return value and call instruction.
'entry' instructions are replaced with 'abi_entry' macro.

More interesting changes:
- non-leaf assembly functions (e.g. _dl_tlsdesc_dynamic,
  _dl_linux_resolve, SYSCALL_ERROR_HANDLER, PSEUDO) now need to preserve
  registers around intermediate calls they make, use temporary stack
  frame for that;
- setjmp/longjmp only need to save and restore return address, stack
  pointer and callee-saved registers in the jmpbuf;
- __clone and syscall functions had hardcoded offsets to parameter
  passed on stack, on call0 ABI they don't need stack frame, so the
  offset is different. Replace these offsets with FRAMESIZE macro.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Max Filippov 8 years ago
parent
commit
e78a0f58f2

+ 12 - 0
ldso/ldso/xtensa/dl-startup.h

@@ -23,6 +23,7 @@ __asm__ (
     "	.align  4\n"
     "0:	movi    a3, _start+3\n"
     "	sub     a2, a0, a3\n"
+#if defined(__XTENSA_WINDOWED_ABI__)
     "	# Make sure a0 is cleared to mark the top of stack.\n"
     "	movi    a0, 0\n"
     "	# user_entry_point = _dl_start(pointer to argument block)\n"
@@ -32,6 +33,17 @@ __asm__ (
     "	callx4  a4\n"
     "	# Save user_entry_point so we can jump to it.\n"
     "	mov     a3, a6\n"
+#elif defined(__XTENSA_CALL0_ABI__)
+    "	# user_entry_point = _dl_start(pointer to argument block)\n"
+    "	movi    a0, _dl_start\n"
+    "	add     a0, a0, a2\n"
+    "	mov     a2, sp\n"
+    "	callx0  a0\n"
+    "	# Save user_entry_point so we can jump to it.\n"
+    "	mov     a3, a2\n"
+#else
+#error Unsupported Xtensa ABI
+#endif
     "	l32i    a7, sp, 0   # load argc\n"
     "	# Load _dl_skip_args into a4.\n"
     "	movi    a4, _dl_skip_args\n"

+ 25 - 20
ldso/ldso/xtensa/dl-tlsdesc.S

@@ -23,16 +23,11 @@
 #include "tlsdesc.h"
 
 	.text
-	.align 4
-	.hidden _dl_tlsdesc_return
-	.global	_dl_tlsdesc_return
-	.type	_dl_tlsdesc_return, @function
-_dl_tlsdesc_return:
-	entry	a1, 16
+HIDDEN_ENTRY (_dl_tlsdesc_return)
 	rur.threadptr	a3
 	add		a2, a2, a3
-	retw
-	.size	_dl_tlsdesc_return, .-_dl_tlsdesc_return
+	abi_ret
+END (_dl_tlsdesc_return)
 
 #ifdef SHARED
 
@@ -57,12 +52,7 @@ _dl_tlsdesc_return:
 	   }
 	 */
 
-	.align 4
-	.hidden _dl_tlsdesc_dynamic
-	.global	_dl_tlsdesc_dynamic
-	.type	_dl_tlsdesc_dynamic, @function
-_dl_tlsdesc_dynamic:
-	entry	a1, 32
+HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
 
 	/* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */
 	rur.threadptr	a3
@@ -83,16 +73,31 @@ _dl_tlsdesc_dynamic:
 	     + td->tlsinfo.ti_offset - __builtin_thread_pointer(); */
 	l32i	a6, a2, TLSDESC_MODOFF
 	sub	a2, a6, a3
-	retw
+	abi_ret
 
 	/* return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); */
 .Lslow:
-	mov	a10, a2
-	movi	a8, __tls_get_addr
-	callx8	a8
-	sub	a2, a10, a3
+#if defined(__XTENSA_WINDOWED_ABI__)
+	mov	a6, a2
+	movi	a4, __tls_get_addr
+	callx4	a4
+	sub	a2, a6, a3
 	retw
-	.size	_dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
+#elif defined(__XTENSA_CALL0_ABI__)
+	addi	a1, a1, -16
+	s32i	a0, a1, 0
+	s32i	a3, a1, 4
+	movi	a0, __tls_get_addr
+	callx0	a0
+	l32i	a3, a1, 4
+	l32i	a0, a1, 0
+	sub	a2, a2, a3
+	addi	a1, a1, 16
+	ret
+#else
+#error Unsupported Xtensa ABI
+#endif
+END (_dl_tlsdesc_dynamic)
 
 #endif /* SHARED */
 #endif

+ 35 - 0
ldso/ldso/xtensa/resolve.S

@@ -31,6 +31,7 @@
 	.global	_dl_linux_resolve
 	.type	_dl_linux_resolve, @function
 _dl_linux_resolve:
+#if defined(__XTENSA_WINDOWED_ABI__)
 	/* Call the fixup function.  */
 	movi	a8, _dl_linux_resolver
 	callx8	a8
@@ -47,4 +48,38 @@ _dl_linux_resolve:
 	/* Jump to the next instruction past the ENTRY.  */
 	addi	a10, a10, 3
 	jx	a10
+#elif defined(__XTENSA_CALL0_ABI__)
+	/* Reserve stack space and save incoming arguments.  */
+	addi	a1, a1, -32
+	s32i	a0, a1, 0
+	s32i	a2, a1, 8
+	s32i	a3, a1, 12
+	s32i	a4, a1, 16
+	s32i	a5, a1, 20
+	s32i	a6, a1, 24
+	s32i	a7, a1, 28
+
+	/* Move arguments for the _dl_linux_resolver to proper registers.  */
+	mov	a2, a10
+	mov	a3, a11
+	/* Call the fixup function.  */
+	movi	a0, _dl_linux_resolver
+	callx0	a0
+	mov	a10, a2
+
+	/* Restore incoming arguments from stack and deallocate reservation.  */
+	l32i	a0, a1, 0
+	l32i	a2, a1, 8
+	l32i	a3, a1, 12
+	l32i	a4, a1, 16
+	l32i	a5, a1, 20
+	l32i	a6, a1, 24
+	l32i	a7, a1, 28
+	addi	a1, a1, 32
+
+	/* Jump to the target function.  */
+	jx	a10
+#else
+#error Unsupported Xtensa ABI
+#endif
 	.size	_dl_linux_resolve, . - _dl_linux_resolve

+ 8 - 8
libc/string/xtensa/memcpy.S

@@ -91,7 +91,7 @@ __memcpy_aux:
 #if !XCHAL_HAVE_LOOPS
 	blt	a3, a7, 1b
 #endif
-2:	retw
+2:	abi_ret
 
 
 /* Destination is unaligned.  */
@@ -181,7 +181,7 @@ ENTRY (memcpy)
 3:	bbsi.l	a4, 2, 4f
 	bbsi.l	a4, 1, 5f
 	bbsi.l	a4, 0, 6f
-	retw
+	abi_ret
 
 	/* Copy 4 bytes.  */
 4:	l32i	a6, a3, 0
@@ -190,7 +190,7 @@ ENTRY (memcpy)
 	addi	a5, a5, 4
 	bbsi.l	a4, 1, 5f
 	bbsi.l	a4, 0, 6f
-	retw
+	abi_ret
 
 	/* Copy 2 bytes.  */
 5:	l16ui	a6, a3, 0
@@ -198,14 +198,14 @@ ENTRY (memcpy)
 	s16i	a6, a5, 0
 	addi	a5, a5, 2
 	bbsi.l	a4, 0, 6f
-	retw
+	abi_ret
 
 	/* Copy 1 byte.  */
 6:	l8ui	a6, a3, 0
 	s8i	a6, a5, 0
 
 .Ldone:
-	retw
+	abi_ret
 
 
 /* Destination is aligned; source is unaligned.  */
@@ -276,7 +276,7 @@ ENTRY (memcpy)
 #endif
 	bbsi.l	a4, 1, 5f
 	bbsi.l	a4, 0, 6f
-	retw
+	abi_ret
 
 	/* Copy 2 bytes.  */
 5:	l8ui	a6, a3, 0
@@ -286,11 +286,11 @@ ENTRY (memcpy)
 	s8i	a7, a5, 1
 	addi	a5, a5, 2
 	bbsi.l	a4, 0, 6f
-	retw
+	abi_ret
 
 	/* Copy 1 byte.  */
 6:	l8ui	a6, a3, 0
 	s8i	a6, a5, 0
-	retw
+	abi_ret
 
 libc_hidden_def (memcpy)

+ 2 - 2
libc/string/xtensa/memset.S

@@ -63,7 +63,7 @@ __memset_aux:
 #if !XCHAL_HAVE_LOOPS
 	blt	a5, a6, 1b
 #endif
-2:	retw
+2:	abi_ret
 
 
 /* Destination is unaligned.  */
@@ -159,6 +159,6 @@ ENTRY (memset)
 
 	/* Set 1 byte.  */
 	s8i	a3, a5, 0
-6:	retw
+6:	abi_ret
 
 libc_hidden_def (memset)

+ 10 - 10
libc/string/xtensa/strcmp.S

@@ -108,7 +108,7 @@ ENTRY (strcmp)
 #endif
 .Lretdiff:
 	sub	a2, a8, a9
-	retw
+	abi_ret
 
 /* s1 is word-aligned; s2 is word-aligned.
 
@@ -229,7 +229,7 @@ ENTRY (strcmp)
 
 	/* Words are equal; some byte is zero.  */
 .Leq:	movi	a2, 0		/* return equal */
-	retw
+	abi_ret
 
 .Lwne2:	/* Words are not equal.  On big-endian processors, if none of the
 	   bytes are zero, the return value can be determined by a simple
@@ -239,10 +239,10 @@ ENTRY (strcmp)
 	bnall	a10, a7, .Lsomezero
 	bgeu	a8, a9, .Lposreturn
 	movi	a2, -1
-	retw
+	abi_ret
 .Lposreturn:
 	movi	a2, 1
-	retw
+	abi_ret
 .Lsomezero:	/* There is probably some zero byte. */
 #endif /* __XTENSA_EB__ */
 .Lwne:	/* Words are not equal.  */
@@ -263,14 +263,14 @@ ENTRY (strcmp)
 	   byte.  Just subtract words to get the return value.
 	   The high order equal bytes cancel, leaving room for the sign.  */
 	sub	a2, a8, a9
-	retw
+	abi_ret
 
 .Ldiff0:
 	/* Need to make room for the sign, so can't subtract whole words.  */
 	extui	a10, a8, 24, 8
 	extui	a11, a9, 24, 8
 	sub	a2, a10, a11
-	retw
+	abi_ret
 
 #else /* !__XTENSA_EB__ */
 	/* Little-endian is a little more difficult because can't subtract
@@ -281,28 +281,28 @@ ENTRY (strcmp)
 	extui	a10, a8, 24, 8
 	extui	a11, a9, 24, 8
 	sub	a2, a10, a11
-	retw
+	abi_ret
 
 .Ldiff0:
 	/* Byte 0 is different.  */
 	extui	a10, a8, 0, 8
 	extui	a11, a9, 0, 8
 	sub	a2, a10, a11
-	retw
+	abi_ret
 
 .Ldiff1:
 	/* Byte 0 is equal; byte 1 is different.  */
 	extui	a10, a8, 8, 8
 	extui	a11, a9, 8, 8
 	sub	a2, a10, a11
-	retw
+	abi_ret
 
 .Ldiff2:
 	/* Bytes 0-1 are equal; byte 2 is different.  */
 	extui	a10, a8, 16, 8
 	extui	a11, a9, 16, 8
 	sub	a2, a10, a11
-	retw
+	abi_ret
 
 #endif /* !__XTENSA_EB */
 

+ 6 - 6
libc/string/xtensa/strcpy.S

@@ -68,7 +68,7 @@ ENTRY (strcpy)
 	s8i	a8, a10, 1	/* store byte 0 */
 	addi	a10, a10, 2	/* advance dst pointer */
 	bnez	a8, .Lsrcaligned
-1:	retw
+1:	abi_ret
 
 
 /* dst is word-aligned; src is word-aligned.  */
@@ -102,21 +102,21 @@ ENTRY (strcpy)
 #endif /* !XCHAL_HAVE_LOOPS */
 
 .Lz3:	/* Byte 3 is zero.  */
-	retw
+	abi_ret
 
 .Lz0:	/* Byte 0 is zero.  */
 #ifdef __XTENSA_EB__
 	movi	a8, 0
 #endif
 	s8i	a8, a10, 0
-	retw
+	abi_ret
 
 .Lz1:	/* Byte 1 is zero.  */
 #ifdef __XTENSA_EB__
         extui   a8, a8, 16, 16
 #endif
 	s16i	a8, a10, 0
-	retw
+	abi_ret
 
 .Lz2:	/* Byte 2 is zero.  */
 #ifdef __XTENSA_EB__
@@ -125,7 +125,7 @@ ENTRY (strcpy)
 	s16i	a8, a10, 0
 	movi	a8, 0
 	s8i	a8, a10, 2
-	retw
+	abi_ret
 
 	.align	4
 	/* (2 mod 4) alignment for loop instruction */
@@ -144,6 +144,6 @@ ENTRY (strcpy)
 #else
 	bnez	a8, 1b
 #endif
-2:	retw
+2:	abi_ret
 
 libc_hidden_def (strcpy)

+ 4 - 4
libc/string/xtensa/strlen.S

@@ -59,7 +59,7 @@ ENTRY (strlen)
 	/* Byte 3 is zero.  */
 	addi	a3, a3, 3	/* point to zero byte */
 	sub	a2, a3, a2	/* subtract to get length */
-	retw
+	abi_ret
 
 
 /* String is word-aligned.  */
@@ -88,16 +88,16 @@ ENTRY (strlen)
 
 .Lz0:	/* Byte 0 is zero.  */
 	sub	a2, a3, a2	/* subtract to get length */
-	retw
+	abi_ret
 
 .Lz1:	/* Byte 1 is zero.  */
 	addi	a3, a3, 1	/* point to zero byte */
 	sub	a2, a3, a2	/* subtract to get length */
-	retw
+	abi_ret
 
 .Lz2:	/* Byte 2 is zero.  */
 	addi	a3, a3, 2	/* point to zero byte */
 	sub	a2, a3, a2	/* subtract to get length */
-	retw
+	abi_ret
 
 libc_hidden_def (strlen)

+ 3 - 3
libc/string/xtensa/strncpy.S

@@ -67,7 +67,7 @@ __strncpy_aux:
 	j	.Lfill
 
 .Lret:
-	retw
+	abi_ret
 
 
 ENTRY (strncpy)
@@ -129,7 +129,7 @@ ENTRY (strncpy)
 	addi	a10, a10, 1
 	bnez    a4, .Lfillcleanup
 
-2:	retw
+2:	abi_ret
 
 .Lfill1mod2: /* dst address is odd */
 	s8i	a9, a10, 0	/* store byte 0 */
@@ -235,6 +235,6 @@ ENTRY (strncpy)
 #endif
 2:	j	.Lfill
 
-3:	retw
+3:	abi_ret
 
 libc_hidden_def (strncpy)

+ 17 - 0
libc/sysdeps/linux/xtensa/__longjmp.S

@@ -48,6 +48,7 @@
 
 ENTRY (__longjmp)
 
+#if defined(__XTENSA_WINDOWED_ABI__)
 	/* Invalidate all but the current window.  Reading and writing
 	   special registers WINDOWBASE and WINDOWSTART are
 	   privileged operations, so user processes must call the
@@ -120,6 +121,22 @@ ENTRY (__longjmp)
 	movnez	a2, a3, a3
 
 	retw
+#elif defined(__XTENSA_CALL0_ABI__)
+	l32i	a0, a2, 0
+	l32i	a1, a2, 4
+	l32i	a12, a2, 8
+	l32i	a13, a2, 12
+	l32i	a14, a2, 16
+	l32i	a15, a2, 20
+
+	/* Return v ? v : 1.  */
+	movi	a2, 1
+	movnez	a2, a3, a3
+
+	ret
+#else
+#error Unsupported Xtensa ABI
+#endif
 END (__longjmp)
 
 libc_hidden_def (__longjmp)

+ 9 - 0
libc/sysdeps/linux/xtensa/bits/setjmp.h

@@ -23,6 +23,7 @@
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
+#if defined(__XTENSA_WINDOWED_ABI__)
 /* The jmp_buf structure for Xtensa holds the following (where "proc"
    is the procedure that calls setjmp): 4-12 registers from the window
    of proc, the 4 words from the save area at proc's $sp (in case a
@@ -30,5 +31,13 @@
    proc.  Everything else is saved on the stack in the normal save areas.  */
 
 typedef int __jmp_buf[17];
+#elif defined(__XTENSA_CALL0_ABI__)
+/* The jmp_buf structure for Xtensa Call0 ABI holds the return address,
+   the stack pointer and callee-saved registers (a12 - a15).  */
+
+typedef int __jmp_buf[6];
+#else
+#error Unsupported Xtensa ABI
+#endif
 
 #endif	/* bits/setjmp.h */

+ 15 - 6
libc/sysdeps/linux/xtensa/clone.S

@@ -51,7 +51,7 @@ ENTRY (__clone)
 	mov	a8, a6			/* use a8 as a temp */
 	mov	a6, a4
 	mov	a4, a8
-	l32i	a8, a1, 16		/* child_tid */
+	l32i	a8, a1, FRAMESIZE	/* child_tid */
 	movi	a2, SYS_ify(clone)
 
 	/* syscall(NR_clone,clone_flags, usp, parent_tid, child_tls, child_tid)
@@ -65,7 +65,7 @@ ENTRY (__clone)
 	/* fall through for parent */
 
 .Lpseudo_end:
-	retw
+	abi_ret
 
 .Leinval:
 	movi	a2, -EINVAL
@@ -94,17 +94,26 @@ ENTRY (__clone)
 
 	/* start child thread */
 	movi	a0, 0			/* terminate the stack frame */
+
+#if defined(__XTENSA_WINDOWED_ABI__)
 	mov	a6, a9			/* load up the 'arg' parameter */
 	callx4	a7			/* call the user's function */
 
 	/* Call _exit.  Note that any return parameter from the user's
 	   function in a6 is seen as inputs to _exit. */
-#ifdef	PIC
-	movi	a2, _exit@PLT
+	movi	a2, JUMPTARGET(_exit)
+	callx4	a2
+#elif defined(__XTENSA_CALL0_ABI__)
+	mov	a2, a9			/* load up the 'arg' parameter */
+	callx0	a7			/* call the user's function */
+
+	/* Call _exit.  Note that any return parameter from the user's
+	   function in a2 is seen as inputs to _exit.  */
+	movi	a0, JUMPTARGET(_exit)
+	callx0	a0
 #else
-	movi	a2, _exit
+#error Unsupported Xtensa ABI
 #endif
-	callx4	a2
 
 PSEUDO_END (__clone)
 

+ 30 - 0
libc/sysdeps/linux/xtensa/crt1.S

@@ -76,6 +76,7 @@
 	.global	_start
 	.type	_start, @function
 _start:
+#if defined(__XTENSA_WINDOWED_ABI__)
 	/* Clear a0 to obviously mark the outermost frame.  */
 	movi	a0, 0
 
@@ -104,6 +105,35 @@ _start:
 	   But let the libc call main.    */
 	movi	a4, __uClibc_main
 	callx4	a4
+#elif defined(__XTENSA_CALL0_ABI__)
+	/* Setup the shared library termination function.  */
+	mov	a7, a2
+
+	/* Load up the user's main function.  */
+	movi	a2, main
+
+	/* Extract the arguments as encoded on the stack and set up
+	   the arguments for `main': argc, argv.  envp will be determined
+	   later in __uClibc_main.  */
+	l32i	a3, a1, 0	/* Load the argument count.  */
+	addi	a4, a1, 4	/* Compute the argv pointer.  */
+
+	/* Push address of our own entry points to .fini and .init.  */
+	movi	a5, _init
+	movi	a6, _fini
+
+	/* Provide the highest stack address to the user code (for stacks
+	   which grow downwards).  Note that we destroy the stack version
+	   of argc here.  */
+	s32i	a1, a1, 0
+
+	/* Call the user's main function, and exit with its value.
+	   But let the libc call main.    */
+	movi	a0, __uClibc_main
+	callx0	a0
+#else
+#error Unsupported Xtensa ABI
+#endif
 
 	/* Crash if somehow `exit' does return.  */
 	ill

+ 14 - 1
libc/sysdeps/linux/xtensa/crti.S

@@ -5,12 +5,25 @@
 	.global	_init
 	.type	_init, @function
 _init:
+#if defined(__XTENSA_WINDOWED_ABI__)
 	entry	sp, 48
-
+#elif defined(__XTENSA_CALL0_ABI__)
+	addi	sp, sp, -16
+	s32i	a0, sp, 0
+#else
+#error Unsupported Xtensa ABI
+#endif
 
 	.section .fini
 	.align	4
 	.global	_fini
 	.type	_fini, @function
 _fini:
+#if defined(__XTENSA_WINDOWED_ABI__)
 	entry	sp, 48
+#elif defined(__XTENSA_CALL0_ABI__)
+	addi	sp, sp, -16
+	s32i	a0, sp, 0
+#else
+#error Unsupported Xtensa ABI
+#endif

+ 16 - 1
libc/sysdeps/linux/xtensa/crtn.S

@@ -1,8 +1,23 @@
 /* glibc's sysdeps/xtensa/elf/initfini.c used for reference [EPILOG] */
 
 	.section .init
+#if defined(__XTENSA_WINDOWED_ABI__)
 	retw
-
+#elif defined(__XTENSA_CALL0_ABI__)
+	l32i	a0, sp, 0
+	addi	sp, sp, 16
+	ret
+#else
+#error Unsupported Xtensa ABI
+#endif
 
 	.section .fini
+#if defined(__XTENSA_WINDOWED_ABI__)
 	retw
+#elif defined(__XTENSA_CALL0_ABI__)
+	l32i	a0, sp, 0
+	addi	sp, sp, 16
+	ret
+#else
+#error Unsupported Xtensa ABI
+#endif

+ 1 - 1
libc/sysdeps/linux/xtensa/mmap.S

@@ -48,7 +48,7 @@ ENTRY (__mmap)
 	bltz	a2, SYSCALL_ERROR_LABEL
 
 .Lpseudo_end:
-	retw
+	abi_ret
 
 PSEUDO_END (__mmap)
 

+ 17 - 0
libc/sysdeps/linux/xtensa/setjmp.S

@@ -88,6 +88,7 @@ END (setjmp)
 
 ENTRY (__sigsetjmp)
 1:
+#if defined(__XTENSA_WINDOWED_ABI__)
 	/* Flush registers.  */
 	movi	a4, __window_spill
 	callx4	a4
@@ -146,6 +147,22 @@ ENTRY (__sigsetjmp)
 	callx4	a3
 	mov	a2, a6
 	retw
+#elif defined(__XTENSA_CALL0_ABI__)
+	s32i	a0, a2, 0
+	s32i	a1, a2, 4
+	s32i	a12, a2, 8
+	s32i	a13, a2, 12
+	s32i	a14, a2, 16
+	s32i	a15, a2, 20
+	mov	a12, a2
+	movi	a0, __sigjmp_save
+	callx0	a0
+	l32i	a0, a12, 0
+	l32i	a12, a12, 8
+	ret
+#else
+#error Unsupported Xtensa ABI
+#endif
 END(__sigsetjmp)
 
 weak_extern(_setjmp)

+ 2 - 2
libc/sysdeps/linux/xtensa/syscall.S

@@ -26,7 +26,7 @@
  */
 
 ENTRY (syscall)
-	l32i	a9, a1, 16	/* load extra argument from stack */
+	l32i	a9, a1, FRAMESIZE/* load extra argument from stack */
 	mov	a8, a7
 	mov	a7, a3		/* preserve a3 in a7 */
 	mov	a3, a4
@@ -37,5 +37,5 @@ ENTRY (syscall)
 	movi    a4, -4095
 	bgeu    a2, a4, SYSCALL_ERROR_LABEL
 .Lpseudo_end:
-	retw
+	abi_ret
 PSEUDO_END (syscall)

+ 41 - 4
libc/sysdeps/linux/xtensa/sysdep.h

@@ -28,13 +28,24 @@
 #define ASM_TYPE_DIRECTIVE(name, typearg) .type name, typearg
 #define ASM_SIZE_DIRECTIVE(name) .size name, . - name
 
+#if defined(__XTENSA_WINDOWED_ABI__)
+#define abi_entry(reg, frame_size) entry reg, frame_size
+#define abi_ret retw
+#elif defined(__XTENSA_CALL0_ABI__)
+#define abi_entry(reg, frame_size)
+#define abi_ret ret
+#else
+#error Unsupported Xtensa ABI
+#endif
+
+
 #define	ENTRY(name)							\
   ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				\
   ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function);			\
   .align ALIGNARG(2);							\
   LITERAL_POSITION;							\
   C_LABEL(name)								\
-  entry sp, FRAMESIZE;							\
+  abi_entry(sp, FRAMESIZE);						\
   CALL_MCOUNT
 
 #define	HIDDEN_ENTRY(name)						\
@@ -44,7 +55,7 @@
   .align ALIGNARG(2);							\
   LITERAL_POSITION;							\
   C_LABEL(name)								\
-  entry sp, FRAMESIZE;							\
+  abi_entry(sp, FRAMESIZE);						\
   CALL_MCOUNT
 
 #undef END
@@ -73,7 +84,13 @@
 #endif
 
 #ifndef FRAMESIZE
+#if defined(__XTENSA_WINDOWED_ABI__)
 #define FRAMESIZE 16
+#elif defined(__XTENSA_CALL0_ABI__)
+#define FRAMESIZE 0
+#else
+#error Unsupported Xtensa ABI
+#endif
 #endif
 #define CALL_MCOUNT		/* Do nothing.  */
 
@@ -118,7 +135,7 @@
   END (name)
 
 #undef	ret_NOERRNO
-#define ret_NOERRNO retw
+#define ret_NOERRNO abi_ret
 
 /* The function has to return the error code.  */
 #undef	PSEUDO_ERRVAL
@@ -133,7 +150,7 @@
   END (name)
 
 #undef	ret_ERRVAL
-#define ret_ERRVAL retw
+#define ret_ERRVAL abi_ret
 
 #if defined _LIBC_REENTRANT
 # if defined USE___THREAD
@@ -151,6 +168,8 @@
 	movi	a2, -1;							      \
 	j	.Lpseudo_end;
 # else /* !USE___THREAD */
+
+#if defined(__XTENSA_WINDOWED_ABI__)
 #  define SYSCALL_ERROR_HANDLER						      \
 0:	neg	a2, a2;							      \
 	mov	a6, a2;							      \
@@ -159,6 +178,24 @@
 	s32i	a2, a6, 0;						      \
 	movi	a2, -1;							      \
 	j	.Lpseudo_end;
+#elif defined(__XTENSA_CALL0_ABI__)
+#  define SYSCALL_ERROR_HANDLER						      \
+0:	neg	a2, a2;							      \
+	addi	a1, a1, -16;						      \
+	s32i	a0, a1, 0;						      \
+	s32i	a2, a1, 4;						      \
+	movi	a0, __errno_location@PLT;				      \
+	callx0	a0;						              \
+	l32i	a0, a1, 0;						      \
+	l32i	a3, a1, 4;						      \
+	addi	a1, a1, 16;						      \
+	s32i	a3, a2, 0;						      \
+	movi	a2, -1;							      \
+	j	.Lpseudo_end;
+#else
+#error Unsupported Xtensa ABI
+#endif
+
 # endif /* !USE___THREAD */
 #else /* !_LIBC_REENTRANT */
 #define SYSCALL_ERROR_HANDLER						      \

+ 23 - 0
libc/sysdeps/linux/xtensa/vfork.S

@@ -51,6 +51,8 @@
 
 
 HIDDEN_ENTRY (__vfork)
+
+#if defined(__XTENSA_WINDOWED_ABI__)
         .literal .Ljumptable, 0, .L4, .L8, .L12
 
 	mov	a3, a0			# move return address out of the way
@@ -163,6 +165,27 @@ HIDDEN_ENTRY (__vfork)
 	PSEUDO_END (__vfork)
 .Lpseudo_end:
 	retw
+#elif defined(__XTENSA_CALL0_ABI__)
+	SAVE_PID(a5, a8, a3, a4)
+
+	/* Use syscall 'clone'.  Set new stack pointer to the same address.  */
+	movi	a2, SYS_ify (clone)
+	movi	a3, 0
+	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
+	syscall
+
+	RESTORE_PID(a5, a8, a2)
+
+	movi	a3, -4096
+	bgeu	a2, a3, 1f
+	ret
+1:
+	PSEUDO_END (__vfork)
+.Lpseudo_end:
+	ret
+#else
+#error Unsupported Xtensa ABI
+#endif
 
 weak_alias (__vfork, vfork)
 libc_hidden_def(vfork)

+ 3 - 0
libc/sysdeps/linux/xtensa/windowspill.S

@@ -18,6 +18,7 @@
 
 #include <bits/xtensa-config.h>
 
+#ifdef __XTENSA_WINDOWED_ABI__
 	.text
 	.align  4
 	.literal_position
@@ -93,3 +94,5 @@ __window_spill:
 #endif
 #endif
 	retw
+
+#endif

+ 59 - 5
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h

@@ -25,6 +25,7 @@
 
 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
 
+#if defined(__XTENSA_WINDOWED_ABI__)
 /* CENABLE/CDISABLE in PSEUDO below use call8, stack frame size must be
  * at least 32.
  */
@@ -58,6 +59,64 @@
     j        SYSCALL_ERROR_LABEL;					      \
   .Lpseudo_end:
 
+# define CENABLE	movi    a8, CENABLE_FUNC;		\
+			callx8  a8
+# define CDISABLE	movi    a8, CDISABLE_FUNC;		\
+			callx8  a8
+#elif defined(__XTENSA_CALL0_ABI__)
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+    SINGLE_THREAD_P(a10);						      \
+    bnez     a10, .Lpseudo_cancel;					      \
+    DO_CALL (syscall_name, args);					      \
+    bgez     a2, .Lpseudo_done;						      \
+    movi     a4, -4095;							      \
+    blt      a2, a4, .Lpseudo_done;					      \
+    j        SYSCALL_ERROR_LABEL;					      \
+  .Lpseudo_done:							      \
+    ret;								      \
+  .Lpseudo_cancel:							      \
+    addi     a1, a1, -32;						      \
+    /* The syscall args are in a2...a7; save them */			      \
+    s32i     a0, a1, 0;							      \
+    s32i     a2, a1, 4;							      \
+    s32i     a3, a1, 8;							      \
+    s32i     a4, a1, 12;						      \
+    s32i     a5, a1, 16;						      \
+    s32i     a6, a1, 20;						      \
+    s32i     a7, a1, 24;						      \
+    CENABLE;								      \
+    /* Move return value to a10 preserved across the syscall */		      \
+    mov      a10, a2;							      \
+    l32i     a2, a1, 4;							      \
+    l32i     a3, a1, 8;							      \
+    l32i     a4, a1, 12;						      \
+    l32i     a5, a1, 16;						      \
+    l32i     a6, a1, 20;						      \
+    l32i     a7, a1, 24;						      \
+    DO_CALL (syscall_name, args);					      \
+    s32i     a2, a1, 4;							      \
+    mov      a2, a10;							      \
+    CDISABLE;								      \
+    l32i     a2, a1, 4;							      \
+    l32i     a0, a1, 0;							      \
+    addi     a1, a1, 32;						      \
+    bgez     a2, .Lpseudo_end;                                                \
+    movi     a4, -4095;							      \
+    blt      a2, a4, .Lpseudo_end;                                            \
+    j        SYSCALL_ERROR_LABEL;					      \
+  .Lpseudo_end:
+
+# define CENABLE	movi    a0, CENABLE_FUNC;		\
+			callx0  a0
+# define CDISABLE	movi    a0, CDISABLE_FUNC;		\
+			callx0  a0
+#else
+#error Unsupported Xtensa ABI
+#endif
 
 # ifdef IS_IN_libpthread
 #  define CENABLE_FUNC	__pthread_enable_asynccancel
@@ -74,11 +133,6 @@
 #  error Unsupported library
 # endif
 
-# define CENABLE	movi    a8, CENABLE_FUNC;		\
-			callx8  a8
-# define CDISABLE	movi    a8, CDISABLE_FUNC;		\
-			callx8  a8
-
 # if defined IS_IN_libpthread || !defined NOT_IN_libc
 #  ifndef __ASSEMBLER__
 extern int __local_multiple_threads attribute_hidden;

+ 5 - 9
libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S

@@ -16,13 +16,10 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-	.text
-	.align 4
-
-	.globl pthread_spin_lock
-pthread_spin_lock:
+#include <sysdep.h>
 
-	entry	a1, 16
+	.text
+ENTRY (pthread_spin_lock)
 
 	movi	a3, 0
 	wsr 	a3, scompare1
@@ -31,7 +28,6 @@ pthread_spin_lock:
 	bnez	a3, 1b
 	movi	a2, 0
 
-	retw
+	abi_ret
 
-	.type pthread_spin_lock, @function
-	.size pthread_spin_lock, .-pthread_spin_lock
+END (pthread_spin_lock)

+ 4 - 9
libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S

@@ -18,14 +18,10 @@
 
 #define _ERRNO_H 1
 #include <bits/errno.h>
+#include <sysdep.h>
 
 	.text
-	.align 4
-
-	.globl pthread_spin_trylock
-pthread_spin_trylock:
-
-	entry	a1, 16
+ENTRY (pthread_spin_trylock)
 
 	movi	a3, 0
 	wsr 	a3, scompare1
@@ -34,7 +30,6 @@ pthread_spin_trylock:
 	movi	a2, EBUSY
 	moveqz	a2, a3, a3
 
-	retw
+	abi_ret
 
-	.type pthread_spin_trylock, @function
-	.size pthread_spin_trylock, .-pthread_spin_trylock
+END (pthread_spin_trylock)

+ 27 - 0
test/tls/tls-macros.h

@@ -887,6 +887,7 @@ register void *__gp __asm__("$29");
 
 #elif defined __xtensa__
 
+#if defined(__XTENSA_WINDOWED_ABI__)
 #define TLS_GD(x)							\
   ({ int *__l;								\
      __asm__ ("movi  a8, " #x "@TLSFUNC\n\t"				\
@@ -909,6 +910,32 @@ register void *__gp __asm__("$29");
 	  :								\
 	  : "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15");	\
       __l; })
+#elif defined(__XTENSA_CALL0_ABI__)
+#define TLS_GD(x)							\
+  ({ int *__l;								\
+     __asm__ ("movi  a0, " #x "@TLSFUNC\n\t"				\
+	  "movi a2, " #x "@TLSARG\n\t"					\
+	  "callx0.tls a0, " #x "@TLSCALL\n\t"				\
+	  "mov %0, a2\n\t"						\
+	  : "=r" (__l)							\
+	  :								\
+	  : "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11");\
+      __l; })
+
+#define TLS_LD(x)							\
+  ({ int *__l;								\
+     __asm__ ("movi  a0, _TLS_MODULE_BASE_@TLSFUNC\n\t"			\
+	  "movi a2, _TLS_MODULE_BASE_@TLSARG\n\t"			\
+	  "callx0.tls a0, _TLS_MODULE_BASE_@TLSCALL\n\t"		\
+	  "movi %0, " #x "@TPOFF\n\t"					\
+	  "add %0, %0, a2\n\t"						\
+	  : "=r" (__l)							\
+	  :								\
+	  : "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11");\
+      __l; })
+#else
+#error Unsupported Xtensa ABI
+#endif
 
 #define TLS_IE(x) TLS_LE(x)