Is there a way I can get SBCL to take the value of a CPU register at a certain point in my program and print it as an integer?
Would I have to use gdb?
Steel Bank Common Lisp (SBCL) is a high performance Common Lisp compiler. It is open source / free software, with a permissive license.
Common Lisp is AOT compiled to the metal so it starts up fast and runs fast. CL is often within a factor of 2 of C speed and dramatically faster than plain Python.
Running SBCL To quit SBCL, type (quit) .
Yes, you can access CPU registers by using VOPs (Virtual Operations). In VOPs you can write code also in assembly, so in that sense you can use VOPs like gcc extended assembly.
So, here's an example VOP and a related function for executing it. The get-cpuid-eax
VOP receives two unsigned 32-bit arguments as input, stores them in eax
and ecx
, executes cpuid
instruction, and returns the value of eax
register after the cpuid
to get-cpuid-eax
function that called the VOP. The get-cpuid-eax
function then stores the value in *result*
. You can print the value easily with (format t "~a" *result*)
.
Note: there is some problem (bug in SBCL or in my code?) that causes this code not to execute without problems always. Recompiling and reloading usually helps. I have confirmed the cpuid
eax
output with both gcc
extended assembly and running a x86-64 assembly program in gdb
. All give the same results for same values in eax
and ecx
.
Edit: changed function & VOP names to get-cpuid-eax
to avoid confusion with variable names.
Edit: fixed code formatting with slimv.
(sb-vm::defknown get-cpuid-eax ((unsigned-byte 32) (unsigned-byte 32)) (unsigned-byte 32) (sb-c::foldable sb-c::flushable sb-c::movable)) (sb-vm::define-vop (get-cpuid-eax) (:policy :fast-safe) (:translate get-cpuid-eax) (:args (my-eax :scs (sb-vm::unsigned-reg) :target eax) (my-ecx :scs (sb-vm::unsigned-reg) :target ecx)) (:arg-types sb-vm::unsigned-num sb-vm::unsigned-num) (:temporary (:sc sb-vm::unsigned-reg :offset sb-vm::eax-offset) eax) (:temporary (:sc sb-vm::unsigned-reg :offset sb-vm::ecx-offset) ecx) (:results (my-result :scs (sb-vm::unsigned-reg))) (:result-types sb-vm::unsigned-num) (:generator 0 (sb-vm::move eax my-eax) (sb-vm::move ecx my-ecx) (sb-vm::inst cpuid) (sb-vm::move my-result eax))) (defun get-cpuid-eax (my-eax my-ecx) (declare (type (unsigned-byte 32) my-eax my-ecx) (optimize (speed 3) (safety 0))) (defparameter *result* (get-cpuid-eax my-eax my-ecx)))
Some websites with short VOPs which I found very useful while coding this:
Dmitry Kaliyanov's article "Добавление примитивов виртуальной машины SBCL" ("Adding primitive virtual machines of SBCL", in Russian)
the Lisp code for Dmitry Kaliyanov's article (above)
Dmitry Ignatiev's blog entry: SBCL, x86, SSE (in Russian)
Christophe Rhodes' presentation slides (pdf): Unportable but fun: Using SBCL Internals
kurohuku's blog entry: "SBCLでCPUID" (in Japanese)
swap-bytes source code file sbcl-vops.lisp
Hope this helps.
Another source of a cpuid example (that supports 64bit too) is from the excellent stmx library for CL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With