Как использовать -fsplit-stack в большом проекте

Недавно я опубликовал вопрос о сегментации стека и сопутствующих бустах, но похоже, что подход -fsplit-stack работает только с исходными файлами, скомпилированными с этим флагом, среда выполнения прерывается, когда вы переходите к другой функции, которая не была скомпилирована с - fsplit-стек. Например

Это подразумевает, что среда выполнения использует локальную технику функции для определения того, когда текущий стек был превышен. А не уловка "сигнал охранной страницы", когда на конце стека всегда есть защитная страница, которая подаст сигнал при записи или чтении, сообщая среде выполнения выделить новый кадр стека и перейти к нему.

Тогда какая польза от этого флага? Если я свяжусь с любой другой библиотекой, которая не была с этим построена, код сломается (даже libstdC++ и libc), тогда как это люди используют практически в больших проектах?


Из прочтения вики gcc о разделенных стеках кажется, что вызов функции без разделенного стека из функции разделенного стека приводит к выделению кадра стека размером 64 КБ. Хорошо.

Но кажется, что вызов функции неразделенного стека из указателя функции еще не реализован в соответствии с приведенной выше схемой.

Какая польза от этого флага? Если я продолжу вызывать какую-либо виртуальную функцию, моя программа сломается?

Далее из ответа ниже кажется, что в Clang не реализованы разделенные стеки?

2 ответа

Вы должны скомпилировать boost (по крайней мере boost.context и boost.coroutine) с поддержкой сегментированных стеков И вашего приложения.

  • скомпилируйте boost (boost.context и boost.coroutine) со свойством b2 segmented-stacks=on (включает специальный код внутри boost.coroutine и boost.context).

  • Ваше приложение должно быть скомпилировано с -DBOOST_USE_SEGMENTED_STACKS и -fsplit-stack (требуется заголовками boost.coroutines).

см. документацию boost.coroutine

boost.coroutine содержит пример, демонстрирующий сегментированные стеки (в каталоге coroutine/example/asymmetric/ call b2 toolset=gcc segmented-stacks=on).

относительно вашего последнего вопроса GCC Wiki утверждает:

Для вызовов из кода с разделенным стеком в код без разделенного стека компоновщик изменит начальные инструкции в функции разделенного стека (вызывающего). Это означает, что компоновщик должен иметь специальные знания инструкций, которые выдает компилятор. Результатом изменений будет увеличение требуемого размера кадра на число, достаточно большое, чтобы разумно работать для стека без разделения. Это будет целевой номер; по умолчанию будет что-то вроде 64K. Обратите внимание, что этот большой стек будет освобожден, когда вернется функция split-stack. Обратите внимание, что я игнорирую случай кода с разделенным стеком в общей библиотеке, вызывающий код без разделенного стека в основном исполняемом файле; это кажется маловероятной проблемой.

пожалуйста, обратите внимание: пока llvm поддерживает сегментированные стеки, лягушатые швы не обеспечивают __splitstack_<xyz> функции.

Во-первых, я бы сказал, что поддержка сплит-стека носит несколько экспериментальный характер. Это не является широко поддерживаемой вещью, и ни одна реализация не стала принятой в качестве пути. Таким образом, часть его предназначения, существующего в компиляторе, состоит в том, чтобы сделать возможным исследование в реальном использовании.

Тем не менее, обычно требуется использовать такую ​​функцию, чтобы включить множество потоков с небольшими стеками, но которые могут стать больше, если им это необходимо. В некоторых приложениях код, который выполняется в этих потоках, может жестко контролироваться. Например, достаточно специализированные обработчики запросов, которые не вызывают библиотеки общего назначения, такие как Boost. Работа высокопроизводительных систем часто включает в себя ужесточение ограничений на то, какой код используется в данном пути, и это было бы примером этого. Это, конечно, ограничивает применимость функции, но я не удивлюсь, если кто-то использует ее в производстве таким образом.

Обратите внимание, что похожие проблемы существуют с флагами, такими как -fno-exceptions и -fno-rtti. Обычно C++ требует компиляции всего, что входит в исполняемый файл с совместимым набором флагов. Иногда можно смешивать и сочетать, но это часто хрупко. Это является частью мотивации создания всего, что связано с исходным кодом, и инструментов герметичного построения, таких как Bazel. Другие языки имеют разные подходы к не исходным компонентам, особенно к языкам на основе виртуальных машин, таким как Java и семейство.NET. В этих мирах такие вещи, как разделенные стеки, решаются на более низком уровне компиляции, но обычно никто не будет иметь никакого контроля или осведомленности о них на уровне исходного кода.

Другие вопросы по тегам