我最近发布了一个关于堆栈分段和boost coroutines的问题,但似乎-fsplit-stack方法只适用于使用该标志编译的源文件,当你分支到另一个函数时,运行时会崩溃尚未使用-fsplit-stack编译。对于example
这意味着运行时使用函数本地技术来检测当前堆栈何时被超越。而不是“保护页面信号”技巧,其中堆栈的末尾总是有一个保护页面,它会在写入或读取时产生一个信号,告诉运行时分配一个新的堆栈帧并分支到那个。
然后这个标志的用途是什么?如果我链接到任何其他未使用它构建的库,代码将会中断(甚至libstdc ++和libc),那么人们如何使用这些东西实际上用于大型项目?
从阅读有关拆分堆栈的gcc wiki看来,从拆分堆栈函数调用非拆分堆栈函数会导致分配64KB堆栈帧。好。
但似乎尚未实现从函数指针调用非拆分堆栈函数以遵循上述方案。
这个标志有什么用?如果我继续调用任何虚函数我的程序会中断吗?
从the answer below开始,似乎clang没有实现拆分堆栈?
答案 0 :(得分:2)
你必须使用segmeented-stacks支持和你的应用程序来编译boost(至少是boost.context和boost.coroutine)。
使用b2属性segmented-stacks = on编译boost(boost.context和boost.coroutine)(在boost.coroutine和boost.context中启用特殊代码)。
您的应用必须使用-DBOOST_USE_SEGMENTED_STACKS和-fsplit-stack(boost.coroutines标头所需)进行编译。
请参阅boost.coroutine documentation
boost.coroutine包含一个演示分段堆栈的示例(在目录coroutine / example / asymmetric / call b2 toolset = gcc segmented-stacks = on)。
关于您的上一个问题GCC Wiki states:
对于从分离堆栈代码到非分割堆栈代码的调用,链接器 将更改拆分堆栈中的初始指令(调用方) 功能。这意味着链接器必须具有特殊功能 了解编译器发出的指令。的效果 更改将通过数字增加所需的帧大小 大到足以合理地为非分组堆栈工作。这将是一个 目标依赖数;默认值将是64K。注意 这个大堆栈将在拆分堆栈功能时释放 回报。请注意,我忽略了一个分割堆栈代码的情况 共享库在主可执行文件中调用非拆分堆栈代码; 这似乎是一个不太可能的问题。
请注意:虽然llvm支持分段堆栈,但clang接缝不提供__splitstack_<xyz>
函数。
答案 1 :(得分:0)
首先,我要说拆分堆栈支持本质上是实验性的。它不是一个受到广泛支持的东西,也没有一个实现被接受为可行的方式。因此,编译器中存在的部分目的是使实际研究成为可能。
也就是说,人们通常希望使用这样的功能来启用大量具有小堆栈的线程,但如果需要,可以使用更大的线程。在某些应用程序中,可以严格控制在这些线程中运行的代码。例如。相当专业的请求处理程序,不调用通用库,如Boost。高性能系统工作通常涉及收紧对给定路径中使用的代码的约束,这将是其示例。它肯定限制了该功能的适用性,但如果有人以这种方式在生产中使用它,我不会感到惊讶。
请注意,-fno-exceptions和-fno-rtti等标志存在类似问题。通常,C ++需要使用兼容的标志集编译进入可执行文件的所有内容。有时人们可以混搭,但往往很脆弱。这是从源代码和密封构建工具(如bazel)构建所有的动机的一部分。其他语言对非源组件有不同的方法,尤其是基于虚拟机的语言,如Java和.NET系列。在这些世界中,像分割堆栈这样的东西是在较低级别的编译中决定的,但通常在源代码级别没有对它们的任何控制或意识。