Skip to content

Commit

Permalink
New runtime library: libchkstk
Browse files Browse the repository at this point in the history
Provides 32-bit and 64-bit ___chkstk_ms and __chkstk. The former can
replace the libgcc implementation. Better license, about half the size,
and substantially faster when used on a hot path. The purpose and role
is similar to libmemory.
  • Loading branch information
skeeto committed Feb 3, 2024
1 parent 103b45d commit 43bf1e5
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 2 deletions.
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ RUN sha256sum -c $PREFIX/src/SHA256SUMS \
&& tar xJf nasm-$NASM_VERSION.tar.xz \
&& tar xjf vim-$VIM_VERSION.tar.bz2 \
&& tar xzf cppcheck-$CPPCHECK_VERSION.tar.gz
COPY src/w64devkit.c src/w64devkit.ico src/libmemory.c \
COPY src/w64devkit.c src/w64devkit.ico src/libmemory.c src/libchkstk.S \
src/alias.c src/debugbreak.c src/pkg-config.c src/vc++filt.c \
$PREFIX/src/

Expand Down Expand Up @@ -126,7 +126,9 @@ ENV PATH="/bootstrap/bin:${PATH}"

RUN mkdir -p $PREFIX/$ARCH/lib \
&& CC=$ARCH-gcc DESTDIR=$PREFIX/$ARCH/lib/ sh $PREFIX/src/libmemory.c \
&& ln $PREFIX/$ARCH/lib/libmemory.a /bootstrap/$ARCH/lib/
&& ln $PREFIX/$ARCH/lib/libmemory.a /bootstrap/$ARCH/lib/ \
&& CC=$ARCH-gcc DESTDIR=$PREFIX/$ARCH/lib/ sh $PREFIX/src/libchkstk.S \
&& ln $PREFIX/$ARCH/lib/libchkstk.a /bootstrap/$ARCH/lib/

WORKDIR /x-mingw-crt
RUN /mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ executables. Unique to w64devkit, `libmemory.a` is a library of `memset`,
instructions. When [not linking a CRT][crt], linking `-lmemory` provides
tiny definitions, particularly when GCC requires them.

Also unique to w64devkit, `libchkstk.a` has a leaner, faster definition of
`___chkstk_ms` than GCC (`-lgcc`), as well as `__chkstk`, sometimes needed
when linking MSVC artifacts. Both are in the public domain and so, unlike
default implementations, do not involve complex licensing. When required
in a `-nostdlib` build, link `-lchkstk`.

## Fortran support

Only C and C++ are included by default, but w64devkit also has full
Expand Down
82 changes: 82 additions & 0 deletions src/libchkstk.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#if 0
# Implementations of ___chkstk_ms (GCC) and __chkstk (MSVC). Unlike
# libgcc, no work happens if the stack is already committed. Execute
# this source with a shell to build libchkstk.a.
# This is free and unencumbered software released into the public domain.
set -ex
${CC:-cc} -c -DCHKSTK_MS -Wa,--no-pad-sections -o chkstk_ms.o $0
${CC:-cc} -c -DCHKSTK -Wa,--no-pad-sections -o chkstk.o $0
rm -f "${DESTDIR}libchkstk.a"
ar r "${DESTDIR}libchkstk.a" chkstk_ms.o chkstk.o
rm chkstk_ms.o chkstk.o
exit 0
#endif

#if __amd64
// On x64, ___chkstk_ms and __chkstk have identical semantics. Unlike
// x86 __chkstk, neither adjusts the stack pointer. This implementation
// preserves all registers.
//
// The frame size is passed in rax, and this function ensures that
// enough of the stack is committed for the frame. It commits stack
// pages by writing to the guard page, one page at a time.
# if CHKSTK_MS
.globl ___chkstk_ms
___chkstk_ms:
# elif CHKSTK
.globl __chkstk
__chkstk:
# endif
push %rax
push %rcx
neg %rax // rax = frame low address
add %rsp, %rax // "
mov %gs:(0x10), %rcx // rcx = stack low address
jmp 1f
0: sub $0x1000, %rcx // extend stack into guard page
test %eax, (%rcx) // commit page (two instruction bytes)
1: cmp %rax, %rcx
ja 0b
pop %rcx
pop %rax
ret
#endif // __amd64

#if __i386
# if CHKSTK_MS
// Behaves exactly like x64 ___chkstk_ms.
.globl ___chkstk_ms
___chkstk_ms:
push %eax
push %ecx
neg %eax // eax = frame low address
add %esp, %eax // "
mov %fs:(0x08), %ecx // ecx = stack low address
jmp 1f
0: sub $0x1000, %ecx // extend stack into guard page
test %eax, (%ecx) // commit page (two instruction bytes)
1: cmp %eax, %ecx
ja 0b
sub %esp, %eax
pop %ecx
pop %eax
ret
# elif CHKSTK
// On x86, __chkstk allocates the new stack frame. This implementation
// clobbers eax. MSVC only seems to care about ebp and ecx (this).
.globl __chkstk
__chkstk:
push %ecx // preserve ecx
neg %eax // eax = frame low address
lea 8(%esp,%eax), %eax // "
mov %fs:(0x08), %ecx // ecx = stack low address
jmp 1f
0: sub $0x1000, %ecx // extend stack into guard page
test %eax, (%ecx) // commit page (two instruction bytes)
1: cmp %eax, %ecx
ja 0b
pop %ecx // restore ecx
xchg %eax, %esp // allocate frame
jmp *(%eax) // return
# endif
#endif // __i386

0 comments on commit 43bf1e5

Please sign in to comment.