mirror of
https://github.com/RGBCube/serenity
synced 2025-05-16 10:44:57 +00:00
LibC: Fix sigsetjmp and siglongjmp
This commit is contained in:
parent
6165811081
commit
c972afbea6
4 changed files with 139 additions and 61 deletions
|
@ -4,34 +4,67 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <bits/sighow.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// /!\ Read setjmp.h before modifying this file!
|
||||||
|
//
|
||||||
|
|
||||||
.global setjmp
|
.global setjmp
|
||||||
setjmp:
|
setjmp:
|
||||||
mov 4(%esp), %eax
|
mov 4(%esp), %ecx // Grab jmp_buf argument
|
||||||
mov %ebx, 0(%eax)
|
xor %eax, %eax // Grab val argument (hardcoded to zero)
|
||||||
mov %esi, 4(%eax)
|
jmp .Lsigset_common
|
||||||
mov %edi, 8(%eax)
|
|
||||||
mov %ebp, 12(%eax)
|
.global sigsetjmp
|
||||||
lea 4(%esp), %ecx
|
sigsetjmp:
|
||||||
mov %ecx, 16(%eax)
|
mov 4(%esp), %ecx // Grab jmp_buf argument
|
||||||
mov (%esp), %ecx
|
mov 8(%esp), %eax // Grab val argument
|
||||||
mov %ecx, 20(%eax)
|
|
||||||
|
.Lsigset_common:
|
||||||
|
mov %eax, 24(%ecx) // Store val into did_save_signal_mask
|
||||||
|
movl $0, 28(%ecx) // Clear saved_signal_mask
|
||||||
|
test %eax, %eax
|
||||||
|
jz .Lsaveregs
|
||||||
|
|
||||||
|
lea 28(%ecx), %eax // Set argument oldset
|
||||||
|
push %eax
|
||||||
|
push $0 // Set argument set
|
||||||
|
push $0 // Set argument how
|
||||||
|
call sigprocmask
|
||||||
|
add $12, %esp
|
||||||
|
|
||||||
|
.Lsaveregs:
|
||||||
|
mov (%esp), %edx // Grab return address
|
||||||
|
mov %ebx, (0 * 4)(%ecx) // Save registers
|
||||||
|
mov %esi, (1 * 4)(%ecx)
|
||||||
|
mov %edi, (2 * 4)(%ecx)
|
||||||
|
mov %ebp, (3 * 4)(%ecx)
|
||||||
|
mov %esp, (4 * 4)(%ecx)
|
||||||
|
mov %edx, (5 * 4)(%ecx)
|
||||||
xor %eax, %eax
|
xor %eax, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global longjmp
|
.global longjmp
|
||||||
longjmp:
|
longjmp:
|
||||||
mov 4(%esp), %edx
|
mov 4(%esp), %ecx // Grab jmp_buf argument
|
||||||
mov 8(%esp), %eax
|
mov 8(%esp), %eax // Grab val argument
|
||||||
mov 0(%edx), %ebx
|
|
||||||
mov 4(%edx), %esi
|
|
||||||
mov 8(%edx), %edi
|
|
||||||
mov 12(%edx), %ebp
|
|
||||||
mov 16(%edx), %ecx
|
|
||||||
mov %ecx, %esp
|
|
||||||
mov 20(%edx), %ecx
|
|
||||||
test %eax, %eax
|
test %eax, %eax
|
||||||
jnz .nonzero
|
jnz .Lnonzero
|
||||||
mov 1, %eax
|
mov $1, %eax
|
||||||
.nonzero:
|
|
||||||
jmp *%ecx
|
|
||||||
|
|
||||||
|
.Lnonzero:
|
||||||
|
mov (0 * 4)(%ecx), %ebx // Restore registers
|
||||||
|
mov (1 * 4)(%ecx), %esi
|
||||||
|
mov (2 * 4)(%ecx), %edi
|
||||||
|
mov (3 * 4)(%ecx), %ebp
|
||||||
|
//
|
||||||
|
// Until this point, the stack is still from the caller.
|
||||||
|
//
|
||||||
|
mov (4 * 4)(%ecx), %esp
|
||||||
|
mov (5 * 4)(%ecx), %edx
|
||||||
|
mov %edx, (%esp) // Patch return address
|
||||||
|
//
|
||||||
|
// From this point on, the former stack has been restored.
|
||||||
|
//
|
||||||
|
ret
|
||||||
|
|
|
@ -4,34 +4,64 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <bits/sighow.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// /!\ Read setjmp.h before modifying this file!
|
||||||
|
//
|
||||||
|
|
||||||
.global setjmp
|
.global setjmp
|
||||||
setjmp:
|
setjmp:
|
||||||
mov %rbx, (%rdi)
|
mov $0, %esi // Set val argument to 0
|
||||||
mov %rbp, 8(%rdi)
|
|
||||||
mov %r12, 16(%rdi)
|
.global sigsetjmp
|
||||||
mov %r13, 24(%rdi)
|
sigsetjmp:
|
||||||
mov %r14, 32(%rdi)
|
mov %esi, 60(%rdi) // Store val into did_save_signal_mask
|
||||||
mov %r15, 40(%rdi)
|
movl $0, 64(%rdi) // Clear saved_signal_mask
|
||||||
lea 8(%rsp), %rcx
|
test %esi, %esi
|
||||||
mov %rcx, 48(%rdi)
|
jz .Lsaveregs
|
||||||
mov (%rsp), %rcx
|
|
||||||
mov %rcx, 56(%rdi)
|
mov %rdi, %r12 // Preserve sigjmp_buf argument
|
||||||
|
mov $0, %rdi // Set argument how
|
||||||
|
mov $0, %rsi // Set argument set
|
||||||
|
lea 64(%rdi), %rdx // Set argument oldset
|
||||||
|
call sigprocmask
|
||||||
|
mov %r12, %rdi // Restore sigjmp_buf argument
|
||||||
|
|
||||||
|
.Lsaveregs:
|
||||||
|
mov %rbx, (0 * 8)(%rdi) // Save registers
|
||||||
|
mov %r12, (1 * 8)(%rdi)
|
||||||
|
mov %r13, (2 * 8)(%rdi)
|
||||||
|
mov %r14, (3 * 8)(%rdi)
|
||||||
|
mov %r15, (4 * 8)(%rdi)
|
||||||
|
mov %rbp, (5 * 8)(%rdi)
|
||||||
|
mov %rsp, (6 * 8)(%rdi)
|
||||||
|
mov (%rsp), %rax // Grab return address
|
||||||
|
mov %rax, (7 * 8)(%rdi)
|
||||||
xor %eax, %eax
|
xor %eax, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global longjmp
|
.global longjmp
|
||||||
longjmp:
|
longjmp:
|
||||||
mov (%rdi), %rbx
|
mov %esi, %eax
|
||||||
mov 8(%rdi), %rbp
|
test %eax, %eax
|
||||||
mov 16(%rdi), %r12
|
jnz .Lnonzero
|
||||||
mov 24(%rdi), %r13
|
mov $1, %eax
|
||||||
mov 32(%rdi), %r14
|
|
||||||
mov 40(%rdi), %r15
|
|
||||||
mov 48(%rdi), %rsp
|
|
||||||
|
|
||||||
test %rsi, %rsi
|
|
||||||
jnz .nonzero
|
|
||||||
mov 1, %rax
|
|
||||||
.nonzero:
|
|
||||||
jmp *56(%rdi)
|
|
||||||
|
|
||||||
|
.Lnonzero:
|
||||||
|
mov (0 * 8)(%rdi), %rbx // Restore registers
|
||||||
|
mov (1 * 8)(%rdi), %r12
|
||||||
|
mov (2 * 8)(%rdi), %r13
|
||||||
|
mov (3 * 8)(%rdi), %r14
|
||||||
|
mov (4 * 8)(%rdi), %r15
|
||||||
|
mov (5 * 8)(%rdi), %rbp
|
||||||
|
//
|
||||||
|
// Until this point, the stack is still from the caller.
|
||||||
|
//
|
||||||
|
mov (6 * 8)(%rdi), %rsp
|
||||||
|
mov (7 * 8)(%rdi), %rcx
|
||||||
|
mov %rcx, (%rsp) // Patch return address
|
||||||
|
//
|
||||||
|
// From this point on, the former stack has been restored.
|
||||||
|
//
|
||||||
|
ret
|
||||||
|
|
|
@ -14,25 +14,51 @@
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
//
|
||||||
|
// /!\ This structure is accessed inside setjmp.S, keep both files in sync!
|
||||||
|
//
|
||||||
|
|
||||||
struct __jmp_buf {
|
struct __jmp_buf {
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
uint32_t regs[6];
|
uint32_t ebx;
|
||||||
|
uint32_t esi;
|
||||||
|
uint32_t edi;
|
||||||
|
uint32_t ebp;
|
||||||
|
uint32_t esp;
|
||||||
|
uint32_t eip;
|
||||||
#elif __x86_64__
|
#elif __x86_64__
|
||||||
uint64_t regs[8];
|
uint64_t rbx;
|
||||||
|
uint64_t r12;
|
||||||
|
uint64_t r13;
|
||||||
|
uint64_t r14;
|
||||||
|
uint64_t r15;
|
||||||
|
uint64_t rbp;
|
||||||
|
uint64_t rsp;
|
||||||
|
uint64_t rip;
|
||||||
#else
|
#else
|
||||||
# error
|
# error
|
||||||
#endif
|
#endif
|
||||||
bool did_save_signal_mask;
|
int did_save_signal_mask;
|
||||||
sigset_t saved_signal_mask;
|
sigset_t saved_signal_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct __jmp_buf jmp_buf[1];
|
typedef struct __jmp_buf jmp_buf[1];
|
||||||
typedef struct __jmp_buf sigjmp_buf[1];
|
typedef struct __jmp_buf sigjmp_buf[1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calling conventions mandates that sigsetjmp() cannot call setjmp(),
|
||||||
|
* otherwise the restored calling environment will not be the original caller's
|
||||||
|
* but sigsetjmp()'s and we'll return to the wrong call site on siglongjmp().
|
||||||
|
*
|
||||||
|
* The setjmp(), sigsetjmp() and longjmp() functions have to be implemented in
|
||||||
|
* assembly because they touch the call stack and registers in non-portable
|
||||||
|
* ways. However, we *can* implement siglongjmp() as a standard C function.
|
||||||
|
*/
|
||||||
|
|
||||||
int setjmp(jmp_buf);
|
int setjmp(jmp_buf);
|
||||||
void longjmp(jmp_buf, int val);
|
__attribute__((noreturn)) void longjmp(jmp_buf, int val);
|
||||||
|
|
||||||
int sigsetjmp(sigjmp_buf, int savesigs);
|
int sigsetjmp(sigjmp_buf, int savesigs);
|
||||||
void siglongjmp(sigjmp_buf, int val);
|
__attribute__((noreturn)) void siglongjmp(sigjmp_buf, int val);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
@ -143,17 +143,6 @@ const char* sys_siglist[NSIG] = {
|
||||||
"Bad system call",
|
"Bad system call",
|
||||||
};
|
};
|
||||||
|
|
||||||
int sigsetjmp(jmp_buf env, int savesigs)
|
|
||||||
{
|
|
||||||
if (savesigs) {
|
|
||||||
int rc = sigprocmask(0, nullptr, &env->saved_signal_mask);
|
|
||||||
assert(rc == 0);
|
|
||||||
env->did_save_signal_mask = true;
|
|
||||||
} else {
|
|
||||||
env->did_save_signal_mask = false;
|
|
||||||
}
|
|
||||||
return setjmp(env);
|
|
||||||
}
|
|
||||||
void siglongjmp(jmp_buf env, int val)
|
void siglongjmp(jmp_buf env, int val)
|
||||||
{
|
{
|
||||||
if (env->did_save_signal_mask) {
|
if (env->did_save_signal_mask) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue