Put assembly routines in immobile space if it exists
[sbcl.git] / src / code / x86-64-vm.lisp
blobae40c2d5d9815fa4f6112c7cd8e58b9a17089335
1 ;;;; X86-64-specific runtime stuff
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.
12 (in-package "SB!VM")
13 (defun machine-type ()
14 "Return a string describing the type of the local machine."
15 "X86-64")
17 ;;;; :CODE-OBJECT fixups
19 #!+immobile-space
20 (defun sb!kernel::immobile-space-obj-p (obj)
21 (<= immobile-space-start (get-lisp-obj-address obj) immobile-space-end))
23 ;;; This gets called by LOAD to resolve newly positioned objects
24 ;;; with things (like code instructions) that have to refer to them.
25 (defun fixup-code-object (code offset fixup kind &optional flavor)
26 (declare (type index offset) (ignorable flavor))
27 (without-gcing
28 (let ((sap (code-instructions code)))
29 (ecase kind
30 (:absolute64
31 ;; Word at sap + offset contains a value to be replaced by
32 ;; adding that value to fixup.
33 (setf (sap-ref-64 sap offset) (+ fixup (sap-ref-64 sap offset))))
34 (:absolute
35 ;; Word at sap + offset contains a value to be replaced by
36 ;; adding that value to fixup.
37 (setf (sap-ref-32 sap offset) (+ fixup (signed-sap-ref-32 sap offset))))
38 (:relative
39 ;; Fixup is the actual address wanted.
40 ;; Replace word with value to add to that loc to get there.
41 ;; In the #!-immobile-code case, there's nothing to assert.
42 ;; Relative fixups pretty much can't happen.
43 #!+immobile-code
44 (unless (<= immobile-space-start (get-lisp-obj-address code) immobile-space-end)
45 (error "Can't compute fixup relative to movable object ~S" code))
46 (setf (signed-sap-ref-32 sap offset)
47 (etypecase fixup
48 (integer
49 ;; JMP/CALL are relative to the next instruction,
50 ;; so add 4 bytes for the size of the displacement itself.
51 (- fixup
52 (the (unsigned-byte 64) (+ (sap-int sap) offset 4))))))))))
53 ;; An absolute fixup is stored in the code header if it
54 ;; references an immobile-space (but not static-space) object.
55 ;; This needn't be inside WITHOUT-GCING, because code fixups will point
56 ;; only to objects that don't move except during save-lisp-and-die.
57 ;; So there is no race with GC here.
58 ;; Note that:
59 ;; (1) :NAMED-CALL occurs in both :RELATIVE and :ABSOLUTE kinds.
60 ;; We can ignore the :RELATIVE kind.
61 ;; (2) :STATIC-CALL fixups point to immobile space, not static space.
62 ;; We don't record them.
63 #!+immobile-space
64 (when (and (eq kind :absolute)
65 (member flavor '(:named-call :layout :immobile-object)))
66 (let ((fixups (%code-fixups code)))
67 ;; Sanctifying the code component will compact these into a bignum.
68 (setf (%code-fixups code) (cons offset (if (eql fixups 0) nil fixups)))))
69 nil)
71 #!+immobile-space
72 (defun sanctify-for-execution (code)
73 (let ((fixups (%code-fixups code)))
74 (when (listp fixups)
75 (setf (%code-fixups code) (sb!c::pack-code-fixup-locs fixups))))
76 nil)
78 #!+(or darwin linux win32)
79 (define-alien-routine ("os_context_float_register_addr" context-float-register-addr)
80 (* unsigned) (context (* os-context-t)) (index int))
82 ;;; This is like CONTEXT-REGISTER, but returns the value of a float
83 ;;; register. FORMAT is the type of float to return.
85 (defun context-float-register (context index format)
86 (declare (ignorable context index))
87 #!-(or darwin linux win32)
88 (progn
89 (warn "stub CONTEXT-FLOAT-REGISTER")
90 (coerce 0 format))
91 #!+(or darwin linux win32)
92 (let ((sap (alien-sap (context-float-register-addr context index))))
93 (ecase format
94 (single-float
95 (sap-ref-single sap 0))
96 (double-float
97 (sap-ref-double sap 0))
98 (complex-single-float
99 (complex (sap-ref-single sap 0)
100 (sap-ref-single sap 4)))
101 (complex-double-float
102 (complex (sap-ref-double sap 0)
103 (sap-ref-double sap 8))))))
105 (defun %set-context-float-register (context index format value)
106 (declare (ignorable context index format))
107 #!-(or linux win32)
108 (progn
109 (warn "stub %SET-CONTEXT-FLOAT-REGISTER")
110 value)
111 #!+(or linux win32)
112 (let ((sap (alien-sap (context-float-register-addr context index))))
113 (ecase format
114 (single-float
115 (setf (sap-ref-single sap 0) value))
116 (double-float
117 (setf (sap-ref-double sap 0) value))
118 (complex-single-float
119 (locally
120 (declare (type (complex single-float) value))
121 (setf (sap-ref-single sap 0) (realpart value)
122 (sap-ref-single sap 4) (imagpart value))))
123 (complex-double-float
124 (locally
125 (declare (type (complex double-float) value))
126 (setf (sap-ref-double sap 0) (realpart value)
127 (sap-ref-double sap 8) (imagpart value)))))))
129 ;;; Given a signal context, return the floating point modes word in
130 ;;; the same format as returned by FLOATING-POINT-MODES.
131 #!-linux
132 (defun context-floating-point-modes (context)
133 (declare (ignore context)) ; stub!
134 (warn "stub CONTEXT-FLOATING-POINT-MODES")
136 #!+linux
137 (define-alien-routine ("os_context_fp_control" context-floating-point-modes)
138 (unsigned 32)
139 (context (* os-context-t)))
141 (define-alien-routine
142 ("arch_get_fp_modes" floating-point-modes) (unsigned 32))
144 (define-alien-routine
145 ("arch_set_fp_modes" %floating-point-modes-setter) void (fp (unsigned 32)))
147 (defun (setf floating-point-modes) (val) (%floating-point-modes-setter val))
150 ;;;; INTERNAL-ERROR-ARGS
152 ;;; Given a (POSIX) signal context, extract the internal error
153 ;;; arguments from the instruction stream.
154 (defun internal-error-args (context)
155 (declare (type (alien (* os-context-t)) context))
156 (/show0 "entering INTERNAL-ERROR-ARGS, CONTEXT=..")
157 (/hexstr context)
158 (let* ((pc (context-pc context))
159 (trap-number (sap-ref-8 pc 0)))
160 (declare (type system-area-pointer pc))
161 (/show0 "got PC")
162 ;; using INT3 the pc is .. INT3 <here> code length bytes...
163 (if (= trap-number invalid-arg-count-trap)
164 (values #.(error-number-or-lose 'invalid-arg-count-error)
165 '(#.arg-count-sc))
166 (let ((error-number (sap-ref-8 pc 1)))
167 (values error-number
168 (sb!kernel::decode-internal-error-args (sap+ pc 2) error-number)
169 trap-number)))))
172 ;;; the current alien stack pointer; saved/restored for non-local exits
173 (defvar *alien-stack-pointer*)
175 #!+immobile-code
176 (progn
177 (defun fun-immobilize (fun)
178 (let ((code (allocate-code-object t 0 16)))
179 (setf (%code-debug-info code) fun)
180 (let ((sap (code-instructions code))
181 (ea (+ (logandc2 (get-lisp-obj-address code) lowtag-mask)
182 (ash code-debug-info-slot word-shift))))
183 ;; For a funcallable-instance, the instruction sequence is:
184 ;; MOV RAX, [RIP-n] ; load the function
185 ;; MOV RAX, [RAX+5] ; load the funcallable-instance-fun
186 ;; JMP [RAX-3]
187 ;; Otherwise just instructions 1 and 3 will do.
188 ;; We could use the #xA1 opcode to save a byte, but that would
189 ;; be another headache do deal with when relocating this code.
190 ;; There's precedent for this style of hand-assembly,
191 ;; in arch_write_linkage_table_jmp() and arch_do_displaced_inst().
192 (setf (sap-ref-32 sap 0) #x058B48 ; REX MOV [RIP-n]
193 (signed-sap-ref-32 sap 3) (- ea (+ (sap-int sap) 7))) ; disp
194 (let ((i (if (/= (fun-subtype fun) funcallable-instance-widetag)
196 (let ((disp8 (- (ash funcallable-instance-function-slot
197 word-shift)
198 fun-pointer-lowtag))) ; = 5
199 (setf (sap-ref-32 sap 7) (logior (ash disp8 24) #x408B48))
200 11))))
201 (setf (sap-ref-32 sap i) #xFD60FF))) ; JMP [RAX-3]
202 code))
204 ;;; Return T if FUN can't be called without loading RAX with its descriptor.
205 ;;; This is true of any funcallable instance which is not a GF, and closures.
206 (defun fun-requires-simplifying-trampoline-p (fun)
207 (cond ((funcallable-instance-p fun)
208 ;; A funcallable-instance with no raw slots has no machine
209 ;; code within it, and thus requires an external trampoline.
210 (zerop (layout-bitmap (%funcallable-instance-layout fun))))
212 (closurep fun))))
214 (defun %set-fin-trampoline (fin)
215 (let ((sap (int-sap (- (get-lisp-obj-address fin) fun-pointer-lowtag)))
216 (insts-offs (ash (1+ funcallable-instance-info-offset) word-shift)))
217 (setf (sap-ref-word sap insts-offs) #xFFFFFFE9058B48 ; MOV RAX,[RIP-23]
218 (sap-ref-32 sap (+ insts-offs 7)) #x00FD60FF)) ; JMP [RAX-3]
219 fin)
221 (defun %set-fdefn-fun (fdefn fun)
222 (declare (type fdefn fdefn) (type function fun)
223 (values function))
224 (unless (eql (sb!vm::fdefn-has-static-callers fdefn) 0)
225 (sb!vm::remove-static-links fdefn))
226 (let ((trampoline (when (or (>= (get-lisp-obj-address fun) (ash 1 32))
227 (fun-requires-simplifying-trampoline-p fun))
228 (fun-immobilize fun)))) ; a newly made CODE object
229 (with-pinned-objects (fdefn trampoline fun)
230 (binding* (((fun-entry-addr nop-byte)
231 ;; The NOP-BYTE is an arbitrary value used to indicate the
232 ;; kind of callee in the FDEFN-RAW-ADDR slot.
233 ;; Though it should never be executed, it is a valid encoding.
234 (if trampoline
235 (values (sap-int (code-instructions trampoline)) #x90)
236 (values (sap-ref-word (int-sap (get-lisp-obj-address fun))
237 (- (ash simple-fun-self-slot word-shift)
238 fun-pointer-lowtag))
239 (if (simple-fun-p fun) 0 #x48))))
240 (fdefn-addr (- (get-lisp-obj-address fdefn) ; base of the object
241 other-pointer-lowtag))
242 (fdefn-entry-addr (+ fdefn-addr ; address that callers jump to
243 (ash fdefn-raw-addr-slot word-shift)))
244 (displacement (the (signed-byte 32)
245 (- fun-entry-addr (+ fdefn-entry-addr 5)))))
246 (setf (sap-ref-word (int-sap fdefn-entry-addr) 0)
247 (logior #xE9
248 ;; Allow negative displacement
249 (ash (ldb (byte 32 0) displacement) 8) ; JMP opcode
250 (ash nop-byte 40))
251 (sap-ref-lispobj (int-sap fdefn-addr) (ash fdefn-fun-slot word-shift))
252 fun)))))
253 ) ; end PROGN
255 ;;; Find an immobile FDEFN or FUNCTION given an interior pointer to it.
256 #!+immobile-space
257 (defun find-called-object (address)
258 (when (<= immobile-space-start address immobile-space-end)
259 (let ((obj (alien-funcall (extern-alien "search_immobile_space" (function long long))
260 address)))
261 (unless (eql obj 0)
262 (case (sap-ref-8 (int-sap obj) 0)
263 (#.fdefn-widetag
264 (make-lisp-obj (logior obj other-pointer-lowtag)))
265 (#.funcallable-instance-widetag
266 (make-lisp-obj (logior obj fun-pointer-lowtag)))
267 (#.code-header-widetag
268 (let ((code (make-lisp-obj (logior obj other-pointer-lowtag))))
269 (dotimes (i (code-n-entries code))
270 (let ((f (%code-entry-point code i)))
271 (if (= (+ (get-lisp-obj-address f)
272 (ash simple-fun-code-offset word-shift)
273 (- fun-pointer-lowtag))
274 address)
275 (return f)))))))))))
277 ;;; Compute the PC that FDEFN will jump to when called.
278 #!+immobile-code
279 (defun fdefn-call-target (fdefn)
280 (let ((pc (+ (get-lisp-obj-address fdefn)
281 (- other-pointer-lowtag)
282 (ash fdefn-raw-addr-slot word-shift))))
283 (+ pc 5 (signed-sap-ref-32 (int-sap pc) 1)))) ; 5 = length of JMP