From 938fe167d45fb6006cc9ebca376722ffa86e9af2 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Sat, 24 Dec 2022 22:54:34 +0000 Subject: [PATCH 3/3] riscv libc: fix longjmp with 0 value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On RISC-V, calling `longjmp(x, 0);` makes `setjmp(x)` return 0, which normally causes an infinite loop, and is against the ISO C standard for setjmp/longjmp. Instead, using a value of 0 should make `setjmp` return 1: > The `longjmp` function cannot cause the `setjmp` macro to return the > value 0; if `val` is 0, the `setjmp` macro returns the value 1. > > _Taken from ยง7.13.2.1.4 of the C99 spec_ --- Notes: I think I've actually managed to beat the compiler in this patch. Both GCC and Clang do something like the following at `-Os`: ```Assembly mv a0,a1 bne a1,zero,.L2 li a0,1 .L2: ret ``` It took a while of scouring the RISC-V ISA spec, but I found a method that doesn't use branching and has less one less instruction! lib/libc/riscv/gen/_setjmp.S | 8 ++++++-- lib/libc/riscv/gen/setjmp.S | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/libc/riscv/gen/_setjmp.S b/lib/libc/riscv/gen/_setjmp.S index ded6705ef7ee..6b9f4260545b 100644 --- a/lib/libc/riscv/gen/_setjmp.S +++ b/lib/libc/riscv/gen/_setjmp.S @@ -129,8 +129,12 @@ ENTRY(_longjmp) addi a0, a0, (12 * 8) #endif - /* Load the return value */ - mv a0, a1 + /* + * Load the return value. + * If the value is 0, longjmp should make setjmp() return 1, not 0. + */ + seqz a0, a1 /* a0 = (a1 == 0) ? 1 : 0; */ + add a0, a0, a1 ret botch: diff --git a/lib/libc/riscv/gen/setjmp.S b/lib/libc/riscv/gen/setjmp.S index c0458e907ce0..634f58974152 100644 --- a/lib/libc/riscv/gen/setjmp.S +++ b/lib/libc/riscv/gen/setjmp.S @@ -159,8 +159,12 @@ ENTRY(longjmp) addi a0, a0, (12 * 8) #endif - /* Load the return value */ - mv a0, a1 + /* + * Load the return value. + * If the value is 0, longjmp should make setjmp() return 1, not 0. + */ + seqz a0, a1 /* a0 = (a1 == 0) ? 1 : 0; */ + add a0, a0, a1 ret botch: -- 2.34.1