1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
#if 0
# From:
# https://github.com/skeeto/w64devkit/blob/master/src/libchkstk.S
#
# because Clang on Windows generates calls to chkstk(), it is
# necessary to provide our implementation when not linking to C library.
# For details, see e.g.
# https://stackoverflow.com/questions/8400118/what-is-the-purpose-of-the-chkstk-function
#
# 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:-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
mov %gs:(0x10), %rcx // rcx = stack low address
neg %rax // rax = frame low address
add %rsp, %rax // "
jb 1f // frame low address overflow?
xor %eax, %eax // overflowed: frame low address = null
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
mov %fs:(0x08), %ecx // ecx = stack low address
neg %eax // eax = frame low address
add %esp, %eax // "
jb 1f // frame low address overflow?
xor %eax, %eax // overflowed: frame low address = null
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
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
mov %fs:(0x08), %ecx // ecx = stack low address
neg %eax // eax = frame low address
lea 8(%esp,%eax), %eax // "
cmp %esp, %eax // frame low address overflow?
jb 1f // "
xor %eax, %eax // overflowed: frame low address = null
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
|