Ich arbeite an einer setjmp
/longjmp
benutzerdefinierte 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.x86_64: zwingen gcc, Argumente auf dem Stapel zu übergeben
Der Code funktioniert in minimalen Beispielen (wenn er direkt von einer Baugruppenquelle aufgerufen wird). Das Problem tritt auf, wenn es mit C-Code verwendet wird, aufgrund der Art und Weise, wie Parameter an die Funktionen des 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 Unterschrift 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 dies nicht wie arbeiten. In der Tat, wenn ich set_jmp
eingeben, rdi
und rsi
wurden bereits geklopft, um einen Zeiger auf env
und val
zu halten. Gleiches gilt für long_jmp
gegenüber rdi
.
Gibt es eine Möglichkeit, GCC, z. 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 set_jmp
und long_jmp
mit einigen definieren, die manuell die clobbered Register auf Stapel, so dass sie später abrufen.
Dies würde die PCS/ABI brechen. Sie nähern sich von der falschen Seite. Ihr Assembler-Code muss dem ABI folgen. Am besten verwenden Sie C-Funktionen mit Inline-Assembler entweder direkt oder als Wrapper für Ihren eigentlichen Code. Auf diese Weise können Sie festlegen, welche Code-Clobber gespeichert werden sollen und wie Sie gcc speichern/wiederherstellen können. – Olaf
'setjmp' muss nicht' rdi' und 'rsi' speichern - wie du sagst, sie sind in' setjmp' geplätschert, also warum sollten sie gespeichert werden? Tatsächlich müssen nur die Register, die als "callee-saved" (d. H. Rbp, ebx, r12, r13, r14, r15 und natürlich rsp) markiert sind, beibehalten werden. – fuz
Ich stimme zu, dass ich die ABI nicht respektiere, aber dafür gibt es einen Grund. Alles funktioniert gut mit 'setjmp' und' longjmp', denn was nicht von 'setjmp' gespeichert wird, wird tatsächlich vom Aufrufer gespeichert, falls es benötigt wird, da es sich um Register zum Speichern der Aufrufer handelt. In meiner Anwendung habe ich eine Interaktion mit dem Linux-Kernel, der bei einem bestimmten Interrupt das Steuerelement an einen anderen Teil des Codes auf Benutzerebene zurückgibt, der wiederum 'setjmp' aufruft. Durch diese Konstruktion weiß der ursprünglich ausführende Code nicht, dass "setjmp" aufgerufen wird, und daher sollten Register zum Speichern von Anrufern ebenfalls gespeichert werden. – ilpelle