From 57a459bb7f3c6652102e44a89874b2708fa68885 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Tue, 14 Jun 2022 17:59:08 +0300 Subject: [PATCH] Main: libc/include/setjmp.h: Implement setjmp/longjmp --- COPYING | 6 +++++- common/printf_orig.yml | 2 ++ libc/Makefile.am | 14 ++++++++++++++ libc/include/setjmp.h | 12 +++++++++++- libc/src/asm/i386/longjmp.S | 24 ++++++++++++++++++++++++ libc/src/asm/i386/setjmp.S | 24 ++++++++++++++++++++++++ libc/src/asm/x86_64/longjmp.S | 26 ++++++++++++++++++++++++++ libc/src/asm/x86_64/setjmp.S | 27 +++++++++++++++++++++++++++ src/printf.c | 2 ++ src/printf_fmt.c | 2 ++ 10 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 libc/src/asm/i386/longjmp.S create mode 100644 libc/src/asm/i386/setjmp.S create mode 100644 libc/src/asm/x86_64/longjmp.S create mode 100644 libc/src/asm/x86_64/setjmp.S diff --git a/COPYING b/COPYING index 9dfa28c..f9c6c04 100644 --- a/COPYING +++ b/COPYING @@ -1,8 +1,12 @@ MIT License -Copyright (c) 2014-2019 Marco Paland Copyright (c) 2020-2022 Alex Kotov +Copyright (c) 2011 Nicholas J. Kain +Copyright (c) 2011-2015 Rich Felker +Copyright (c) 2014-2019 Marco Paland +Copyright (c) 2022 Alexander Monakov + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/common/printf_orig.yml b/common/printf_orig.yml index edbc11a..e2e21fa 100644 --- a/common/printf_orig.yml +++ b/common/printf_orig.yml @@ -1,3 +1,5 @@ +# The code was taken from Marco Paland's printf. + # Copyright (c) 2014-2019 Marco Paland # TODO: add remaining tests from diff --git a/libc/Makefile.am b/libc/Makefile.am index 21ae55a..d645adc 100644 --- a/libc/Makefile.am +++ b/libc/Makefile.am @@ -12,3 +12,17 @@ libc_la_SOURCES = \ src/ctype.c \ src/stdlib.c \ src/string.c + +if ASM_I386 +libc_la_SOURCES += \ + src/asm/i386/longjmp.S \ + src/asm/i386/setjmp.S +endif + +if ASM_X86_64 +libc_la_SOURCES += \ + src/asm/x86_64/longjmp.S \ + src/asm/x86_64/setjmp.S +endif + +# TODO: implement setjmp/longjmp for riscv64 diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h index 349f0f3..b46ffac 100644 --- a/libc/include/setjmp.h +++ b/libc/include/setjmp.h @@ -5,9 +5,19 @@ extern "C" { #endif -typedef int jmp_buf; +// TODO: define in architecture-specific header +typedef unsigned long __jmp_buf[sizeof(long) == 8 ? 8 : 6]; +typedef struct __jmp_buf_tag { + __jmp_buf __jb; + unsigned long __fl; + unsigned long __ss[128 / sizeof(long)]; +} jmp_buf[1]; + +__attribute__((returns_twice)) int setjmp(jmp_buf env); + +__attribute__((noreturn)) void longjmp(jmp_buf env, int val); #ifdef __cplusplus diff --git a/libc/src/asm/i386/longjmp.S b/libc/src/asm/i386/longjmp.S new file mode 100644 index 0000000..caa5340 --- /dev/null +++ b/libc/src/asm/i386/longjmp.S @@ -0,0 +1,24 @@ +/** + * The code was taken from musl libc. + * + * Copyright (c) 2011 Rich Felker + * Copyright (c) 2022 Alexander Monakov + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +.global longjmp +.type longjmp, @function +longjmp: + mov 4(%esp) , %edx + mov 8(%esp) , %eax + cmp $1 , %eax + adc $0 , %al + mov (%edx) , %ebx + mov 4(%edx) , %esi + mov 8(%edx) , %edi + mov 12(%edx) , %ebp + mov 16(%edx) , %esp + jmp *20(%edx) diff --git a/libc/src/asm/i386/setjmp.S b/libc/src/asm/i386/setjmp.S new file mode 100644 index 0000000..d993619 --- /dev/null +++ b/libc/src/asm/i386/setjmp.S @@ -0,0 +1,24 @@ +/** + * The code was taken from musl libc. + * + * Copyright (c) 2011-2015 Rich Felker + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +.global setjmp +.type setjmp, @function +setjmp: + mov 4(%esp) , %eax + mov %ebx , (%eax) + mov %esi , 4(%eax) + mov %edi , 8(%eax) + mov %ebp , 12(%eax) + lea 4(%esp) , %ecx + mov %ecx , 16(%eax) + mov (%esp) , %ecx + mov %ecx , 20(%eax) + xor %eax , %eax + ret diff --git a/libc/src/asm/x86_64/longjmp.S b/libc/src/asm/x86_64/longjmp.S new file mode 100644 index 0000000..3c4ff01 --- /dev/null +++ b/libc/src/asm/x86_64/longjmp.S @@ -0,0 +1,26 @@ +/** + * The code was taken from musl libc. + * + * Copyright (c) 2011 Nicholas J. Kain + * Copyright (c) 2011-2012 Rich Felker + * Copyright (c) 2022 Alexander Monakov + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +.global longjmp +.type longjmp, @function +longjmp: + xor %eax , %eax + cmp $1 , %esi /* CF = val ? 0 : 1 */ + adc %esi , %eax /* eax = val + !val */ + mov (%rdi) , %rbx /* rdi is the jmp_buf, restore regs from it */ + mov 8(%rdi) , %rbp + mov 16(%rdi) , %r12 + mov 24(%rdi) , %r13 + mov 32(%rdi) , %r14 + mov 40(%rdi) , %r15 + mov 48(%rdi) , %rsp + jmp *56(%rdi) /* goto saved address without altering rsp */ diff --git a/libc/src/asm/x86_64/setjmp.S b/libc/src/asm/x86_64/setjmp.S new file mode 100644 index 0000000..58eed1c --- /dev/null +++ b/libc/src/asm/x86_64/setjmp.S @@ -0,0 +1,27 @@ +/** + * The code was taken from musl libc. + * + * Copyright (c) 2011 Nicholas J. Kain + * Copyright (c) 2011-2012 Rich Felker + * Copyright (c) 2022 Alexander Monakov + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +.global setjmp +.type setjmp, @function +setjmp: +mov %rbx , (%rdi) /* rdi is jmp_buf, move registers onto it */ +mov %rbp , 8(%rdi) +mov %r12 , 16(%rdi) +mov %r13 , 24(%rdi) +mov %r14 , 32(%rdi) +mov %r15 , 40(%rdi) +lea 8(%rsp) , %rdx /* this is our rsp WITHOUT current ret addr */ +mov %rdx , 48(%rdi) +mov (%rsp) , %rdx /* save return addr ptr for new rip */ +mov %rdx , 56(%rdi) +xor %eax , %eax /* always return 0 */ +ret diff --git a/src/printf.c b/src/printf.c index 685a63d..572695a 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1,4 +1,6 @@ /** + * The code was taken from Marco Paland's printf. + * * Copyright (c) 2014-2019 Marco Paland * * Tiny [v]fprintf, sfprintf and [v]snprintf implementation, optimized for speed diff --git a/src/printf_fmt.c b/src/printf_fmt.c index 3ad2870..0a2cc80 100644 --- a/src/printf_fmt.c +++ b/src/printf_fmt.c @@ -1,4 +1,6 @@ /** + * The code was taken from Marco Paland's printf. + * * Copyright (c) 2014-2019 Marco Paland */