0.9.2.26: refactoring internals of foreign linkage
[sbcl.git] / src / code / foreign.lisp
1 ;;;; Foreign symbol linkage
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!IMPL")
13
14 #!-(or elf mach-o)
15 (error "Not an ELF or Mach-O platform?")
16
17 (defun extern-alien-name (name)
18   (handler-case
19       #!+elf (coerce name 'base-string)
20       #!+mach-o (concatenate 'base-string "_" name)
21     (error ()
22       (error "invalid external alien name: ~S" name))))
23
24 ;;; *STATIC-FOREIGN-SYMBOLS* are static as opposed to "dynamic" (not
25 ;;; as opposed to C's "extern"). The table contains symbols known at
26 ;;; the time that the program was built, but not symbols defined in
27 ;;; object files which have been loaded dynamically since then.
28 (declaim (type hash-table *static-foreign-symbols*))
29 (defvar *static-foreign-symbols* (make-hash-table :test 'equal))
30
31 (declaim 
32  (ftype (sfunction (string hash-table) (or integer null)) find-foreign-symbol-in-table))
33 (defun find-foreign-symbol-in-table (name table)
34   (let ((extern (extern-alien-name name)))
35     (values 
36      (or (gethash extern table)
37          (gethash (concatenate 'base-string "ldso_stub__" extern) table)))))
38
39 (defun find-foreign-symbol-address (name)
40   "Returns the address of the foreign symbol NAME, or NIL. Does not enter the
41 symbol in the linkage table, and never returns an address in the linkage-table."
42   (or (find-foreign-symbol-in-table name *static-foreign-symbols*)
43       (find-dynamic-foreign-symbol-address name)))
44
45 (defun foreign-symbol-address (name &optional datap)
46   "Returns the address of the foreign symbol NAME. DATAP must be true if the
47 symbol designates a variable (used only on linkage-table platforms). Returns a
48 secondary value that is true if DATAP was true and the symbol is a dynamic
49 foreign symbol.
50
51 On linkage-table ports the returned address is always static: either direct
52 address of a static symbol, or the linkage-table address of a dynamic one.
53 Dynamic symbols are entered into the linkage-table if they aren't there already.
54
55 On non-linkage-table ports signals an error if the symbol isn't found."
56   (let ((static (find-foreign-symbol-in-table name  *static-foreign-symbols*)))
57     (if static
58         (values static nil)
59         #!+os-provides-dlopen
60         (progn
61           #-sb-xc-host
62           (values #!-linkage-table
63                   (ensure-dynamic-foreign-symbol-address name)
64                   #!+linkage-table
65                   (ensure-foreign-symbol-linkage name datap)
66                   t)
67           #+sb-xc-host
68           (error 'undefined-alien-error :name name))
69         #!-os-provides-dlopen
70         (error 'undefined-alien-error :name name))))
71
72 (defun foreign-symbol-sap (symbol &optional datap)
73   "Returns a SAP corresponding to the foreign symbol. DATAP must be true if the
74 symbol designates a variable (used only on linkage-table platforms). May enter
75 the symbol into the linkage-table. On non-linkage-table ports signals an error
76 if the symbol isn't found."
77   (declare (ignorable datap))
78   #!-linkage-table
79   (int-sap (foreign-symbol-address symbol))
80   #!+linkage-table
81   (multiple-value-bind (addr sharedp)
82       (foreign-symbol-address symbol datap)
83     #+sb-xc-host
84     (aver (not sharedp))
85     ;; If the address is from linkage-table and refers to data
86     ;; we need to do a bit of juggling. It is not the address of the
87     ;; variable, but the address where the real address is stored.
88     (if (and sharedp datap)
89         (int-sap (sap-ref-word (int-sap addr) 0))
90         (int-sap addr))))
91
92 #-sb-xc-host
93 (defun foreign-reinit ()
94   #!+os-provides-dlopen
95   (reopen-shared-objects)
96   #!+linkage-table
97   (update-linkage-table))
98
99 ;;; Cleanups before saving a core
100 #-sb-xc-host
101 (defun foreign-deinit ()
102   #!+(and os-provides-dlopen (not linkage-table))
103   (when (dynamic-foreign-symbols-p)
104     (warn "~@<Saving cores with alien definitions referring to non-static ~
105            foreign symbols is unsupported on this platform: references to ~
106            such foreign symbols from the restarted core will not work. You ~
107            may be able to work around this limitation by reloading all ~
108            foreign definitions and code using them in the restarted core, ~
109            but no guarantees.~%~%Dynamic foreign symbols in this core: ~
110            ~{~A~^, ~}~:@>" (list-dynamic-foreign-symbols)))
111   #!+os-provides-dlopen
112   (close-shared-objects))
113
114 (defun sap-foreign-symbol (sap)
115   (declare (ignorable sap))
116   #-sb-xc-host
117   (let ((addr (sap-int sap)))
118     (declare (ignorable addr))
119     #!+linkage-table
120     (when (<= sb!vm:linkage-table-space-start
121               addr
122               sb!vm:linkage-table-space-end)
123       (maphash (lambda (name info)
124                  (let ((table-addr (linkage-info-address info)))
125                    (when (<= table-addr
126                              addr
127                              (+ table-addr sb!vm:linkage-table-entry-size))
128                      (return-from sap-foreign-symbol name))))
129                *linkage-info*))
130     #!+os-provides-dladdr
131     (with-alien ((info (struct dl-info
132                                (filename c-string)
133                                (base unsigned)
134                                (symbol c-string)
135                                (symbol-address unsigned)))
136                  (dladdr (function unsigned unsigned (* (struct dl-info)))
137                          :extern "dladdr"))
138       (let ((err (alien-funcall dladdr addr (addr info))))
139         (if (zerop err)
140             nil
141             (slot info 'symbol))))
142     ;; FIXME: Even in the absence of dladdr we could search the
143     ;; static foreign symbols (and *linkage-info*, for that matter).
144     ))
145
146 ;;; How we learn about foreign symbols and dlhandles initially
147 (defvar *!initial-foreign-symbols*)
148
149 #-sb-xc-host
150 (defun !foreign-cold-init ()
151   (dolist (symbol *!initial-foreign-symbols*)
152     (setf (gethash (car symbol) *static-foreign-symbols*) (cdr symbol)))
153   #!+os-provides-dlopen
154   (setf *runtime-dlhandle* (dlopen-or-lose)
155         *shared-objects* nil))
156
157 #!-os-provides-dlopen
158 (define-unsupported-fun load-shared-object)