Sto lavorando a un'implementazione personalizzata setjmp
/longjmp
per sistemi x86-64 che salva l'intero contesto della CPU (vale a dire, tutto xmm, stack di fpu, ecc., Non solo registri callee-save). Questo è scritto direttamente in assemblea.x86_64: forzare gcc a passare argomenti nello stack
Il codice funziona bene in esempi minimi (quando lo si chiama direttamente da un'origine assembly). Il problema sorge quando lo si utilizza con il codice C, a causa del modo in cui i parametri vengono passati alle funzioni homebrew setjmp
/. In effetti, SysV ABI per i sistemi x64_64 impone che gli argomenti debbano essere trasmessi tramite registri (se sono al massimo 6). La firma delle mie funzioni sono:
long long set_jmp(exec_context_t *env);
__attribute__ ((__noreturn__)) void long_jmp(exec_context_t *env, long long val);
Naturalmente, questo non può funzionare così com'è. Infatti, quando inserisco set_jmp
, rdi
e rsi
sono già stati ignorati per mantenere un puntatore a env
e val
. Lo stesso vale per long_jmp
rispetto a rdi
.
C'è un modo per forzare GCC, ad es. facendo affidamento su qualche attributo, per forzare l'argomento passando attraverso lo stack? Questo sarebbe molto più elegante dell'involucro di set_jmp
e long_jmp
con alcune definizioni che spingono manualmente i registri danneggiati nello stack, in modo da recuperarli in un secondo momento.
Ciò interromperà il PCS/ABI. Ti stai avvicinando dal lato sbagliato. Il tuo codice assembler deve seguire l'ABI. La cosa migliore è usare le funzioni C con inline-assembler direttamente o come wrapper per il tuo codice reale. In questo modo puoi solo specificare quale registro/memoria il codice clobbre e lasciare il salvataggio/ripristino in gcc. – Olaf
'setjmp' non ha bisogno di salvare' rdi' e 'rsi'-come dici tu, sono sbavati dentro' setjmp' quindi perché dovrebbero essere salvati? Infatti, solo i registri contrassegnati come "salvati con il callee" (cioè rbp, ebx, r12, r13, r14, r15 e naturalmente rsp) devono essere preservati. – fuz
Sono d'accordo che non sto rispettando l'ABI, ma c'è una ragione per questo. Tutto funziona bene con 'setjmp' e' longjmp' perché ciò che non viene salvato da 'setjmp' viene effettivamente salvato dal chiamante, nel caso sia necessario, poiché sono registri di salvataggio del chiamante. Nella mia applicazione, ho un'interazione con il Kernel Linux che, su un dato interrupt, restituisce il controllo a una parte diversa del codice a livello utente, che, a sua volta, chiama 'setjmp'. Con questa costruzione, il codice originariamente in esecuzione non sa che viene chiamato 'setjmp', e quindi i registri di salvataggio del chiamante dovrebbero essere salvati. – ilpelle