8

I recently posted a question about stack segmentation and boost coroutines but it seems like the -fsplit-stack approach only works with source files that are compiled with that flag, the runtime breaks down when you branch to another function that has not been compiled with -fsplit-stack. For example

This implies that the runtime uses a function local technique to detect when the current stack has been surpassed. And not a "guard page signal" trick, where the end of the stack always has a guard page which will raise a signal on write or read, telling the runtime to allocate a new stack frame and branch to that.

Then what is the use of this flag? If I link to any other library that has not been built with this, code will break (even libstdc++ and libc), then how is this something people use practically with big projects?


From reading the gcc wiki about split stacks it seems like calling a non split stack function from a split stack function results in an allocation of a 64KB stack frame. Good.

But it seems like calling a non split stack function from a function pointer has not yet been implemented to follow the above scheme.

What use is this flag then? If I proceed to call any virtual function will my program break?

Further from the answer below it seems like clang has not implemented split stacks?

Curious
  • 20,870
  • 8
  • 61
  • 146
  • 1
    Am I right in concluding it's not actually about "large" projects. Just projects with unknown stack requirements in third-party code? – sehe Sep 20 '17 at 07:19
  • 1
    https://gcc.gnu.org/wiki/SplitStacks: _"6. At least on x86, arrange to allocate a new field in the TCB header accessible via %fs or %gs. This is probably the best solution, and it is the one implemented for i386 and x86_64."_ – sehe Sep 20 '17 at 07:19
  • 1
    Short answer: don't use `-fsplit-stack` (unless you understand all its implication and are ready to recompile everything, including even `libc` & `libstdc++`); that flag is practically useful for language implementors (notably for implementing Go) – Basile Starynkevitch Sep 20 '17 at 07:23
  • @BasileStarynkevitch I think OP knows he needs it if he wants to use Coroutines, hence the questions – sehe Sep 20 '17 at 07:36
  • @sehe yes that is what I meant, what to do in situations where you do not know how the other code has been compiled, etc – Curious Sep 20 '17 at 14:05
  • @BasileStarynkevitch I wonder why boost coroutines offer that functionality then.. There has to be a practical aspect to it that I am missing here... – Curious Sep 20 '17 at 14:24

2 Answers2

4

You have to compile boost (at least boost.context and boost.coroutine) with segmeented-stacks support AND your application.

  • compile boost (boost.context and boost.coroutine) with b2 property segmented-stacks=on (enables special code inside boost.coroutine and boost.context).

  • your app has to be compiled with -DBOOST_USE_SEGMENTED_STACKS and -fsplit-stack (required by boost.coroutines headers).

see boost.coroutine documentation

boost.coroutine contains an example that demonstrates segmented stacks (in directory coroutine/example/asymmetric/ call b2 toolset=gcc segmented-stacks=on).

regarding your last question GCC Wiki states:

For calls from split-stack code to non-split-stack code, the linker will change the initial instructions in the split-stack (caller) function. This means that the linker will have to have special knowledge of the instructions that the compiler emits. The effect of the changes will be to increase the required framesize by a number large enough to reasonably work for a non-split-stack. This will be a target dependent number; the default will be something like 64K. Note that this large stack will be released when the split-stack function returns. Note that I'm disregarding the case of split-stack code in a shared library calling non-split-stack code in the main executable; that seems like an unlikely problem.

please note: while llvm supports segmented stacks, clang seams not to provide the __splitstack_<xyz> functions.

xlrg
  • 1,994
  • 1
  • 16
  • 14
  • The Boost Coroutine part is irrelevant. OP is using Coroutine2 which is header only – sehe Sep 20 '17 at 07:20
  • You even have to recompile all other libraries, including `libc` and `libstdc++` – Basile Starynkevitch Sep 20 '17 at 07:22
  • @sehe: It is not irrelevant because even boost.coroutine2 tests for BOOST_USE_SEGMENTED_STACKS in its headers. – xlrg Sep 20 '17 at 07:23
  • @xlrg That's interesting. I'd say that means there should be corresponding mention in the _relevant_ docs :) – sehe Sep 20 '17 at 07:25
  • @Basile Starynkevitch: the example using segmented stacks in coroutine(2) does not recompile libc or libstdc++. – xlrg Sep 20 '17 at 07:25
  • @BasileStarynkevitch, xlrg The question is specifically about whether that is asking for problems if using functions from such libraries with heavier stack requirements, or invoked at a time when spare stack space has run low – sehe Sep 20 '17 at 07:26
  • That's awesome addition. – sehe Sep 20 '17 at 07:33
  • So am I correct in assuming that the flag is only useful if it only calls other code compiled with -fsplit-stack? If there are any calls to non split-stack code that will allocate 64KB (which is the default boost coroutine stack size anyway) and continue as normal. Also `clang seams not to provide the __splitstack_ functions` what does this imply? That clang does not support split stacks? – Curious Sep 20 '17 at 14:03
  • @sehe which addition are you talking about? – Curious Sep 20 '17 at 14:06
  • @Curious I thought the quote regarding mixed linking was added in the edit. Apparently it wasn't. – sehe Sep 20 '17 at 14:14
  • @sehe Ah, I still find it hard to understand where split stacks are actually useful... If you have code that is not compiled with that flag, then things will eventually break – Curious Sep 20 '17 at 14:22
  • @Curios, read the GCC Wiki! If you use split-stacks (implemented in gcc for GO) your stack grows on demand, e.g. you start with a 4kB large stack and if necessary the environment expands the stack (for instance if you do recursive calls). You can call non-split-stack code from split-stack code. As the Wiki mentions, the linker takes care and allocates a stackframe of 64kB (the default, should be configureable at compiler cmd line). – xlrg Sep 21 '17 at 06:03
  • @xlrg and what happens when that non split stack code requires more stack space? – Curious Sep 21 '17 at 15:02
  • @xlrg further it seems like crucial function pointer stack splitting is not yet enabled `"(This is not yet implemented)"` (from the gcc wiki) – Curious Sep 21 '17 at 15:16
  • @Curious: UB, if the stack is not large enough – xlrg Sep 25 '17 at 08:06
1

First I'd say split stack support is somewhat experimental in nature to begin with. It is not a widely supported thing nor has a single implementation become accepted as the way to go. As such, part of the purpose of it existing in the compiler is to enable research in real use.

That said, one generally wants to use such a feature to enable lots of threads with small stacks, but which can get bigger if they need to. In some applications, the code that runs in these threads can be tightly controlled. E.g. fairly specialized request handlers that do not call general purpose libraries such as Boost. High performance systems work often involves tightening down the constraints on what code is used in a given path and this would be an example thereof. It certainly limits the applicability of the feature, but I wouldn't be surprised if someone is using it in production this way.

Note that similar issues exist with flags such as -fno-exceptions and -fno-rtti . Generally C++ requires compiling everything that goes into an executable with a compatible set of flags. Sometimes one can mix and match, but it is often fragile. This is part of the motivation of building everything from source and hermetic build tools like bazel. Other languages have different approaches to non-source components, especially virtual machine based languages such as Java and the .NET family. In those worlds things like split stacks are decided at a lower-level of compilation, but typically one would not have any control over or awareness of them at the source code level.

Zalman Stern
  • 3,161
  • 12
  • 18