From af6edc5adaeac6535c88cfaa81fcfb5b20734ab8 Mon Sep 17 00:00:00 2001 From: Nikodemus Siivola Date: Sun, 6 Nov 2005 13:25:47 +0000 Subject: [PATCH] 0.9.6.26: preserve stack alignment in callbacks on ppc * Merge patch from Cyrus Harmon (sbcl-devel 2005-11-04), plus slightly twisted tests. Note: This has been tested on ppc/darwin and x86/linux, but the new tests are active on all platforms -- using alignment requirements I've essentially guessed. --- src/compiler/ppc/c-call.lisp | 7 ++- tests/foreign-stack-alignment.impure.lisp | 69 +++++++++++++++++++++++++++++ tests/stack-alignment-offset.c | 56 +++++++++++++++++++++++ version.lisp-expr | 2 +- 4 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 tests/foreign-stack-alignment.impure.lisp create mode 100644 tests/stack-alignment-offset.c diff --git a/src/compiler/ppc/c-call.lisp b/src/compiler/ppc/c-call.lisp index 7426c93..8f5820f 100644 --- a/src/compiler/ppc/c-call.lisp +++ b/src/compiler/ppc/c-call.lisp @@ -459,8 +459,11 @@ ;; 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) diff --git a/tests/foreign-stack-alignment.impure.lisp b/tests/foreign-stack-alignment.impure.lisp new file mode 100644 index 0000000..2ed55a3 --- /dev/null +++ b/tests/foreign-stack-alignment.impure.lisp @@ -0,0 +1,69 @@ +;;;; 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! diff --git a/tests/stack-alignment-offset.c b/tests/stack-alignment-offset.c new file mode 100644 index 0000000..fe0ad9c --- /dev/null +++ b/tests/stack-alignment-offset.c @@ -0,0 +1,56 @@ +/* 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 +#include + +/* bwahahahaaa! + * oh dear. He's finally flipped + * nikodemus pasted "stack_alignment_offset" at + * http://paste.lisp.org/display/13231 + * heh + * along with a big / * This code is really twisted * / comment :-) + * 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; +} diff --git a/version.lisp-expr b/version.lisp-expr index 3a322c0..5e8847e 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; checkins which aren't released. (And occasionally for internal ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"0.9.6.25" +"0.9.6.26" -- 1.7.10.4