From 49fdb02506c8cf8e8dda4cc3ebe0ad4240e458e2 Mon Sep 17 00:00:00 2001
From: toy <toy>
Date: Thu, 24 Oct 2002 20:39:00 +0000
Subject: [PATCH] o Port over Tim Moore's cool foreign linkage table stuff to
 sparc. o Make new-genesis save target-foreign-linkage-table-size to  
 internals.h.

---
 code/sparc-svr4-vm.lisp           |  18 +++-
 compiler/generic/new-genesis.lisp |  13 ++-
 compiler/sparc/c-call.lisp        |  30 ++++++-
 compiler/sparc/cell.lisp          |  18 +++-
 compiler/sparc/parms.lisp         |  12 ++-
 lisp/Config.sun4_solaris_gcc      |   6 +-
 lisp/os-common.c                  |  30 ++++++-
 lisp/solaris-os.c                 |  46 +++++++++-
 lisp/sparc-arch.c                 | 138 +++++++++++++++++++++++++++++-
 lisp/sparc-assem.S                |  71 ++++++++++++++-
 lisp/sparc-validate.h             |  21 ++++-
 11 files changed, 381 insertions(+), 22 deletions(-)

diff --git a/code/sparc-svr4-vm.lisp b/code/sparc-svr4-vm.lisp
index 896f395c7..1740cab39 100644
--- a/code/sparc-svr4-vm.lisp
+++ b/code/sparc-svr4-vm.lisp
@@ -5,7 +5,7 @@
 ;;; Carnegie Mellon University, and has been placed in the public domain.
 ;;;
 (ext:file-comment
-  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/code/sparc-svr4-vm.lisp,v 1.4 1997/02/19 01:41:40 dtc Exp $")
+  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/code/sparc-svr4-vm.lisp,v 1.5 2002/10/24 20:38:57 toy Exp $")
 ;;;
 ;;; **********************************************************************
 ;;;
@@ -310,3 +310,19 @@
 		   (* (code-header-ref component code-code-size-slot)
 		      word-bytes)))
   nil)
+
+#+linkage-table
+(progn
+(defun lisp::foreign-symbol-address-aux (name flavor)
+  (let ((entry-num (lisp::register-foreign-linkage name flavor)))
+    (+ #.vm:target-foreign-linkage-space-start
+       (* entry-num vm:target-foreign-linkage-entry-size))))
+
+(defun lisp::find-foreign-symbol (addr)
+  (declare (type (unsigned-byte 32) addr))
+  (when (>= addr vm:target-foreign-linkage-space-start)
+    (let ((entry (/ (- addr vm:target-foreign-linkage-space-start)
+		    vm:target-foreign-linkage-entry-size)))
+      (when (< entry (lisp::foreign-linkage-symbols))
+	(lisp::foreign-linkage-entry entry)))))
+)
diff --git a/compiler/generic/new-genesis.lisp b/compiler/generic/new-genesis.lisp
index b3dc359a2..b3b77cb13 100644
--- a/compiler/generic/new-genesis.lisp
+++ b/compiler/generic/new-genesis.lisp
@@ -4,7 +4,7 @@
 ;;; Carnegie Mellon University, and has been placed in the public domain.
 ;;;
 (ext:file-comment
-  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/generic/new-genesis.lisp,v 1.48 2002/08/27 22:18:27 moore Exp $")
+  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/generic/new-genesis.lisp,v 1.49 2002/10/24 20:38:58 toy Exp $")
 ;;;
 ;;; **********************************************************************
 ;;;
@@ -1954,8 +1954,12 @@
 (defun init-foreign-linkage ()
   (setf (fill-pointer *cold-linkage-table*) 0)
   (clrhash *cold-foreign-hash*)
-  ;; This has gotta be the first entry.
-  (cold-register-foreign-linkage "resolve_linkage_tramp" :code))
+  ;; This has gotta be the first entry.  This has to match what
+  ;; os_foreign_linkage_init does!
+  #+x86
+  (cold-register-foreign-linkage "resolve_linkage_tramp" :code)
+  #+sparc
+  (cold-register-foreign-linkage "call_into_c" :code))
 
 (defvar *cold-assembler-routines* nil)
 
@@ -2252,7 +2256,8 @@
 	    (test-tail "-TRAP" "trap_" 2)
 	    (test-tail "-SUBTYPE" "subtype_" 3)
 	    (test-head "TRACE-TABLE-" "tracetab_" 4)
-	    (test-tail "-SC-NUMBER" "sc_" 5)))))
+	    (test-tail "-SC-NUMBER" "sc_" 5)
+	    (test-head "TARGET-FOREIGN-" "" 6)))))
     (setf constants
 	  (sort constants
 		#'(lambda (const1 const2)
diff --git a/compiler/sparc/c-call.lisp b/compiler/sparc/c-call.lisp
index f49924980..90c30d685 100644
--- a/compiler/sparc/c-call.lisp
+++ b/compiler/sparc/c-call.lisp
@@ -5,7 +5,7 @@
 ;;; Carnegie Mellon University, and has been placed in the public domain.
 ;;;
 (ext:file-comment
-  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/sparc/c-call.lisp,v 1.15 2001/01/23 04:40:15 dtc Exp $")
+  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/sparc/c-call.lisp,v 1.16 2002/10/24 20:38:58 toy Exp $")
 ;;;
 ;;; **********************************************************************
 ;;;
@@ -190,6 +190,7 @@
 	(c::give-up))))
 
 
+#-linkage-table
 (define-vop (foreign-symbol-address)
   (:translate foreign-symbol-address)
   (:policy :fast-safe)
@@ -202,6 +203,33 @@
     (inst li res (make-fixup (extern-alien-name foreign-symbol)
 			     :foreign))))
 
+(define-vop (foreign-symbol-code-address)
+  (:translate #+linkage-table foreign-symbol-code-address
+	      #-linkage-table foreign-symbol-address)
+  (:policy :fast-safe)
+  (:args)
+  (:arg-types (:constant simple-string))
+  (:info foreign-symbol)
+  (:results (res :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:generator 2
+    (inst li res (make-fixup (extern-alien-name foreign-symbol)
+			     :foreign))))
+
+(define-vop (foreign-symbol-data-address)
+  (:translate foreign-symbol-data-address)
+  (:policy :fast-safe)
+  (:args)
+  (:arg-types (:constant simple-string))
+  (:info foreign-symbol)
+  (:results (res :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:temporary (:scs (non-descriptor-reg)) addr)
+  (:generator 2
+    (inst li addr (make-fixup (extern-alien-name foreign-symbol)
+			      :foreign-data))
+    (loadw res addr)))
+
 (define-vop (call-out)
   (:args (function :scs (sap-reg) :target cfunc)
 	 (args :more t))
diff --git a/compiler/sparc/cell.lisp b/compiler/sparc/cell.lisp
index 1d68f73a7..550849627 100644
--- a/compiler/sparc/cell.lisp
+++ b/compiler/sparc/cell.lisp
@@ -5,7 +5,7 @@
 ;;; Carnegie Mellon University, and has been placed in the public domain.
 ;;;
 (ext:file-comment
-  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/sparc/cell.lisp,v 1.20 1994/10/31 04:46:41 ram Exp $")
+  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/sparc/cell.lisp,v 1.21 2002/10/24 20:38:58 toy Exp $")
 ;;;
 ;;; **********************************************************************
 ;;;
@@ -126,7 +126,13 @@
       (inst cmp type function-header-type)
       (inst b :eq normal-fn)
       (inst move lip function)
-      (inst li lip (make-fixup (extern-alien-name "closure_tramp") :foreign))
+      ;; For the linkage-table stuff, we need to look up the address
+      ;; from the linkage table instead of using the address directly.
+      (inst li lip (make-fixup (extern-alien-name "closure_tramp")
+			       #-linkage-table :foreign
+			       #+linkage-table :foreign-data))
+      #+linkage-table
+      (loadw lip lip)
       (emit-label normal-fn)
       (storew function fdefn fdefn-function-slot other-pointer-type)
       (storew lip fdefn fdefn-raw-addr-slot other-pointer-type)
@@ -140,7 +146,13 @@
   (:results (result :scs (descriptor-reg)))
   (:generator 38
     (storew null-tn fdefn fdefn-function-slot other-pointer-type)
-    (inst li temp (make-fixup (extern-alien-name "undefined_tramp") :foreign))
+    ;; For the linkage-table stuff, we need to look up the address
+    ;; from the linkage table instead of using the address directly.
+    (inst li temp (make-fixup (extern-alien-name "undefined_tramp")
+			      #-linkage-table :foreign
+			      #+linkage-table :foreign-data))
+    #+linkage-table
+    (loadw temp temp)
     (storew temp fdefn fdefn-raw-addr-slot other-pointer-type)
     (move result fdefn)))
 
diff --git a/compiler/sparc/parms.lisp b/compiler/sparc/parms.lisp
index da9e1ad0b..077338656 100644
--- a/compiler/sparc/parms.lisp
+++ b/compiler/sparc/parms.lisp
@@ -5,7 +5,7 @@
 ;;; Carnegie Mellon University, and has been placed in the public domain.
 ;;;
 (ext:file-comment
-  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/sparc/parms.lisp,v 1.35 2002/09/03 16:29:46 toy Exp $")
+  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/compiler/sparc/parms.lisp,v 1.36 2002/10/24 20:38:59 toy Exp $")
 ;;;
 ;;; **********************************************************************
 ;;;
@@ -196,9 +196,12 @@
 (defparameter target-read-only-space-start #x10000000)
 (defparameter target-static-space-start    #x28000000)
 (defparameter target-dynamic-space-start   #x40000000)
-(defparameter target-foreign-linkage-space-start #x0fc00000)
-(defconstant target-foreign-linkage-entry-size 8) ;In bytes.  Duh.
 
+;; This better match the value in sparc-validate.h!
+(defparameter target-foreign-linkage-space-start #x0f800000)
+;; This better agree with what sparc-arch.c thinks it is!  Right now,
+;; it's 4 instructions, so 16 bytes.
+(defconstant target-foreign-linkage-entry-size 16)
 
 
 ;;;; Other random constants.
@@ -273,6 +276,9 @@
     lisp::*free-interrupt-context-index*
     unix::*interrupts-enabled*
     unix::*interrupt-pending*
+
+    ;; Foreign linkage stuff
+    lisp::*linkage-table-data*
     ))
 
 (defparameter static-functions
diff --git a/lisp/Config.sun4_solaris_gcc b/lisp/Config.sun4_solaris_gcc
index aca79ed9e..78f7f5d6b 100644
--- a/lisp/Config.sun4_solaris_gcc
+++ b/lisp/Config.sun4_solaris_gcc
@@ -19,16 +19,16 @@ vpath %.S .:$(PATH1)
 #CC_V8PLUS = -xarch=v8plus
 #AS_V8PLUS = -Wa
 
-CPPFLAGS = -I. -I$(PATH1) -I/usr/openwin/include -I/usr/include/X11 -DSOLARIS -DSOLARIS25 -DSVR4 $(CC_V8PLUS)
+CPPFLAGS = -I. -I$(PATH1) -I/usr/openwin/include -I/usr/include/X11 -DSOLARIS -DSOLARIS25 -DSVR4 $(CC_V8PLUS) -DLINKAGE_TABLE
 CC = gcc
 CPP = gcc -E
-CFLAGS = -g -O3 $(AS_V8PLUS)
+CFLAGS = -g $(AS_V8PLUS)
 
 # Needed for sys/asm_linkage.h and sparc-assem.S (at least in 2.3)
 # Note that the sys/asm_linkage.h braindamage breaks make depend
 ASFLAGS = -g -traditional-cpp
 DEPEND_FLAGS = -traditional-cpp
-NM = ./solaris-nm
+NM = $(PATH1)/solaris-nm
 ASSEM_SRC = sparc-assem.S
 ARCH_SRC = sparc-arch.c
 
diff --git a/lisp/os-common.c b/lisp/os-common.c
index 26815657d..16fbee750 100644
--- a/lisp/os-common.c
+++ b/lisp/os-common.c
@@ -1,6 +1,6 @@
 /*
 
- $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/os-common.c,v 1.6 2002/08/28 13:29:25 pmai Exp $
+ $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/os-common.c,v 1.7 2002/10/24 20:38:59 toy Exp $
 
  This code was written as part of the CMU Common Lisp project at
  Carnegie Mellon University, and has been placed in the public domain.
@@ -104,7 +104,11 @@ os_vm_address_t os_reallocate(os_vm_address_t addr, os_vm_size_t old_len,
 }
 
 #ifdef LINKAGE_TABLE
+
+/* These declarations are lies.  They actually take args, but are
+   never called by C.  Only by Lisp */
 extern void resolve_linkage_tramp(void);
+extern void call_into_c(void);
 
 /* In words */
 #define LINKAGE_DATA_ENTRY_SIZE 3
@@ -127,13 +131,29 @@ void os_foreign_linkage_init (void)
 	  = (struct vector *)PTR(data_vector->data[i]);
 	long type = fixnum_value(data_vector->data[i + 1]);
 	lispobj lib_list = data_vector->data[i + 2];
-	
+
+	/*
+         * Verify the "known" entries.  This had better match what
+         * init-foreign-linkage in new-genesis does!
+         */
 	if (i == 0) {
+#ifdef sparc
+	    if (type != 1 || strcmp((char *)symbol_name->data,
+				    "call_into_c")) {
+                fprintf(stderr, "linkage_data is %s but expected call_into_c\n",
+                        (char*)symbol_name->data);
+		lose("First element of linkage_data is bogus.\n");
+	    }
+	    arch_make_linkage_entry(i, &call_into_c, 1);
+#else
 	    if (type != 1 || strcmp((char *)symbol_name->data,
 				    "resolve_linkage_tramp")) {
+                fprintf(stderr, "linkage_data is %s but expected resolve_linkage_tramp\n",
+                        (char*)symbol_name->data);
 		lose("First element of linkage_data is bogus.\n");
 	    }
-	    arch_make_linkage_entry(0, &resolve_linkage_tramp, 1);
+	    arch_make_linkage_entry(i, &resolve_linkage_tramp, 1);
+#endif
 	    continue;
 	}
 	if (type == 2 && lib_list == NIL) {
@@ -147,6 +167,7 @@ void os_foreign_linkage_init (void)
 	} else {
 	    arch_make_lazy_linkage(i / LINKAGE_DATA_ENTRY_SIZE);
 	}
+
     }
 #endif /* LINKAGE_TABLE */
 }
@@ -215,6 +236,9 @@ unsigned long os_link_one_symbol(long entry)
     type = fixnum_value(data_vector->data[table_index + 1]);
     target_addr = os_dlsym((char *)symbol_name->data,
 			   data_vector->data[table_index + 2]);
+    fprintf(stderr, "Looked up %s symbol %s at %lx\n",
+            type == 1 ? "code" : "data",
+            (char*) symbol_name->data, (unsigned long) target_addr);
     if (!target_addr) {
 	undefined_foreign_symbol_trap((lispobj)data_vector->data[table_index]);
     }
diff --git a/lisp/solaris-os.c b/lisp/solaris-os.c
index 0c2e78e9d..67a317f07 100644
--- a/lisp/solaris-os.c
+++ b/lisp/solaris-os.c
@@ -1,5 +1,5 @@
 /*
- * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/solaris-os.c,v 1.4 2000/12/05 03:03:48 dtc Exp $
+ * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/solaris-os.c,v 1.5 2002/10/24 20:38:59 toy Exp $
  *
  * OS-dependent routines.  This file (along with os.h) exports an
  * OS-independent interface to the operating system VM facilities.
@@ -23,6 +23,9 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/param.h>
+
+#include <dlfcn.h>
+
 #define OS_PROTERR		SEGV_ACCERR
 #define OS_MAPERR		SEGV_MAPERR
 #define OS_HASERRNO(code)	((code)->si_errno != 0)
@@ -35,6 +38,9 @@
 /* To get memory map */
 #include "sparc-validate.h"
 
+/* For type_ListPointer and NIL */
+#include "internals.h"
+
 /* block size must be larger than the system page size */
 #define SPARSE_BLOCK_SIZE (1<<15)
 #define SPARSE_SIZE_MASK (SPARSE_BLOCK_SIZE-1)
@@ -447,3 +453,41 @@ void make_holes(void)
   os_protect(hole, HOLE_SIZE, 0);
 }
 
+/* Some symbols, most notably stat and lstat, don't appear at all in
+   the glibc .so files as a result of preprocessor and linker magic /
+   braindamage.  So, try falling back to a stub in linux-stubs.S that
+   will call the proper function if it's one of those. */
+
+static void *dlsym_fallback(void *handle, const char *name)
+{
+  fprintf(stderr, "dlsym_fallback name = %s\n", name);
+}
+
+void *os_dlsym(const char *sym_name, lispobj lib_list)
+{
+    static void *program_handle;
+    void *sym_addr = 0;
+
+    if (!program_handle)
+	program_handle = dlopen((void *)0, RTLD_LAZY | RTLD_GLOBAL);
+    if (lib_list != NIL) {
+	lispobj lib_list_head;
+
+	for (lib_list_head = lib_list;
+	     lib_list_head != NIL;
+	     lib_list_head = (CONS(lib_list_head))->cdr) {
+	    struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
+	    struct sap *dlhandle = (struct sap *)PTR(lib_cons->car);
+
+	    sym_addr = dlsym((void *)dlhandle->pointer, sym_name);
+	    if (sym_addr)
+		return sym_addr;
+	}
+    }
+    sym_addr = dlsym(program_handle, sym_name);
+    if (!sym_addr && dlerror()) {
+	return dlsym_fallback(program_handle,sym_name);
+    } else {
+	return sym_addr;
+    }
+}
diff --git a/lisp/sparc-arch.c b/lisp/sparc-arch.c
index 68e610f79..35f7ef462 100644
--- a/lisp/sparc-arch.c
+++ b/lisp/sparc-arch.c
@@ -1,6 +1,6 @@
 /*
 
- $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/sparc-arch.c,v 1.11 2002/05/02 21:09:33 toy Exp $
+ $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/sparc-arch.c,v 1.12 2002/10/24 20:39:00 toy Exp $
 
  This code was written as part of the CMU Common Lisp project at
  Carnegie Mellon University, and has been placed in the public domain.
@@ -416,3 +416,139 @@ lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
 
     return call_into_lisp(function, args, 3);
 }
+
+#ifdef LINKAGE_TABLE
+
+/* This is mostly stolen from the x86 version, with adjustments for sparc */
+
+/*
+ * Linkage entry size is 16, because we need at least 3 instruction to
+ * implement a jump:
+ *
+ *      sethi %hi(addr), %g4
+ *      jmpl  [%g4 + %lo(addr)], %g5
+ *      nop
+ *
+ * The Sparc V9 ABI seems to use 8 words for its jump tables.  Maybe
+ * we should do the same?
+ */
+
+/*
+ * This had better match lisp::target-foreign-linkage-entry-size in
+ * sparc/parms.lisp!  Each entry is 4 instructions long, so 16 bytes.
+ */
+#ifndef LinkageEntrySize
+#define LinkageEntrySize (4*4)
+#endif
+
+
+/*
+ * Define the registers to use in the linkage jump table.  Can be the
+ * same.  This MUST be coordinated with resolve_linkage_tramp which
+ * needs to know the register used for LINKAGE_ADDR_REG.
+ *
+ * Some care must be exercised when choosing these.  It has to be a
+ * register that is not otherwise being used.  reg_L0 is a good
+ * choice.  call_into_c trashes reg_L0 without preserving it, so we
+ * can trash it in the linkage jump table.  For the linkage entries
+ * that call resolve_linkage_tramp, we can use reg_L0 too because
+ * resolve_linkage_tramp is always called from call_into_c.  (This is
+ * enforced by having new-genesis create an entry for call_into_c, so
+ * we never have to do a lookup for call_into_c.)
+ */
+#define LINKAGE_TEMP_REG        reg_L0
+#define LINKAGE_ADDR_REG        reg_L0
+
+/*
+ * Insert the necessary jump instructions at the given address.
+ * Return the address of the next word
+ */
+void* arch_make_jump_entry(void* reloc_addr, void *target_addr)
+{
+  
+  /*
+   * Make JMP to function entry.
+   *
+   * The instruction sequence is:
+   *
+   *        sethi %hi(addr), temp_reg
+   *        jmp   %temp_reg + %lo(addr), %addr_reg
+   *        nop
+   *        nop
+   *        
+   */
+  int* inst_ptr;
+  unsigned long hi;                   /* Top 22 bits of address */
+  unsigned long lo;                   /* Low 10 bits of address */
+  unsigned int inst;
+
+  inst_ptr = (int*) reloc_addr;
+
+  /*
+   * Split the target address into hi and lo parts for the sethi
+   * instruction.  hi is the top 22 bits.  lo is the low 10 bits.
+   */
+  hi = (unsigned long) target_addr;
+  lo = hi & 0x3ff;
+  hi >>= 10;
+
+  /*
+   * sethi %hi(addr), temp_reg
+   */
+      
+  inst = (0 << 30) | (LINKAGE_TEMP_REG << 25) | (4 << 22) | hi;
+  *inst_ptr++ = inst;
+
+  /*
+   * jmpl [temp_reg + %lo(addr)], addr_reg
+   */
+
+  inst = (2 << 30) | (LINKAGE_ADDR_REG << 25) | (0x38 << 19)
+    | (LINKAGE_TEMP_REG << 14) | (1 << 13) | lo;
+  *inst_ptr++ = inst;
+
+  /* nop (really sethi 0, %g0) */
+
+  inst = (0 << 30) | (0 << 25) | (4 << 22) | 0;
+      
+  *inst_ptr++ = inst;
+  *inst_ptr++ = inst;
+  
+  os_flush_icache(reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
+  return reloc_addr;
+}
+
+void arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
+{
+  int *reloc_addr = (int *)(FOREIGN_LINKAGE_SPACE_START
+                            + linkage_entry * LinkageEntrySize);
+
+  if (type == 1)
+    {			/* code reference */
+      arch_make_jump_entry(reloc_addr, target_addr);
+    }
+  else if (type == 2)
+    {
+      *(unsigned long *)reloc_addr = (unsigned long)target_addr;
+    }
+}
+
+/* Make a the entry a jump to resolve_linkage_tramp. */
+
+extern void resolve_linkage_tramp(void);
+
+void arch_make_lazy_linkage(long linkage_entry)
+{
+  arch_make_linkage_entry(linkage_entry, (void*) resolve_linkage_tramp, 1);
+}
+
+/* Get linkage entry.  We're given the return address which should be
+   the address of the jmpl instruction (2nd word) of the linkage
+   entry.  Figure out which entry this address belong to. */
+
+long arch_linkage_entry(unsigned long retaddr)
+{
+  return (retaddr - (FOREIGN_LINKAGE_SPACE_START))
+    / LinkageEntrySize;
+}
+#endif /* LINKAGE_TABLE */
diff --git a/lisp/sparc-assem.S b/lisp/sparc-assem.S
index 37a5653e8..d5d1cd802 100644
--- a/lisp/sparc-assem.S
+++ b/lisp/sparc-assem.S
@@ -17,6 +17,11 @@
 #define _function_end_breakpoint_guts function_end_breakpoint_guts
 #define _call_into_c call_into_c
 #define _flush_icache flush_icache
+#ifdef LINKAGE_TABLE
+#define _resolve_linkage_tramp resolve_linkage_tramp
+#define	_lazy_resolve_linkage	lazy_resolve_linkage
+#define	_undefined_foreign_symbol_trap	undefined_foreign_symbol_trap
+#endif		
 #ifdef __STDC__
 #define FUNCDEF(x)	.type x, \#function
 #else
@@ -53,7 +58,7 @@
 #ifdef v8plus	
 #define FRAMESIZE (SA(WINDOWSIZE+4 + 6*8))
 #else	
-#define FRAMESIZE (SA(WINDOWSIZE+4))
+#define FRAMESIZE (SA(MINFRAME))
 #endif
         .seg    "text"
         .global _call_into_lisp
@@ -186,6 +191,7 @@ _call_into_c:
         store(reg_BSP,_current_binding_stack_pointer)
         store(reg_CSP,_current_control_stack_pointer)
         store(reg_CFP,_current_control_frame_pointer)
+
 	/* Use reg_CFP as a work register, and restore it */
 	andn	reg_ALLOC, 7, reg_CFP
         store(reg_CFP,_current_dynamic_space_free_pointer)
@@ -349,6 +355,69 @@ _flush_icache:
         nop
 	SET_SIZE(_flush_icache)
 
+#ifdef LINKAGE_TABLE
+/*
+ * Call into C code to resolve a linkage entry.
+ *
+ * We get here by Lisp calling call_into_c with an address of the
+ * desired function which is contained in the register reg_CFUNC (aka
+ * %i4, aka %r28).  This is the address of the entry in the linkage
+ * table, which is what we need to figure out what function we really
+ * wanted.
+ *
+ * Note that because we get here from call_into_c, all necessary live
+ * registers have been saved, including FP registers.  Hence, no need
+ * to save them.
+ */
+	.global _lazy_resolve_linkage
+	.global _resolve_linkage_tramp
+	FUNCDEF(_resolve_linkage_tramp)
+_resolve_linkage_tramp:
+	/*
+	 * At this point, all of the global %g registers have been
+	 * saved by call_into_c, so we can use them as temps.  %g2,
+	 * aka reg_NIL, aka null-tn is a good choice.  reg_L0 contains
+	 * the address of the jmpl instruction in the linkage jump
+	 * table.  (See sparc-arch.c.)
+	 */
+
+	mov	reg_L0, reg_NIL
+		
+	/* 
+	 * New stack frame so the %o regs become %i.  We can't touch
+	 * the original %o because they contain the parameters to the
+	 * function!
+	 */
+	save	%sp, -FRAMESIZE, %sp
+
+	/* %g2 tells where we came from in the linkage table */
+	call	_lazy_resolve_linkage
+	mov	reg_NIL, %o0		! in the delay slot
+
+	mov	%o0, reg_NIL
+	restore	%sp, FRAMESIZE, %sp
+
+	/* And away we go! */
+	jmp	reg_NIL
+	nop
+	
+	SET_SIZE(_resolve_linkage_tramp)						
+		
+	.global _undefined_foreign_symbol_trap
+	FUNCDEF(_undefined_foreign_symbol_trap)
+_undefined_foreign_symbol_trap:	
+	unimp	trap_Error
+	.byte	2	/* Number of argument bytes */
+	.byte	UNDEFINED_FOREIGN_SYMBOL_ERROR
+        /* Escape to create 16bit BE number from following two values */
+        .byte	254
+        /* SC_OFFSET(sc_DescriptorReg,NL0) NL0 = %o0 */
+	.byte	sc_NonDescriptorReg
+	.byte	0
+	.align	4
+					
+#endif
+											
 #ifndef SOLARIS
 
 /****************************************************************\
diff --git a/lisp/sparc-validate.h b/lisp/sparc-validate.h
index 29d268271..53898faf5 100644
--- a/lisp/sparc-validate.h
+++ b/lisp/sparc-validate.h
@@ -1,6 +1,6 @@
 /*
 
- $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/sparc-validate.h,v 1.10 2000/10/27 19:32:03 dtc Exp $
+ $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/sparc-validate.h,v 1.11 2002/10/24 20:39:00 toy Exp $
 
  This code was written as part of the CMU Common Lisp project at
  Carnegie Mellon University, and has been placed in the public domain.
@@ -41,6 +41,25 @@
  * initialization.)
  *
  */
+
+#ifdef LINKAGE_TABLE
+/*
+ * This space start better match the value of
+ * target-foreign-linkage-space-start defined in sparc/parms.lisp!
+ *
+ * See the notes there!
+ */
+#define FOREIGN_LINKAGE_SPACE_START (0x0f800000)
+
+/*
+ * This allows for about 510K symbols (assuming each entry is 16 bytes
+ * long).  Hope that's enough!  Make sure this doesn't overlap the
+ * READ_ONLY_SPACE_START!
+ */
+#define FOREIGN_LINKAGE_SPACE_SIZE  (0x007f8000) /* 8 MB - 32 KB */
+#endif
+
+
 #define READ_ONLY_SPACE_START	(0x10000000)
 #define READ_ONLY_SPACE_SIZE	(0x07ff8000) /* 128 MB - 32 KB, 256 MB max */
   
-- 
GitLab