First, he's writing a nonportable language runtime. For Cywgin. It's not a fair critique to say "he's making the mistake of writing x86-specific code".
Second, you don't have to initialize a stack before you use it. The stack isn't magically cleared before it gets used. In fact, that's rather the point of having the stack implemented with a single pointer, and is also the reason that in C you have to explicitly initialize (say) integers before using them.
Third, there's nothing "dangerous" about what he's doing, in that what he's doing can't ever work. He created a temp stack, write code that attempts to switch into it, and never wrote the code to switch out of it. That's not going to slip into production. But that's also not a fundamental critique of the approach.
What he's trying to do works fine, including under Cygwin, when completely implemented. Despite much peanut gallery whining that it can't possibly work, or that this guy should give up on doing inline/threaded/coroutine stacks and instead implement some CS101 interpreter instead.
He said his code works on Linux but not Cygwin. Linux is not a hardware architecture. The code generated for Linux Arm is very different from Linux i386. I merely pointed out he's confused about different machine abstractions and his claim of "working on Linux" is not a good basis to expect it would work on Cygwin. Does that make sense for you?
Second, re-read what I wrote. I talked about returning from main(). I wasn't talking about sub-function calls within main(). Returning from main() will take the garbage content from the uninitialized buffer as return address and crash. And if you initialize the buffer with the correct stack frame for the function you want to jump to, you can "return" to it. That's how co-routine work, or buffer overflow attack. Does that make sense for you?
Second (b) a stack is not necessarily implemented as a single pointer. On i386, it's a double-indirect pointer EBP:ESP. He only set up ESP and forgot about EBP. Depending on how the generated code sets up the runtime environment, EBP is not necessary (most likely not) the same as the heap.
Third, whatever, it's your pure speculation. He's jumping wildly to whatever location. It's lucky it crashes rather than silently executes whatever code and format his drive.
The fact remains that what he's doing doesn't work, despite what you insist. No one says he should give up doing thread/coroutine stacks. Just his approach is wrong and non-portable. There are better ways to do coroutine.
Every technical detail you try to provide makes it seem less likely you've ever implemented any of these things.
People targeting Cygwin aren't writing for ARM. They're by and large trying to port Unix code to Win32. Meanwhile: what on earth is your point? He wants to build a language runtime on top of the native stack. You propose that he should find an arch-neutral way to do that? That's silly. This post is from 2005, before you try to muddy the waters with LLVM.
Second, like I said upthread, it's clear that it his code doesn't work. Switching stacks isn't a 2-liner. He hasn't fully implemented the concept. Nobody is arguing that his code properly restores the system stack, because he didn't implement that. What does that have to do with how malloc() initializes buffers? You don't have to provide a valid return address at the end of a synthesized stack; you can just JMP directly back to where you want to rejoin the original code --- where you switch the stack back.
The x86 stack isn't "double-indirected" through EBP. EBP is where the compiler arranges to store the base of the stack frame. C code works just fine without it; you simply fix up ESP in the function epilogue. All you lose by doing so (besides negligible overhead) is the ability to trivially dump stack traces.
Why don't you tell us how you, in 2005, would have implemented portable native-stack execution of a high level language? (Note that we're using "threaded" in two very different ways, a fact made all the more confusing by some guy on that thread's insistence that he should spawn a thread every time he needs a new stack).
For what it's worth, I'm not super comfortable tit-for-tatting your comment, except that this whole thread is about a bunch of people pooping on someone who asked for help, and many of the principles being espoused on that thread are simply bogus. I think people felt like they could be puffed-up and self-righteous because they had cover from Korn's original post. And right now, I think that about you too.
He claimed his code work on Linux but didn't work when he ported to Cygwin. He's writing a Scheme interpreter which would aim for portability one assumes. Where did he say he's doing a non-portable exclusively Cygwin implementation? Stop putting your words into his mouth to make your argument.
I specifically wrote the return address of main() was messed up in his code and that was what not working. Please point out what is wrong with that assessment. You are bringing up far fetched ideas and arguments that I didn't mention. Stop putting words in my mouth.
Ok, I made a mistake with the register name. It's ESS:ESP instead of EBP:ESP. I meant he forgot to set up the stack segment register. The stack segment is most likely different from the heap segment. Switching the ESP but not the ESS is asking for trouble.
I will NOT tell you how to implement a portable native-stack. That's not my intention. What I have done is pointing out exactly what were not working in his code. You are the one failing on reading comprehension and making wild assumption and arguing in different directions.
There is no "ESS" register on x86. You've confused the stack segment selector, which is an addressing format quirk (and which virtually never changes), with the register file. Please, stop digging.
The stack segment descriptor virtually never changes in userland protected mode code. You're not "asking for trouble" by not fucking with it. It's also not simply a pointer, unlike EBP with frame pointers. And it's called SS, not "ESS", and it's implied in stack operations.
Have you ever changed a segment register in userland code? Tell me about the code that did it and why.
And while you're at it: have you ever written code that switched stacks? You might have had to if you wrote a userland threading library, or if you wrote an exception handling system, or a coroutine library. This stuff you're critiquing this guy on the Cygwin list about: are you an expert?
I saw your Reddit comments; I believe you're a competent WinAPI C programmer. What I want to know is, do you actually know assembly? Or just have a lot of opinions about it?
Yes, I had, in both user mode or kernel mode codes. Where do you think I got the idea about stack segment register? I don't need to prove how awesome an expert I am, unlike someone. My comments remain as they stand.
You can insist until your face turns blue that you've never seen a stack segment register changed. The fact remains the Intel standard reference states that the stack segment register can be changed and is used in stack operations. The difference between you and me is that I code defensively to handle the published standard contract so as not to worry about some corner cases coming up in some compiler implementation while you ignore the published standard and base decision solely on what you have seen. That's fine, to each their own. I just find the cavalier attitude surprising coming from a supposed security expert.
It's obvious that you don't have anything constructive to say and arguing purely for argument sake. That's the end of this discussion.
I asked if you'd ever changed a segment selector in userland code and why. You said "yes", didn't say why, blew smoke about how "Intel says its possible to change them!" (no shit?), said changing the stack segment selector is "defensive coding" (again: userland code practically disables segment addressing, except for conveniences like the TEB at GS), made reference to a "published standard", and then called me a "supposed" security expert. And, let's be clear, you're the expert that can't remember the eight (8) GPRs on x86.
I'm convinced you can code, but I'm equally convinced that you had no business berating someone else for asking questions about how Cygwin handles its stack, because you don't know either. Don't pile on to people.
First, he's writing a nonportable language runtime. For Cywgin. It's not a fair critique to say "he's making the mistake of writing x86-specific code".
Second, you don't have to initialize a stack before you use it. The stack isn't magically cleared before it gets used. In fact, that's rather the point of having the stack implemented with a single pointer, and is also the reason that in C you have to explicitly initialize (say) integers before using them.
Third, there's nothing "dangerous" about what he's doing, in that what he's doing can't ever work. He created a temp stack, write code that attempts to switch into it, and never wrote the code to switch out of it. That's not going to slip into production. But that's also not a fundamental critique of the approach.
What he's trying to do works fine, including under Cygwin, when completely implemented. Despite much peanut gallery whining that it can't possibly work, or that this guy should give up on doing inline/threaded/coroutine stacks and instead implement some CS101 interpreter instead.