x86: Better disassembly of segment-prefixes.
authorLutz Euler <lutz.euler@freenet.de>
Wed, 14 Dec 2011 17:11:53 +0000 (18:11 +0100)
committerLutz Euler <lutz.euler@freenet.de>
Wed, 14 Dec 2011 17:11:53 +0000 (18:11 +0100)
Thanks to Alastair Bridgewater who originally provided these changes
(and the headline above). I adapted his work to fit into the prefix
instruction infrastructure now available. Of his original comments
the following three still apply:

  * Establish a SEG prefix for segment overrides similar
to the X66 data-width prefix.

  * Have the SEG prefilter set an instruction property
for the specific segment being used.

  * Alter PRINT-MEM-ACCESS to output a suitable prefix
for memory addresses when the appropriate instruction
property has been set.

I have abstracted out the segment prefix printing into the new function
MAYBE-PRINT-SEGMENT-OVERRIDE, called from PRINT-MEM-ACCESS, not to make
the latter more lengthy.

Here is an example to show the difference in disassembler output:

Old:

;      0E6:       64               FS-SEGMENT-PREFIX
;      0E7:       8910             MOV [EAX], EDX
;      0E9:       64               FS-SEGMENT-PREFIX
;      0EA:       8B0528000000     MOV EAX, [#x28]

New:

;      0E6:       648910           MOV FS:[EAX], EDX
;      0E9:       648B0528000000   MOV EAX, FS:[#x28]

NEWS
src/compiler/x86/insts.lisp
src/compiler/x86/target-insts.lisp

diff --git a/NEWS b/NEWS
index cec67b6..1f3e208 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -34,10 +34,12 @@ changes relative to sbcl-1.0.54:
   * enhancement: SBCL now provides either an explicit :BIG-ENDIAN or
     :LITTLE-ENDIAN in *FEATURES*, instead of :BIG-ENDIAN being implied by lack
     of the :LITTLE-ENDIAN feature. (Thanks to Luís Oliveira, lp#901661)
+  * enhancement: better disassembly of segment-prefixes on x86 and other
+    instruction prefixes (e.g. LOCK) on x86 and x86-64.
   * optimization: SUBSEQ on vectors of unknown element type is substantially
     faster. (lp#902537)
   * optimization: specialized arrays with non-zero :INITIAL-ELEMENT can
-    be stack-allocated. (lp#902351) 
+    be stack-allocated. (lp#902351)
   * optimization: the compiler is smarter about representation selection for
     floating point constants used in full calls.
   * optimization: the compiler no longer refuses to coerce large fixnums to
index e5373bd..c779a8b 100644 (file)
 ;;; correctly in all cases, so we copy the x86-64 version which at
 ;;; least can handle the code output by the compiler.
 ;;;
-;;; Width information for an instruction is stored as an inst-prop on
-;;; the dstate.  The inst-props are cleared automatically after each
-;;; instruction, must be set by prefilters, and contain a single bit
-;;; of data each (presence/absence).  As such, each instruction that
-;;; can emit an operand-size prefix (x66 prefix) needs to have a set
-;;; of printers declared for both the prefixed and non-prefixed
-;;; encodings.
+;;; Width information for an instruction and whether a segment
+;;; override prefix was seen is stored as an inst-prop on the dstate.
+;;; The inst-props are cleared automatically after each non-prefix
+;;; instruction, must be set by prefilters, and contain a single bit of
+;;; data each (presence/absence).
 
 ;;; Return the operand size based on the prefixes and width bit from
 ;;; the dstate.
   (declare (ignore dstate))
   (sb!disassem:princ16 value stream))
 
+(defun maybe-print-segment-override (stream dstate)
+  (cond ((sb!disassem:dstate-get-inst-prop dstate 'fs-segment-prefix)
+         (princ "FS:" stream))
+        ((sb!disassem:dstate-get-inst-prop dstate 'gs-segment-prefix)
+         (princ "GS:" stream))))
+
 ;;; Returns either an integer, meaning a register, or a list of
 ;;; (BASE-REG OFFSET INDEX-REG INDEX-SCALE), where any component
 ;;; may be missing or nil to indicate that it's not used or has the
            (type sb!disassem:disassem-state dstate))
   (sb!disassem:dstate-put-inst-prop dstate 'operand-size-16))
 
+;;; This prefilter is used solely for its side effect, namely to put
+;;; one of the properties [FG]S-SEGMENT-PREFIX into the DSTATE.
+;;; Unlike PREFILTER-X66, this prefilter only catches the low bit of
+;;; the prefix byte.
+(defun prefilter-seg (value dstate)
+  (declare (type bit value)
+           (type sb!disassem:disassem-state dstate))
+  (sb!disassem:dstate-put-inst-prop
+   dstate (elt '(fs-segment-prefix gs-segment-prefix) value)))
+
 (defun read-address (value dstate)
   (declare (ignore value))              ; always nil anyway
   (sb!disassem:read-suffix (width-bits *default-address-size*) dstate))
 (sb!disassem:define-arg-type x66
   :prefilter #'prefilter-x66)
 
+;;; Used to capture the effect of the #x64 and #x65 segment override
+;;; prefixes.
+(sb!disassem:define-arg-type seg
+  :prefilter #'prefilter-seg)
+
 (eval-when (:compile-toplevel :load-toplevel :execute)
 (defparameter *conditions*
   '((:o . 0)
 (sb!disassem:define-instruction-format (x66 8)
   (x66   :field (byte 8 0) :type 'x66 :value #x66))
 
+(sb!disassem:define-instruction-format (seg 8)
+  (seg   :field (byte 7 1) :value #x32)
+  (fsgs  :field (byte 1 0) :type 'seg))
+
 (sb!disassem:define-instruction-format (simple 8)
   (op    :field (byte 7 1))
   (width :field (byte 1 0) :type 'width)
     (:gs
      (emit-byte segment #x65))))
 
+(define-instruction fs (segment)
+  (:printer seg ((fsgs #b0)) nil :print-name nil)
+  (:emitter
+   (bug "FS prefix used as a standalone instruction")))
+
+(define-instruction gs (segment)
+  (:printer seg ((fsgs #b1)) nil :print-name nil)
+  (:emitter
+   (bug "GS prefix used as a standalone instruction")))
+
 (define-instruction lock (segment)
   (:printer byte ((op #b11110000)) nil)
   (:emitter
    (emit-byte segment #xf3)
    (emit-byte segment #x90)))
 \f
-(define-instruction fs-segment-prefix (segment)
-  (:printer byte ((op #b01100100)))
-  (:emitter
-   (bug "FS emitted as a separate instruction!")))
-
-(define-instruction gs-segment-prefix (segment)
-  (:printer byte ((op #b01100101)))
-  (:emitter
-   (bug "GS emitted as a separate instruction!")))
-
 ;;;; flag control instructions
 
 ;;; CLC -- Clear Carry Flag.
index b51b9f5..c761ee0 100644 (file)
@@ -23,6 +23,7 @@
   (when print-size-p
     (princ (inst-operand-size dstate) stream)
     (princ '| PTR | stream))
+  (maybe-print-segment-override stream dstate)
   (write-char #\[ stream)
   (let ((firstp t))
     (macrolet ((pel ((var val) &body body)