diff graal/com.oracle.max.asmdis/src/com/sun/max/asm/dis/x86/X86Disassembler.java @ 3733:e233f5660da4

Added Java files from Maxine project.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 17 Dec 2011 19:59:18 +0100
parents
children bc8527f3071c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.asmdis/src/com/sun/max/asm/dis/x86/X86Disassembler.java	Sat Dec 17 19:59:18 2011 +0100
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.max.asm.dis.x86;
+
+import java.io.*;
+import java.util.*;
+
+import com.sun.max.*;
+import com.sun.max.asm.*;
+import com.sun.max.asm.amd64.*;
+import com.sun.max.asm.dis.*;
+import com.sun.max.asm.gen.*;
+import com.sun.max.asm.gen.cisc.x86.*;
+import com.sun.max.asm.x86.*;
+import com.sun.max.io.*;
+import com.sun.max.lang.*;
+import com.sun.max.program.*;
+import com.sun.max.util.*;
+
+/**
+ * An x86 instruction disassembler.
+ *
+ * The string representation for disassembler output has the following format,
+ * which borrows from both Intel and AT&T syntax and differs from either
+ * regarding indirect addressing and indexing.
+ *
+ * Operand order follows Intel syntax:
+ *
+ * mnemonic argument
+ * mnemonic destination, source
+ * mnemonic argument1, argument2, argument3
+ *
+ * Some mnemonics may have operand size suffixes as in AT&T (gas) syntax.
+ * Suffix    Intel size     Java size    # bits
+ * ------    -----------    ---------    ------
+ * b         byte           byte          8
+ * w         word           short        16
+ * l         long word      int          32
+ * q         quad word      long         64
+ *
+ * Using this AT&T syntax feature, there is no need for operand size indicators
+ * (e.g. DWORD PTR) for pointers as in Intel syntax.
+ *
+ * Registers etc. are named as in Intel syntax,
+ * in lower case without AT&T's "%" prefix.
+ *
+ * Indexing is indicated by '[' and ']', similiar to array access in the Java(TM) Programming Language:
+ *
+ * base[index], e.g. eax[ebx]
+ *
+ * Indirect access looks like indexing without a base (or with implicit base 0):
+ *
+ * [indirect], e.g. [ecx]
+ *
+ * Displacements are added/subtracted from the index/indirect operand:
+ *
+ * base[index + displacement], e.g. ebp[eax - 12]
+ * [indirect + displacement], e.g. [esi + 100]
+ *
+ * Scale is displayed as multiplication of the index:
+ *
+ * [base[index * scale] or base[index * scale + displacement], e.g. ecx[ebx * 4 + 10]
+ *
+ * A scale of 1 is left implicit, i.e. not printed.
+ * Scale literals are the unsigned decimal integer numbers 2, 4, 8.
+ *
+ * Displacement literals are signed decimal integer numbers.
+ *
+ * Direct memory references (pointer literals) are unsigned hexadecimal integer numbers, e.g.:
+ *
+ * [0x12345678], 0x12345678[eax]
+ *
+ * Immediate operands are unsigned hexadecimal integer numbers, e.g.:
+ *
+ * 0x12, 0xffff, 0x0, 0x123456789abcdef
+ *
+ * Offset operands are signed decimal integer numbers, like displacements, but without space between the sign and the number, e.g.:
+ *
+ * jmp +12
+ * call -2048
+ *
+ * RIP (Relative to Instruction Pointer) addressing is a combination of an offset operand and indirect addressing, e.g.:
+ *
+ * add [+20], eax
+ * mov ebx, [-200]
+ *
+ * The disassembler displays synthetic labels for all target addresses
+ * within the disassembled address range that hit the start address of an instruction.
+ * Operands that coincide with such a label are displayed with the respective Label prepended. e.g.:
+ *
+ * jmp L1: +100
+ * adc [L2: +128], ESI
+ *
+ * @see Disassembler
+ * @see X86DisassembledInstruction
+ */
+public abstract class X86Disassembler extends Disassembler {
+
+    private X86Assembly<? extends X86Template> assembly;
+
+    protected X86Disassembler(ImmediateArgument startAddress, X86Assembly<? extends X86Template> assembly, InlineDataDecoder inlineDataDecoder) {
+        super(startAddress, Endianness.LITTLE, inlineDataDecoder);
+        this.assembly = assembly;
+    }
+
+    protected abstract boolean isRexPrefix(HexByte opcode);
+
+    private X86InstructionHeader scanInstructionHeader(BufferedInputStream stream, boolean justSkip) throws IOException {
+        int byteValue = stream.read();
+        if (byteValue < 0) {
+            return null;
+        }
+        final X86InstructionHeader header = new X86InstructionHeader();
+
+        do {
+            final HexByte hexByte = HexByte.VALUES.get(byteValue);
+            if (header.opcode1 == null) {
+                if (hexByte == X86Opcode.ADDRESS_SIZE) {
+                    header.hasAddressSizePrefix = true;
+                } else if (hexByte == X86Opcode.OPERAND_SIZE) {
+                    if (header.instructionSelectionPrefix != null) {
+                        return X86InstructionHeader.INVALID;
+                    }
+                    header.instructionSelectionPrefix = hexByte;
+                } else if (hexByte == X86Opcode.REPE || hexByte == X86Opcode.REPNE) {
+                    if (header.instructionSelectionPrefix != null) {
+                        return X86InstructionHeader.INVALID;
+                    }
+                    header.instructionSelectionPrefix = hexByte;
+                } else if (isRexPrefix(hexByte)) {
+                    header.rexPrefix = hexByte;
+                } else {
+                    header.opcode1 = hexByte;
+                    if (hexByte != HexByte._0F) {
+                        break;
+                    }
+                }
+            } else {
+                header.opcode2 = hexByte;
+                break;
+            }
+            byteValue = stream.read();
+        } while (byteValue >= 0);
+
+        if (TRACE && !justSkip) {
+            System.out.println("Scanned header: " + header);
+        }
+
+        return justSkip ? null : header;
+    }
+
+    private List<Argument> scanArguments(BufferedInputStream stream, X86Template template, X86InstructionHeader header, byte modRMByte, byte sibByte) throws IOException {
+        final List<Argument> arguments = new ArrayList<Argument>();
+        final byte rexByte = (header.rexPrefix != null) ? header.rexPrefix.byteValue() : 0;
+        for (X86Parameter parameter : template.parameters()) {
+            int value = 0;
+            switch (parameter.place()) {
+                case MOD_REG_REXR:
+                    value = X86Field.extractRexValue(X86Field.REX_R_BIT_INDEX, rexByte);
+                    // fall through...
+                case MOD_REG:
+                    value += X86Field.REG.extract(modRMByte);
+                    break;
+                case MOD_RM_REXB:
+                    value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte);
+                    // fall through...
+                case MOD_RM:
+                    value += X86Field.RM.extract(modRMByte);
+                    break;
+                case SIB_BASE_REXB:
+                    value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte);
+                    // fall through...
+                case SIB_BASE:
+                    value += X86Field.BASE.extract(sibByte);
+                    break;
+                case SIB_INDEX_REXX:
+                    value = X86Field.extractRexValue(X86Field.REX_X_BIT_INDEX, rexByte);
+                    // fall through...
+                case SIB_INDEX:
+                    value += X86Field.INDEX.extract(sibByte);
+                    break;
+                case SIB_SCALE:
+                    value = X86Field.SCALE.extract(sibByte);
+                    break;
+                case APPEND:
+                    if (parameter instanceof X86EnumerableParameter) {
+                        final X86EnumerableParameter enumerableParameter = (X86EnumerableParameter) parameter;
+                        final Enumerator enumerator = enumerableParameter.enumerator();
+                        arguments.add((Argument) enumerator.fromValue(endianness().readByte(stream)));
+                        continue;
+                    }
+                    final X86NumericalParameter numericalParameter = (X86NumericalParameter) parameter;
+                    switch (numericalParameter.width()) {
+                        case BITS_8:
+                            arguments.add(new Immediate8Argument(endianness().readByte(stream)));
+                            break;
+                        case BITS_16:
+                            arguments.add(new Immediate16Argument(endianness().readShort(stream)));
+                            break;
+                        case BITS_32:
+                            arguments.add(new Immediate32Argument(endianness().readInt(stream)));
+                            break;
+                        case BITS_64:
+                            arguments.add(new Immediate64Argument(endianness().readLong(stream)));
+                            break;
+                    }
+                    continue;
+                case OPCODE1_REXB:
+                    value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte);
+                    // fall through...
+                case OPCODE1:
+                    value += header.opcode1.ordinal() & 7;
+                    break;
+                case OPCODE2_REXB:
+                    value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte);
+                    // fall through...
+                case OPCODE2:
+                    value += header.opcode2.ordinal() & 7;
+                    break;
+            }
+            final X86EnumerableParameter enumerableParameter = (X86EnumerableParameter) parameter;
+            final Enumerator enumerator = enumerableParameter.enumerator();
+            if (enumerator == AMD64GeneralRegister8.ENUMERATOR) {
+                arguments.add(AMD64GeneralRegister8.fromValue(value, header.rexPrefix != null));
+            } else {
+                arguments.add((Argument) enumerator.fromValue(value));
+            }
+        }
+        return arguments;
+    }
+
+    private int getModVariantParameterIndex(X86Template template, byte modRMByte, byte sibByte) {
+        if (template.modCase() == X86TemplateContext.ModCase.MOD_0 && X86Field.MOD.extract(modRMByte) != X86TemplateContext.ModCase.MOD_0.value()) {
+            switch (template.rmCase()) {
+                case NORMAL: {
+                    if (template.addressSizeAttribute() == WordWidth.BITS_16) {
+                        if (X86Field.RM.extract(modRMByte) != X86TemplateContext.RMCase.SWORD.value()) {
+                            return -1;
+                        }
+                    } else if (X86Field.RM.extract(modRMByte) != X86TemplateContext.RMCase.SDWORD.value()) {
+                        return -1;
+                    }
+                    for (int i = 0; i < template.parameters().size(); i++) {
+                        switch (template.parameters().get(i).place()) {
+                            case MOD_RM_REXB:
+                            case MOD_RM:
+                                return i;
+                            default:
+                                break;
+                        }
+                    }
+                    break;
+                }
+                case SIB: {
+                    if (template.sibBaseCase() == X86TemplateContext.SibBaseCase.GENERAL_REGISTER && X86Field.BASE.extract(sibByte) == 5) {
+                        for (int i = 0; i < template.parameters().size(); i++) {
+                            switch (template.parameters().get(i).place()) {
+                                case SIB_BASE_REXB:
+                                case SIB_BASE:
+                                    return i;
+                                default:
+                                    break;
+                            }
+                        }
+                    }
+                    break;
+                }
+                default: {
+                    break;
+                }
+            }
+        }
+        return -1;
+    }
+
+    private byte getSibByte(BufferedInputStream stream, X86Template template, byte modRMByte) throws IOException {
+        if (template.addressSizeAttribute() == WordWidth.BITS_16) {
+            return 0;
+        }
+        if (template.hasSibByte()) {
+            return endianness().readByte(stream);
+        }
+        if (template.hasModRMByte() && X86Field.RM.extract(modRMByte) == X86TemplateContext.RMCase.SIB.value() &&
+                   X86Field.MOD.extract(modRMByte) != X86TemplateContext.ModCase.MOD_3.value()) {
+            return endianness().readByte(stream);
+        }
+        return 0;
+    }
+
+    protected abstract Map<X86InstructionHeader, List<X86Template>> headerToTemplates();
+
+    private static int serial;
+
+    public DisassembledObject scanInstruction(BufferedInputStream stream, X86InstructionHeader header) throws IOException, AssemblyException {
+        if (header != X86InstructionHeader.INVALID) {
+            serial++;
+            Trace.line(4, "instruction: " + serial);
+            if (header.opcode1 != null) {
+                boolean isFloatingPointEscape = false;
+                if (X86Opcode.isFloatingPointEscape(header.opcode1)) {
+                    final int byte2 = stream.read();
+                    if (byte2 >= 0xC0) {
+                        isFloatingPointEscape = true;
+                        header.opcode2 = HexByte.VALUES.get(byte2);
+                    }
+                }
+                final List<X86Template> templates = headerToTemplates().get(header);
+                if (templates != null) {
+                    for (X86Template template : templates) {
+                        stream.reset();
+                        scanInstructionHeader(stream, true);
+                        if (isFloatingPointEscape) {
+                            stream.read();
+                        }
+                        try {
+                            byte modRMByte = 0;
+                            byte sibByte = 0;
+                            int modVariantParameterIndex = -1;
+                            List<Argument> arguments = null;
+                            if (template.hasModRMByte()) {
+                                modRMByte = endianness().readByte(stream);
+                                sibByte = getSibByte(stream, template, modRMByte);
+                                modVariantParameterIndex = getModVariantParameterIndex(template, modRMByte, sibByte);
+                                if (modVariantParameterIndex >= 0) {
+                                    final X86Template modVariantTemplate = X86Assembly.getModVariantTemplate(templates, template, template.parameters().get(modVariantParameterIndex).type());
+                                    arguments = scanArguments(stream, modVariantTemplate, header, modRMByte, sibByte);
+                                }
+                            }
+                            if (arguments == null) {
+                                arguments = scanArguments(stream, template, header, modRMByte, sibByte);
+                            }
+                            if (modVariantParameterIndex >= 0) {
+                                final Immediate8Argument immediateArgument = (Immediate8Argument) arguments.get(modVariantParameterIndex);
+                                if (immediateArgument.value() != 0) {
+                                    continue;
+                                }
+
+                                // Remove the mod variant argument
+                                final Argument modVariantArgument = arguments.get(modVariantParameterIndex);
+                                final List<Argument> result = new ArrayList<Argument>();
+                                for (Argument argument : arguments) {
+                                    if (modVariantArgument != argument) {
+                                        result.add(argument);
+                                    }
+                                }
+                                arguments = result;
+                            }
+                            if (!(Utils.indexOfIdentical(arguments, null) != -1)) {
+                                byte[] bytes;
+                                if (true) {
+                                    final Assembler assembler = createAssembler(currentPosition);
+                                    try {
+                                        assembly.assemble(assembler, template, arguments);
+                                    } catch (AssemblyException e) {
+                                        // try the next template
+                                        continue;
+                                    }
+                                    bytes = assembler.toByteArray();
+                                } else { // TODO: does not work yet
+                                    final X86TemplateAssembler templateAssembler = new X86TemplateAssembler(template, addressWidth());
+                                    bytes = templateAssembler.assemble(arguments);
+                                }
+                                if (bytes != null) {
+                                    stream.reset();
+                                    if (Streams.startsWith(stream, bytes)) {
+                                        final DisassembledInstruction disassembledInstruction = createDisassembledInstruction(currentPosition, bytes, template, arguments);
+                                        currentPosition += bytes.length;
+                                        return disassembledInstruction;
+                                    }
+                                }
+                            }
+                        } catch (NoSuchAssemblerMethodError e) {
+                            // Until the X86TemplateAssembler is complete, only templates for which a generated assembler
+                            // method exists can be disassembled
+                        } catch (IOException ioException) {
+                            // this one did not work, so loop back up and try another template
+                        }
+                    }
+                }
+            }
+            if (header.instructionSelectionPrefix == X86Opcode.REPE || header.instructionSelectionPrefix == X86Opcode.REPNE) {
+
+                stream.reset();
+                final int size = 1;
+                final byte[] data = new byte[size];
+                Streams.readFully(stream, data);
+
+                final X86InstructionHeader prefixHeader = new X86InstructionHeader();
+                prefixHeader.opcode1 = header.instructionSelectionPrefix;
+                final List<X86Template> prefixTemplates = headerToTemplates().get(prefixHeader);
+                final X86Template template = Utils.first(prefixTemplates);
+                final byte[] bytes = new byte[]{header.instructionSelectionPrefix.byteValue()};
+                List<Argument> empty = Collections.emptyList();
+                final DisassembledInstruction disassembledInstruction = createDisassembledInstruction(currentPosition, bytes, template, empty);
+                currentPosition++;
+                return disassembledInstruction;
+            }
+        }
+        if (INLINE_INVALID_INSTRUCTIONS_AS_BYTES) {
+            stream.reset();
+            final int size = 1;
+            final byte[] data = new byte[size];
+            Streams.readFully(stream, data);
+            final InlineData inlineData = new InlineData(currentPosition, data);
+            final DisassembledData disassembledData = createDisassembledDataObjects(inlineData).iterator().next();
+            currentPosition += size;
+            return disassembledData;
+        }
+        throw new AssemblyException("unknown instruction");
+    }
+
+    /**
+     * Creates a disassembled instruction based on a given sequence of bytes, a template and a set of arguments. The
+     * caller has performed the necessary decoding of the bytes to derive the template and arguments.
+     *
+     * @param position the position an instruction stream from which the bytes were read
+     * @param bytes the bytes of an instruction
+     * @param template the template that corresponds to the instruction encoded in {@code bytes}
+     * @param arguments the arguments of the instruction encoded in {@code bytes}
+     * @return a disassembled instruction representing the result of decoding {@code bytes} into an instruction
+     */
+    protected X86DisassembledInstruction createDisassembledInstruction(int position, byte[] bytes, X86Template template, List<Argument> arguments) {
+        return new X86DisassembledInstruction(this, position, bytes, template, arguments);
+    }
+
+    private static final int MORE_THAN_ANY_INSTRUCTION_LENGTH = 100;
+    private static final boolean INLINE_INVALID_INSTRUCTIONS_AS_BYTES = true;
+
+    @Override
+    public List<DisassembledObject> scanOne0(BufferedInputStream stream) throws IOException, AssemblyException {
+        final List<DisassembledObject> disassembledObjects = new ArrayList<DisassembledObject>();
+        stream.mark(MORE_THAN_ANY_INSTRUCTION_LENGTH);
+        final X86InstructionHeader header = scanInstructionHeader(stream, false);
+        if (header == null) {
+            throw new AssemblyException("unknown instruction");
+        }
+        disassembledObjects.add(scanInstruction(stream, header));
+        return disassembledObjects;
+    }
+
+    @Override
+    public List<DisassembledObject> scan0(BufferedInputStream stream) throws IOException, AssemblyException {
+        final SortedSet<Integer> knownGoodCodePositions = new TreeSet<Integer>();
+        final List<DisassembledObject> result = new ArrayList<DisassembledObject>();
+        boolean processingKnownValidCode = true;
+
+        while (true) {
+            while (knownGoodCodePositions.size() > 0 && knownGoodCodePositions.first().intValue() < currentPosition) {
+                knownGoodCodePositions.remove(knownGoodCodePositions.first());
+            }
+
+            scanInlineData(stream, result);
+
+            stream.mark(MORE_THAN_ANY_INSTRUCTION_LENGTH);
+
+            final X86InstructionHeader header = scanInstructionHeader(stream, false);
+            if (header == null) {
+                return result;
+            }
+            final DisassembledObject disassembledObject = scanInstruction(stream, header);
+
+            if (knownGoodCodePositions.size() > 0) {
+                final int firstKnownGoodCodePosition = knownGoodCodePositions.first().intValue();
+                final int startPosition = disassembledObject.startPosition();
+                if (firstKnownGoodCodePosition > startPosition && firstKnownGoodCodePosition < disassembledObject.endPosition()) {
+                    // there is a known valid code location in the middle of this instruction - assume that it is an invalid instruction
+                    stream.reset();
+                    final int size = firstKnownGoodCodePosition - startPosition;
+                    final byte[] data = new byte[size];
+                    Streams.readFully(stream, data);
+                    final InlineData inlineData = new InlineData(startPosition, data);
+                    currentPosition += addDisassembledDataObjects(result, inlineData);
+                    processingKnownValidCode = true;
+                } else {
+                    result.add(disassembledObject);
+                    if (firstKnownGoodCodePosition == startPosition) {
+                        processingKnownValidCode = true;
+                    }
+                }
+            } else {
+                if (processingKnownValidCode && disassembledObject instanceof DisassembledInstruction) {
+                    final DisassembledInstruction disassembledInstruction = (DisassembledInstruction) disassembledObject;
+                    if (isRelativeJumpForward(disassembledInstruction)) {
+                        int jumpOffset;
+                        if (Utils.first(disassembledInstruction.arguments()) instanceof Immediate32Argument) {
+                            jumpOffset = ((Immediate32Argument) Utils.first(disassembledInstruction.arguments())).value();
+                        } else {
+                            assert Utils.first(disassembledInstruction.arguments()) instanceof Immediate8Argument;
+                            jumpOffset = ((Immediate8Argument) Utils.first(disassembledInstruction.arguments())).value();
+                        }
+                        final int targetPosition = disassembledInstruction.endPosition() + jumpOffset;
+                        knownGoodCodePositions.add(targetPosition);
+                        processingKnownValidCode = false;
+                    }
+                }
+                result.add(disassembledObject);
+            }
+        }
+    }
+
+    private boolean isRelativeJumpForward(DisassembledInstruction instruction) {
+        return instruction.template().internalName().equals("jmp") && // check if this is a jump instruction...
+            instruction.arguments().size() == 1 && // that accepts one operand...
+            ((Utils.first(instruction.arguments()) instanceof Immediate32Argument && // which is a relative offset...
+            ((Immediate32Argument) Utils.first(instruction.arguments())).value() >= 0) || // forward in the code stream
+            (Utils.first(instruction.arguments()) instanceof Immediate8Argument && // which is a relative offset...
+            ((Immediate8Argument) Utils.first(instruction.arguments())).value() >= 0)); // forward in the code stream
+    }
+
+    @Override
+    public ImmediateArgument addressForRelativeAddressing(DisassembledInstruction di) {
+        return startAddress().plus(di.endPosition());
+    }
+
+    @Override
+    public String mnemonic(DisassembledInstruction di) {
+        return di.template().externalName();
+    }
+
+    @Override
+    public String operandsToString(DisassembledInstruction di, AddressMapper addressMapper) {
+        final LinkedList<X86Operand> operandQueue = new LinkedList<X86Operand>();
+        for (Operand operand : di.template().operands()) {
+            operandQueue.add((X86Operand) operand);
+        }
+        final LinkedList<Argument> argumentQueue = new LinkedList<Argument>(di.arguments());
+        String result = "";
+        String separator = "";
+        while (!operandQueue.isEmpty()) {
+            result += separator + getOperand(di, operandQueue, argumentQueue, addressMapper);
+            separator = ", ";
+        }
+        return result;
+    }
+
+    @Override
+    public String toString(DisassembledInstruction di, AddressMapper addressMapper) {
+        String s = operandsToString(di, addressMapper);
+        if (s.length() > 0) {
+            s = "  " + s;
+        }
+        return Strings.padLengthWithSpaces(mnemonic(di), 8) + s;
+    }
+
+    private String getSibIndexAndScale(Queue<X86Operand> operands, Queue<Argument> arguments) {
+        X86Parameter parameter = (X86Parameter) operands.remove();
+        assert parameter.place() == ParameterPlace.SIB_INDEX || parameter.place() == ParameterPlace.SIB_INDEX_REXX;
+        final String result = arguments.remove().disassembledValue();
+        parameter = (X86Parameter) operands.remove();
+        assert parameter.place() == ParameterPlace.SIB_SCALE;
+        final Scale scale = (Scale) arguments.remove();
+        if (scale == Scale.SCALE_1) {
+            return result;
+        }
+        return result + " * " + scale.disassembledValue();
+    }
+
+    private String addition(Argument argument, String space) {
+        assert argument instanceof ImmediateArgument;
+        final long value = argument.asLong();
+        final String s = Long.toString(value);
+        if (value >= 0) {
+            return "+" + space + s;
+        }
+        return "-" + space + s.substring(1);
+    }
+
+    private String getOperand(DisassembledInstruction di, Queue<X86Operand> operands, Queue<Argument> arguments, AddressMapper addressMapper) {
+        final X86Operand operand = operands.remove();
+        if (operand instanceof ImplicitOperand) {
+            final ImplicitOperand implicitOperand = (ImplicitOperand) operand;
+            return implicitOperand.argument().disassembledValue();
+        }
+        final X86Parameter parameter = (X86Parameter) operand;
+        final Argument argument = arguments.remove();
+        if (parameter instanceof X86DisplacementParameter) {
+            assert parameter.place() == ParameterPlace.APPEND;
+            final X86Parameter nextParameter = (X86Parameter) operands.element();
+            String prefix = "";
+            if (IndirectRegister.class.isAssignableFrom(nextParameter.type())) {
+                operands.remove();
+                prefix += "[" + arguments.remove().disassembledValue();
+            } else {
+                if (nextParameter.place() == ParameterPlace.SIB_BASE || nextParameter.place() == ParameterPlace.SIB_BASE_REXB) {
+                    operands.remove();
+                    prefix += arguments.remove().disassembledValue();
+                }
+                prefix += "[" + getSibIndexAndScale(operands, arguments);
+            }
+            return prefix + " " + addition(argument, " ") + "]";
+        }
+        if (parameter.place() == ParameterPlace.SIB_BASE || parameter.place() == ParameterPlace.SIB_BASE_REXB) {
+            return argument.disassembledValue() + "[" + getSibIndexAndScale(operands, arguments) + "]";
+        }
+        if (IndirectRegister.class.isAssignableFrom(parameter.type())) {
+            return "[" + argument.disassembledValue() + "]";
+        }
+        if (parameter instanceof X86AddressParameter) {
+            String address = argument.disassembledValue();
+            final DisassembledLabel label = addressMapper.labelAt((ImmediateArgument) argument);
+            if (label != null) {
+                address = label.name() + ": " + address;
+            }
+            final X86Operand nextOperand = operands.peek();
+            if (nextOperand instanceof X86Parameter) {
+                final X86Parameter nextParameter = (X86Parameter) nextOperand;
+                if (nextParameter.place() == ParameterPlace.SIB_INDEX || nextParameter.place() == ParameterPlace.SIB_INDEX_REXX) {
+                    return address + "[" + getSibIndexAndScale(operands, arguments) + "]";
+                }
+            }
+            return "[" + address + "]";
+        }
+        if (parameter instanceof X86OffsetParameter) {
+            String offset = addition(argument, "");
+            final ImmediateArgument targetAddress = di.addressForRelativeAddressing().plus((ImmediateArgument) argument);
+            final DisassembledLabel label =  addressMapper.labelAt(targetAddress);
+            if (label != null) {
+                offset = label.name() + ": " + offset;
+            }
+            if (((X86Template) di.template()).addressSizeAttribute() == WordWidth.BITS_64 && ((X86Template) di.template()).rmCase() == X86TemplateContext.RMCase.SDWORD) {
+                return "[" + offset + "]"; // RIP
+            }
+            return offset;
+        }
+        if (parameter.getClass() == X86ImmediateParameter.class) {
+            return argument.disassembledValue();
+        }
+        return argument.disassembledValue();
+    }
+}