Я работаю над пользовательской реализацией для систем x86-64 setjmp
//longjmp
, которая сохраняет весь контекст процессора (а именно, все xmm, fpu stack и т. Д. Не только регистры регистрации сбережений). Это написано непосредственно в сборке.x86_64: принудительное gcc передать аргументы в стеке
Код прекрасно работает в минимальных примерах (при вызове непосредственно из источника сборки). Проблема возникает при использовании ее с кодом C из-за того, как параметры передаются на домашнюю страницу setjmp
/longjmp
. Фактически, SysV ABI для систем x64_64 диктует, что аргументы должны передаваться через регистры (если их не более 6). Подпись моих функций:
long long set_jmp(exec_context_t *env);
__attribute__ ((__noreturn__)) void long_jmp(exec_context_t *env, long long val);
Конечно, это не может работать, как есть. Фактически, когда я ввожу set_jmp
, rdi
и rsi
уже были сбиты, чтобы сохранить указатель на env
и val
. То же самое относится к long_jmp
по отношению к rdi
.
Есть ли способ заставить GCC, например. опираясь на некоторый атрибут, чтобы заставить аргумент проходить через стек? Это было бы намного более элегантно, чем обертывание set_jmp
и long_jmp
с некоторым определением, которое вручную выталкивает сбитые регистры в стек, чтобы получить их позже.
Это сломает PCS/ABI. Вы приближаетесь с другой стороны. Ваш код ассемблера должен следовать за ABI. Лучше всего использовать функции C с встроенным ассемблером либо напрямую, либо как обертки для вашего реального кода. Таким образом, вы можете просто указать, что регистрирует/запоминает ваш код, сжимает и оставляет сохранение/восстановление в gcc. – Olaf
'setjmp' не нужно сохранять' rdi' и 'rsi', как вы говорите, они сбиты внутри' setjmp', так зачем их спасти? Фактически, только регистры, отмеченные как «спасенные» (т. Е. Rbp, ebx, r12, r13, r14, r15 и, конечно, rsp), должны быть сохранены. – fuz
Я согласен с тем, что я не уважаю ABI, но есть причина для этого. Все работает отлично с 'setjmp' и' longjmp', потому что то, что не сохраняется 'setjmp', фактически сохраняется вызывающим, в случае необходимости, поскольку они являются регистрами сохранения звонящего. В моем приложении у меня есть взаимодействие с ядром Linux, которое после определенного прерывания возвращает элемент управления в другую часть кода пользовательского уровня, что, в свою очередь, вызывает 'setjmp'. По этой конструкции первоначально исполняемый код не знает, что вызывается 'setjmp', и поэтому регистры сохранения вызывающего абонента также должны быть сохранены. – ilpelle