0.8.21.21: fix & share EXTERN-ALIEN-NAME logic (fixes bug #373)
[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 (defun find-foreign-symbol-in-table (name table)
32   (let ((extern (extern-alien-name name)))
33     (or (gethash extern table)
34         (gethash (concatenate 'base-string "ldso_stub__" extern) table))))
35
36 (defun foreign-symbol-address-as-integer-or-nil (name &optional datap)
37   (declare (ignorable datap))
38   (or (find-foreign-symbol-in-table name  *static-foreign-symbols*)
39       #!+os-provides-dlopen
40       (progn
41         #-sb-xc-host
42         (values #!-linkage-table
43                 (get-dynamic-foreign-symbol-address name datap)
44                 #!+linkage-table
45                 (ensure-foreign-symbol-linkage name datap)
46                 t))))
47
48 (defun foreign-symbol-address-as-integer (name &optional datap)
49   (or (foreign-symbol-address-as-integer-or-nil name datap)
50       (error "Unknown foreign symbol: ~S" name)))
51
52 (defun foreign-symbol-address (symbol &optional datap)
53   (declare (ignorable datap))
54   #!-linkage-table
55   (int-sap (foreign-symbol-address-as-integer symbol))
56   #!+linkage-table
57   (multiple-value-bind (addr sharedp)
58       (foreign-symbol-address-as-integer symbol datap)
59     #+sb-xc-host
60     (aver (not sharedp))
61     ;; If the address is from linkage-table and refers to data
62     ;; we need to do a bit of juggling.
63     (if (and sharedp datap)
64         (int-sap (sap-ref-word (int-sap addr) 0))
65         (int-sap addr))))
66
67 #-sb-xc-host
68 (defun foreign-reinit ()
69   #!+os-provides-dlopen
70   (reopen-shared-objects)
71   #!+linkage-table
72   (update-linkage-table))
73
74 ;;; Cleanups before saving a core
75 #-sb-xc-host
76 (defun foreign-deinit ()
77   ;; KLUDGE: Giving this warning only when non-static foreign symbols
78   ;; are used would be much nicer, but actually pretty hard: we can
79   ;; get dynamic symbols thru the runtime as well, so cheking the
80   ;; list of *shared-objects* is not enough. Eugh & blech.
81   #!+(and os-provides-dlopen (not linkage-table))
82   (when (dynamic-foreign-symbols)
83     (warn "~@<Saving cores with alien definitions referring to non-static ~
84            foreign symbols is unsupported on this platform: references to ~
85            such foreign symbols from the restarted core will not work. You ~
86            may be able to work around this limitation by reloading all ~
87            foreign definitions and code using them in the restarted core, ~
88            but no guarantees.~%~%Dynamic foreign symbols in this core: ~
89            ~{~A~^, ~}~:@>" (dynamic-foreign-symbols)))
90   #!+os-provides-dlopen
91   (close-shared-objects))
92
93 (defun foreign-symbol-in-address (sap)
94   (declare (ignorable sap))
95   #-sb-xc-host
96   (let ((addr (sap-int sap)))
97     (declare (ignorable addr))
98     #!+linkage-table
99     (when (<= sb!vm:linkage-table-space-start
100               addr
101               sb!vm:linkage-table-space-end)
102       (maphash (lambda (name info)
103                  (let ((table-addr (linkage-info-address info)))
104                    (when (<= table-addr
105                              addr
106                              (+ table-addr sb!vm:linkage-table-entry-size))
107                      (return-from foreign-symbol-in-address name))))
108                *linkage-info*))
109     #!+os-provides-dladdr
110     (with-alien ((info (struct dl-info
111                                (filename c-string)
112                                (base unsigned)
113                                (symbol c-string)
114                                (symbol-address unsigned)))
115                  (dladdr (function unsigned unsigned (* (struct dl-info)))
116                          :extern "dladdr"))
117       (let ((err (alien-funcall dladdr addr (addr info))))
118         (if (zerop err)
119             nil
120             (slot info 'symbol))))
121     ;; FIXME: Even in the absence of dladdr we could search the
122     ;; static foreign symbols (and *linkage-info*, for that matter).
123     ))
124
125 ;;; How we learn about foreign symbols and dlhandles initially
126 (defvar *!initial-foreign-symbols*)
127
128 #-sb-xc-host
129 (defun !foreign-cold-init ()
130   (dolist (symbol *!initial-foreign-symbols*)
131     (setf (gethash (car symbol) *static-foreign-symbols*) (cdr symbol)))
132   #!+os-provides-dlopen
133   (setf *runtime-dlhandle* (dlopen-or-lose)
134         *shared-objects* nil))
135
136 #!-os-provides-dlopen
137 (define-unsupported-fun load-shared-object)