From de6d4c2fc663eb1caeb6b4fd114866413fb56a41 Mon Sep 17 00:00:00 2001 From: Lutz Euler Date: Wed, 14 Dec 2011 18:11:53 +0100 Subject: [PATCH] x86: Better disassembly of segment-prefixes. 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 | 4 ++- src/compiler/x86/insts.lisp | 57 +++++++++++++++++++++++++----------- src/compiler/x86/target-insts.lisp | 1 + 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/NEWS b/NEWS index cec67b6..1f3e208 100644 --- 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 diff --git a/src/compiler/x86/insts.lisp b/src/compiler/x86/insts.lisp index e5373bd..c779a8b 100644 --- a/src/compiler/x86/insts.lisp +++ b/src/compiler/x86/insts.lisp @@ -48,13 +48,11 @@ ;;; 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. @@ -154,6 +152,12 @@ (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 @@ -218,6 +222,16 @@ (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)) @@ -349,6 +363,11 @@ (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) @@ -405,6 +424,10 @@ (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) @@ -965,6 +988,16 @@ (: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 @@ -1186,16 +1219,6 @@ (emit-byte segment #xf3) (emit-byte segment #x90))) -(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. diff --git a/src/compiler/x86/target-insts.lisp b/src/compiler/x86/target-insts.lisp index b51b9f5..c761ee0 100644 --- a/src/compiler/x86/target-insts.lisp +++ b/src/compiler/x86/target-insts.lisp @@ -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) -- 1.7.10.4