;; FIXME: magic constant, and probably n-args-bytes
(args-size (* 3 n-word-bytes))
;; FIXME: n-frame-bytes?
- (frame-size
- (+ n-foreign-linkage-area-bytes n-return-area-bytes args-size)))
+ (frame-size (logandc2 (+ n-foreign-linkage-area-bytes
+ n-return-area-bytes
+ args-size
+ +stack-alignment-bytes+)
+ +stack-alignment-bytes+)))
(destructuring-bind (sp r0 arg1 arg2 arg3 arg4)
(mapcar #'make-gpr '(1 0 3 4 5 6))
(flet ((load-address-into (reg addr)
--- /dev/null
+;;;; Testing the stack alignment of foreign calls. Uses stack-alignment-offset.c.
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; While most of SBCL is derived from the CMU CL system, the test
+;;;; files (like this one) were written from scratch after the fork
+;;;; from CMU CL.
+;;;;
+;;;; This software is in the public domain and is provided with
+;;;; absolutely no warranty. See the COPYING and CREDITS files for
+;;;; more information.
+
+(use-package :sb-alien)
+
+;;; Callbacks are not part of the exported interface yet -- when they are this can
+;;; go away.
+(import 'sb-alien::alien-lambda)
+
+(defun run (program &rest arguments)
+ (let* ((proc nil)
+ (output
+ (with-output-to-string (s)
+ (setf proc (run-program program arguments
+ :search (not (eql #\. (char program 0)))
+ :output s)))))
+ (unless (zerop (process-exit-code proc))
+ (error "Bad exit code: ~S~%Output:~% ~S"
+ (process-exit-code proc)
+ output))
+ output))
+
+(defvar *required-alignment*
+ #+(and ppc darwin) 16
+ #+(and ppc linux) 16
+ #+(or mips x86-64) 8
+ #+x86 4
+ #-(or x86 x86-64 mips (and ppc (or darwin linux))) (error "Unknown platform"))
+
+;;;; Build the offset-tool as regular excutable, and run it with
+;;;; fork/exec, so that no lisp is on the stack. This is our known-good
+;;;; number.
+
+(run "cc" "stack-alignment-offset.c" "-o" "stack-alignment-offset")
+
+(defparameter *good-offset*
+ (parse-integer (run "./stack-alignment-offset"
+ (princ-to-string *required-alignment*))))
+
+;;;; Build the tool again, this time as a shared object, and load it
+
+(run "cc" "stack-alignment-offset.c"
+ #+darwin "-bundle" #-darwin "-shared"
+ "-o" "stack-alignment-offset.so")
+
+(load-shared-object "stack-alignment-offset.so")
+
+(define-alien-routine stack-alignment-offset int (alignment int))
+(define-alien-routine trampoline int (callback (function int)))
+
+;;;; Now get the offset by calling from lisp, first with a regular foreign function
+;;;; call, then with an intervening callback.
+
+(assert (= *good-offset* (stack-alignment-offset *required-alignment*)))
+
+(assert (= *good-offset* (trampoline (alien-lambda int ()
+ (stack-alignment-offset *required-alignment*)))))
+
+;;;; success!
--- /dev/null
+/* Compiled and run by foreign-stack-alignment.lisp
+ *
+ * stack_alignment_offset(int) returns the offset of the first argument from a
+ * given alignment. run (1) from main, to obtain the good value with no
+ * lisp involved (2) from lisp both with and without callbacks to see that
+ * we have not messed the alignment.
+ *
+ * trampoline(int(*)()) is here so that we can get callbacks on the
+ * stack too.
+ */
+
+/* This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * While most of SBCL is derived from the CMU CL system, the test
+ * files (like this one) were written from scratch after the fork
+ * from CMU CL.
+ *
+ * This software is in the public domain and is provided with
+ * absolutely no warranty. See the COPYING and CREDITS files for
+ * more information.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* <nikodemus> bwahahahaaa!
+ * <Xophe> oh dear. He's finally flipped
+ * <lisppaste> nikodemus pasted "stack_alignment_offset" at
+ * http://paste.lisp.org/display/13231
+ * <Xophe> heh
+ * <Xophe> along with a big / * This code is really twisted * / comment :-)
+ * <antifuchs> gods.
+ */
+extern int
+stack_alignment_offset (int alignment)
+{
+ return ((unsigned int)&alignment) % alignment;
+}
+
+extern int
+trampoline (int(*callback)())
+{
+ return callback();
+}
+
+int main (int argc, char** argv)
+{
+ if (argc != 2) {
+ printf("wrong number of arguments: %d\n", argc-1);
+ return 1;
+ }
+
+ printf("%d\n", stack_alignment_offset(atoi(argv[1])));
+ return 0;
+}