Я пытаюсь реализовать вызов бедняка с текущим продолжением для программы, написанной на C. Я могу «легко» получить доступ и записать в память соответствующую часть стека C (очевидно, это непереносимо и полно UB, но я уже укусил эту пулю).
Мне интересно, как получить фактический указатель стека и адрес возврата и как их восстановить. У меня такое впечатление, что мне, вероятно, удастся сделать это только для указателя стека (надеюсь, сам обратный адрес будет спрятан внутри фрагмента стека, который я скопировал и восстановил).
Я подозреваю, что это потребует некоторой сборки, но я надеюсь, что в идеале есть какой-нибудь умный способ избежать этого.
Поскольку, как вы говорите, это непереносимо, вам следует упомянуть и пометить реализацию (реализации), на которую вы хотите ориентироваться. Если он отмечен только тегом c, предполагается, что вы полностью работаете в рамках стандарта ISO.
Нельзя ли это сделать (конечно, непереносимым способом) с помощью setjmp
? Я имею в виду, что это почти то же самое, что и вызов /cc, но (и это большое но) из-за того, что вы можете идти только вниз по стеку (то есть вы можете вернуться к вызывающему абоненту или к вызывающему абоненту). , или... ; но не, в отличие от вызова /cc, возврата к ранее вызванной функции. Стек с setjmp
по-прежнему остается тем же классическим стеком, просто его можно быстро разложить. "стек" с call/cc
)
Но, тем не менее, setjmp
хранит все необходимое (указатель стека, регистры и т. д.). Это UB, если используется с устаревшим стеком, но его можно объединить с уродливой копией стека, которую вы собираетесь сделать...
Вас интересуют протопотоки? dunkels.com/adam/pt
Этого можно добиться с помощью ucontext . Он не столько позволяет вам манипулировать стеком, сколько позволяет переключаться между различными комбинациями стека и адресов выполнения. Я демонстрирую использование его для создания сопрограмм (кооперативной многозадачности) здесь.
Пахнет «ху-вопросом». Какую реальную проблему вы пытаетесь здесь решить? Вы реализуете переключение контекста RTOS или что-то подобное?
@chrslg: Спасибо, спасибо, спасибо! Не стесняйтесь превратить это в ответ. Не знаю, почему я об этом не подумал, но действительно setjmp
должен делать именно то, что мне нужно. После копирования старой копии стека (ранее записанной одновременно с setjmp
) обратно в текущий стек я смогу использовать longjmp
, чтобы «воскресить» старое состояние.
@NateEldredge: Я бы хотел, чтобы он работал на Windows, Android, macOS, GNU/Linux (для ОС) и Armhf, Arm64, riscv, i386 и amd64 (для ISA), как с GCC, так и с LLVM. Не знаю, как пометить эту «реализацию».
@ikegami: Спасибо за указатель на get/setcontext
. Я не знал об этих новых альтернативах (sig)longjmp
.
По запросу мои комментарии в форме ответа (правда, вы делаете что-то настолько конкретное, что я сомневаюсь, что кто-нибудь с таким же вопросом когда-нибудь это прочитает :D)
Вероятно, это можно было бы сделать (конечно, непереносимым способом) с помощью setjmp/longjmp
. То есть это почти то же самое, что и call/cc
, но (и это большое но) из-за того, что идти можно только вниз по стеку. Итак, вы можете вернуться к вызывающему абоненту, или к вызывающему абоненту, или... ; но не, в отличие от call/cc
, возвращаться «назад» к ранее вызванной функции в столь же нелинейном стеке, как временная шкала Марти МакФлая. Стек с setjmp
остается тем же классическим, линейным стеком, только его можно быстро разложить. Это не неявное дерево, которое представляет собой стек с вызовом/cc.
Но, тем не менее, setjmp
хранит все необходимое (указатель стека, регистры и т. д.). Это UB, если используется с устаревшим стеком, но его можно объединить с уродливой копией стека, которую вы собираетесь сделать...
Я бы удалил часть «или что есть библиотека, которая делает для меня неприятные вещи, или, в худшем случае, какой-то существующий код, который я мог бы скопировать, который имеет аналогичные потребности и имеет необходимый встроенный ASM для обычно подозрительных ISA». так как это близкая приманка. Если кто-то знает о такой библиотеке, я уверен, что они все равно расскажут.