Ich arbeite an einer setjmp
/ longjmp
benutzerdefinierten Implementierung für x86-64-Systeme, die den gesamten Kontext der CPU speichert (nämlich alle xmm, fpu stack, etc; nicht nur Callee-save-Register). Dies wird direkt in Assembly geschrieben.
Der Code funktioniert in minimalen Beispielen (wenn er direkt von einer Assembly-Quelle aufgerufen wird). Das Problem tritt auf, wenn es mit C-Code verwendet wird, da die Parameter an die Funktionen homebrew setjmp
/ longjmp
übergeben werden. Tatsächlich schreibt SysV ABI für x64_64-Systeme vor, dass Argumente über Register weitergegeben werden sollten (wenn sie höchstens 6 sind). Die Signatur meiner Funktionen sind:
long long set_jmp(exec_context_t *env);
__attribute__ ((__noreturn__)) void long_jmp(exec_context_t *env, long long val);
Natürlich kann das nicht so funktionieren, wie es ist. In der Tat, wenn ich set_jmp
eingeben, wurden rdi
und rsi
bereits geplottert, um einen Zeiger auf env
und val
zu behalten. Gleiches gilt für long_jmp
in rdi
.
Gibt es eine Möglichkeit, GCC zu erzwingen, z.B. indem man sich auf irgendein Attribut verlässt, um das Argument zu zwingen, über den Stapel zu gehen? Dies wäre viel eleganter als das Wrapping von set_jmp
und long_jmp
mit einigen define, die die gestopften Register manuell auf den Stack schieben, um sie später wieder zu finden.
Sie können das Überschreiben der Register vermeiden, indem Sie die Funktion mit Inline-Assembly aufrufen.
%Vor%Hier wird eine Ganzzahl auf den Stack geschoben und die Funktion foo aufgerufen. foo stellt den Wert in seiner lokalen Variablen i zur Verfügung. Nach der Rückkehr wird der Stapelzeiger auf seinen ursprünglichen Wert zurückgesetzt.
Tags und Links c gcc calling-convention parameter-passing x86-64