Is there a way to get sbcl to print out the value of a CPU register?
assembly, common-lisp, cpu-registers, sbcl, x86-64
Solution
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.
Problem
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?