1/* Copyright (C) 2001-2021 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3
4   The GNU C Library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8
9   The GNU C Library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with the GNU C Library; if not, see
16   <https://www.gnu.org/licenses/>.  */
17
18#include <sysdep.h>
19#include <jmpbuf-offsets.h>
20#include <tcb-offsets.h>
21#include <asm-syntax.h>
22
23#include <signal-defines.h>
24/* #include <signal.h> */
25#define SS_ONSTACK 1
26
27
28	.section .rodata.str1.1,"aMS",@progbits,1
29	.type	longjmp_msg,@object
30longjmp_msg:
31	.string "longjmp causes uninitialized stack frame"
32	.size	longjmp_msg, .-longjmp_msg
33
34
35#ifdef PIC
36# define CALL_FAIL	movl	%ebx, %ecx; /* TODO: what's this mov good for? */ \
37			cfi_register(%ebx,%ecx);			      \
38			LOAD_PIC_REG (bx);				      \
39			leal	longjmp_msg@GOTOFF(%ebx), %eax;		      \
40			movl	%eax, (%esp);				      \
41			call	HIDDEN_JUMPTARGET(__fortify_fail)
42#else
43# define CALL_FAIL	movl	$longjmp_msg, %eax;			      \
44			movl	%eax, (%esp);				      \
45			call	HIDDEN_JUMPTARGET(__fortify_fail)
46#endif
47
48
49	.text
50ENTRY (____longjmp_chk)
51	movl	4(%esp), %eax	/* User's jmp_buf in %eax.  */
52
53	/* Save the return address now.  */
54	movl	(JB_PC*4)(%eax), %edx
55	/* Get the stack pointer.  */
56	movl	(JB_SP*4)(%eax), %ecx
57	cfi_undefined(%ecx)
58#ifdef PTR_DEMANGLE
59	PTR_DEMANGLE (%edx)
60	PTR_DEMANGLE (%ecx)
61#endif
62
63	movw	%ds, %si
64	movw	%gs, %di
65	cmpw	%si, %di
66	jz	.Lok		/* TLS not initialized yet */
67
68	movl	%gs:SIGSTATE_OFFSET, %edi
69	testl	%edi, %edi
70	jz	.Lok		/* sigstate not initialized yet */
71
72	testl	$SS_ONSTACK, (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_FLAGS__OFFSET)(%edi)
73	jnz	.Lonstack
74
75	/* We were on the main stack */
76
77	cmpl	%ecx, %esp
78	/* Jumping to a higher-address frame is always allowed.  */
79	jbe	.Lok
80
81	/* Otherwise it's not allowed.  */
82	CALL_FAIL
83
84.Lonstack:
85	/* We were on the alternate stack, can't really easily check anything
86	   since longjmp may get us out of the alternate stack.  */
87
88	cmpl	(HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SP__OFFSET)(%edi), %ecx
89	jb	.Loks		/* We jump below the alternate stack, switch.  */
90
91	movl	(HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SP__OFFSET)(%edi), %ebx
92	addl	(HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SIZE__OFFSET)(%edi), %ebx
93	cmpl	%ebx, %ecx
94	jb	.Lok		/* We jump inside the alternate stack, do not switch.  */
95
96	/* We jump above the alternate stack, switch.  */
97
98.Loks:	/* We jump out of the alternate stack, clear SS_ONSTACK flag.  */
99	andl	$~(SS_ONSTACK), (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_FLAGS__OFFSET)(%edi)
100
101.Lok:	/* We add unwind information for the target here.  */
102	cfi_def_cfa(%eax, 0)
103	cfi_register(%eip, %edx)
104	cfi_register(%esp, %ecx)
105	cfi_offset(%ebx, JB_BX*4)
106	cfi_offset(%esi, JB_SI*4)
107	cfi_offset(%edi, JB_DI*4)
108	cfi_offset(%ebp, JB_BP*4)
109	/* Restore registers.  */
110	movl	(JB_BX*4)(%eax), %ebx
111	movl	(JB_SI*4)(%eax), %esi
112	movl	(JB_DI*4)(%eax), %edi
113	movl	(JB_BP*4)(%eax), %ebp
114	cfi_restore(%ebx)
115	cfi_restore(%esi)
116	cfi_restore(%edi)
117	cfi_restore(%ebp)
118
119	movl	8(%esp), %eax	/* Second argument is return value.  */
120	movl	%ecx, %esp
121
122	/* Jump to saved PC.  */
123	jmp	*%edx
124END (____longjmp_chk)
125