|
| 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