Skip to content

Commit 43bf1e5

Browse files
committed
New runtime library: libchkstk
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.
1 parent 103b45d commit 43bf1e5

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

Dockerfile

+4-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ RUN sha256sum -c $PREFIX/src/SHA256SUMS \
5959
&& tar xJf nasm-$NASM_VERSION.tar.xz \
6060
&& tar xjf vim-$VIM_VERSION.tar.bz2 \
6161
&& tar xzf cppcheck-$CPPCHECK_VERSION.tar.gz
62-
COPY src/w64devkit.c src/w64devkit.ico src/libmemory.c \
62+
COPY src/w64devkit.c src/w64devkit.ico src/libmemory.c src/libchkstk.S \
6363
src/alias.c src/debugbreak.c src/pkg-config.c src/vc++filt.c \
6464
$PREFIX/src/
6565

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

127127
RUN mkdir -p $PREFIX/$ARCH/lib \
128128
&& CC=$ARCH-gcc DESTDIR=$PREFIX/$ARCH/lib/ sh $PREFIX/src/libmemory.c \
129-
&& ln $PREFIX/$ARCH/lib/libmemory.a /bootstrap/$ARCH/lib/
129+
&& ln $PREFIX/$ARCH/lib/libmemory.a /bootstrap/$ARCH/lib/ \
130+
&& CC=$ARCH-gcc DESTDIR=$PREFIX/$ARCH/lib/ sh $PREFIX/src/libchkstk.S \
131+
&& ln $PREFIX/$ARCH/lib/libchkstk.a /bootstrap/$ARCH/lib/
130132

131133
WORKDIR /x-mingw-crt
132134
RUN /mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ executables. Unique to w64devkit, `libmemory.a` is a library of `memset`,
7373
instructions. When [not linking a CRT][crt], linking `-lmemory` provides
7474
tiny definitions, particularly when GCC requires them.
7575

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

7884
Only C and C++ are included by default, but w64devkit also has full

src/libchkstk.S

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#if 0
2+
# Implementations of ___chkstk_ms (GCC) and __chkstk (MSVC). Unlike
3+
# libgcc, no work happens if the stack is already committed. Execute
4+
# this source with a shell to build libchkstk.a.
5+
# This is free and unencumbered software released into the public domain.
6+
set -ex
7+
${CC:-cc} -c -DCHKSTK_MS -Wa,--no-pad-sections -o chkstk_ms.o $0
8+
${CC:-cc} -c -DCHKSTK -Wa,--no-pad-sections -o chkstk.o $0
9+
rm -f "${DESTDIR}libchkstk.a"
10+
ar r "${DESTDIR}libchkstk.a" chkstk_ms.o chkstk.o
11+
rm chkstk_ms.o chkstk.o
12+
exit 0
13+
#endif
14+
15+
#if __amd64
16+
// On x64, ___chkstk_ms and __chkstk have identical semantics. Unlike
17+
// x86 __chkstk, neither adjusts the stack pointer. This implementation
18+
// preserves all registers.
19+
//
20+
// The frame size is passed in rax, and this function ensures that
21+
// enough of the stack is committed for the frame. It commits stack
22+
// pages by writing to the guard page, one page at a time.
23+
# if CHKSTK_MS
24+
.globl ___chkstk_ms
25+
___chkstk_ms:
26+
# elif CHKSTK
27+
.globl __chkstk
28+
__chkstk:
29+
# endif
30+
push %rax
31+
push %rcx
32+
neg %rax // rax = frame low address
33+
add %rsp, %rax // "
34+
mov %gs:(0x10), %rcx // rcx = stack low address
35+
jmp 1f
36+
0: sub $0x1000, %rcx // extend stack into guard page
37+
test %eax, (%rcx) // commit page (two instruction bytes)
38+
1: cmp %rax, %rcx
39+
ja 0b
40+
pop %rcx
41+
pop %rax
42+
ret
43+
#endif // __amd64
44+
45+
#if __i386
46+
# if CHKSTK_MS
47+
// Behaves exactly like x64 ___chkstk_ms.
48+
.globl ___chkstk_ms
49+
___chkstk_ms:
50+
push %eax
51+
push %ecx
52+
neg %eax // eax = frame low address
53+
add %esp, %eax // "
54+
mov %fs:(0x08), %ecx // ecx = stack low address
55+
jmp 1f
56+
0: sub $0x1000, %ecx // extend stack into guard page
57+
test %eax, (%ecx) // commit page (two instruction bytes)
58+
1: cmp %eax, %ecx
59+
ja 0b
60+
sub %esp, %eax
61+
pop %ecx
62+
pop %eax
63+
ret
64+
# elif CHKSTK
65+
// On x86, __chkstk allocates the new stack frame. This implementation
66+
// clobbers eax. MSVC only seems to care about ebp and ecx (this).
67+
.globl __chkstk
68+
__chkstk:
69+
push %ecx // preserve ecx
70+
neg %eax // eax = frame low address
71+
lea 8(%esp,%eax), %eax // "
72+
mov %fs:(0x08), %ecx // ecx = stack low address
73+
jmp 1f
74+
0: sub $0x1000, %ecx // extend stack into guard page
75+
test %eax, (%ecx) // commit page (two instruction bytes)
76+
1: cmp %eax, %ecx
77+
ja 0b
78+
pop %ecx // restore ecx
79+
xchg %eax, %esp // allocate frame
80+
jmp *(%eax) // return
81+
# endif
82+
#endif // __i386

0 commit comments

Comments
 (0)