Pergunta

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?

Foi útil?

Solução

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.

Outras dicas

Another source of a cpuid example (that supports 64bit too) is from the excellent stmx library for CL.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top