1 ;;;; X86-64-specific runtime stuff
3 ;;;; This software is part of the SBCL system. See the README file for
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.
13 (defun machine-type ()
14 "Return a string describing the type of the local machine."
17 ;;;; :CODE-OBJECT fixups
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
))
28 (let ((sap (code-instructions code
)))
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
))))
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
))))
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.
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
)
49 ;; JMP/CALL are relative to the next instruction,
50 ;; so add 4 bytes for the size of the displacement itself.
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.
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.
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
)))))
72 (defun sanctify-for-execution (code)
73 (let ((fixups (%code-fixups code
)))
75 (setf (%code-fixups code
) (sb!c
::pack-code-fixup-locs fixups
))))
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
)
89 (warn "stub CONTEXT-FLOAT-REGISTER")
91 #!+(or darwin linux win32
)
92 (let ((sap (alien-sap (context-float-register-addr context index
))))
95 (sap-ref-single sap
0))
97 (sap-ref-double sap
0))
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
))
109 (warn "stub %SET-CONTEXT-FLOAT-REGISTER")
112 (let ((sap (alien-sap (context-float-register-addr context index
))))
115 (setf (sap-ref-single sap
0) value
))
117 (setf (sap-ref-double sap
0) value
))
118 (complex-single-float
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
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.
132 (defun context-floating-point-modes (context)
133 (declare (ignore context
)) ; stub!
134 (warn "stub CONTEXT-FLOATING-POINT-MODES")
137 (define-alien-routine ("os_context_fp_control" context-floating-point-modes
)
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=..")
158 (let* ((pc (context-pc context
))
159 (trap-number (sap-ref-8 pc
0)))
160 (declare (type system-area-pointer 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
)
166 (let ((error-number (sap-ref-8 pc
1)))
168 (sb!kernel
::decode-internal-error-args
(sap+ pc
2) error-number
)
172 ;;; the current alien stack pointer; saved/restored for non-local exits
173 (defvar *alien-stack-pointer
*)
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
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
198 fun-pointer-lowtag
))) ; = 5
199 (setf (sap-ref-32 sap
7) (logior (ash disp8
24) #x408B48
))
201 (setf (sap-ref-32 sap i
) #xFD60FF
))) ; JMP [RAX-3]
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
))))
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]
221 (defun %set-fdefn-fun
(fdefn fun
)
222 (declare (type fdefn fdefn
) (type function fun
)
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.
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
)
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)
248 ;; Allow negative displacement
249 (ash (ldb (byte 32 0) displacement
) 8) ; JMP opcode
251 (sap-ref-lispobj (int-sap fdefn-addr
) (ash fdefn-fun-slot word-shift
))
255 ;;; Find an immobile FDEFN or FUNCTION given an interior pointer to it.
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
))
262 (case (sap-ref-8 (int-sap obj
) 0)
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
))
277 ;;; Compute the PC that FDEFN will jump to when called.
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