/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.jnasm.assembler.x86;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.jnode.assembler.Label;
import org.jnode.assembler.NativeStream;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86BinaryAssembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.jnasm.assembler.Assembler;
import org.jnode.jnasm.assembler.AssemblerModule;
import org.jnode.jnasm.assembler.HardwareSupport;
import org.jnode.jnasm.assembler.Instruction;
import org.jnode.vm.x86.X86CpuID;
/**
* @author Levente S\u00e1ntha (lsantha@users.sourceforge.net)
*/
public class X86Support extends HardwareSupport {
private final List<AssemblerModule> modules;
private final List<Instruction> instructions;
private final Map<String, Label> labels;
private int pass;
private final Assembler assembler;
private X86Assembler nativeStream;
public X86Support(Assembler assembler, List<Instruction> instructions,
Map<String, Label> labels, Map<String, Integer> constants) {
this.modules = new ArrayList<AssemblerModule>();
this.assembler = assembler;
this.instructions = instructions;
this.labels = labels;
modules.add(new X86Core(labels, constants));
modules.add(new FPU(labels, constants));
modules.add(new MMX(labels, constants));
modules.add(assembler.getPseudo());
}
public void assemble(int baseAddress) {
X86CpuID cpuId = X86CpuID.createID("pentium");
nativeStream = new X86BinaryAssembler(cpuId, X86Constants.Mode.CODE32, baseAddress);
((X86BinaryAssembler) nativeStream).setByteValueEnabled(true);
((X86BinaryAssembler) nativeStream).setRelJumpEnabled(false);
doAssembly();
}
public void assemble(NativeStream asm) {
nativeStream = (X86Assembler) asm;
if (nativeStream instanceof X86BinaryAssembler) {
((X86BinaryAssembler) nativeStream).setByteValueEnabled(true);
((X86BinaryAssembler) nativeStream).setRelJumpEnabled(false);
}
doAssembly();
if (nativeStream instanceof X86BinaryAssembler) {
((X86BinaryAssembler) nativeStream).setByteValueEnabled(true);
}
}
private void doAssembly() {
for (AssemblerModule asmMod : modules) {
asmMod.setNativeStream(nativeStream);
}
for (Instruction ins : instructions) {
//handle prefixes
int prefix = ins.getPrefix();
if ((prefix & Instruction.LOCK_PREFIX) != 0) {
nativeStream.writePrefix(X86Constants.LOCK_PREFIX);
} else if ((prefix & Instruction.REP_PREFIX) != 0) {
nativeStream.writePrefix(X86Constants.REP_PREFIX);
} else if ((prefix & Instruction.FS_PREFIX) != 0) {
nativeStream.writePrefix(X86Constants.FS_PREFIX);
}
String label = ins.getLabel();
if (label != null) {
if (labels.get(label) != null && pass == 1)
throw new IllegalArgumentException("Label already defined: " + label);
defineLabel(label, nativeStream);
}
String mnemo = ins.getMnemonic();
if (mnemo != null) {
try {
int times = ins.getTimes();
if (times > 0) {
for (; times-- > 0;) {
emit(ins.getMnemonic(), ins.getOperands(), getOperandSize(ins), ins);
}
} else {
emit(ins.getMnemonic(), ins.getOperands(), getOperandSize(ins), ins);
}
} catch (IllegalArgumentException x) {
if (Assembler.THROW) {
throw x;
} else {
System.out.println(x.getMessage() + " at line " + ins.getLineNumber());
}
}
}
}
}
public void writeTo(OutputStream out) throws IOException {
nativeStream.writeTo(out);
}
public void setPass(int pass) {
this.pass = pass;
}
private void defineLabel(String label, X86Assembler asm) {
try {
Label lab = new Label(label);
labels.put(label, lab);
NativeStream.ObjectRef ref = asm.setObjectRef(lab);
assembler.putConstant(label, ref.getOffset() + (int) asm.getBaseAddr());
} catch (Exception e) {
e.printStackTrace();
}
}
private void emit(String mnemonic, List<Object> operands, int operandSize, Instruction instruction) {
for (AssemblerModule module : modules) {
if (module.emit(mnemonic, operands, operandSize, instruction)) {
return;
}
}
throw new IllegalArgumentException("Unknown instruction: " + mnemonic);
}
public static int getOperandSize(Instruction ins) {
String size = ins.getSizeInfo();
if (size == null) {
return X86Constants.BITS32;
} else if ("byte".equals(size)) {
return X86Constants.BITS8;
} else if ("word".equals(size)) {
return X86Constants.BITS16;
} else if ("dword".equals(size)) {
return X86Constants.BITS32;
} else if ("qword".equals(size)) {
return X86Constants.BITS64;
} else {
throw new IllegalArgumentException("Unknown operand size: " + size);
}
}
public boolean isRegister(String str) {
return X86Register.isRegister(str);
}
}