private byte[] LinkPass2() { MemoryStream codeBytesStream = new MemoryStream(); BinaryWriter codeBytesWriter = new BinaryWriter(codeBytesStream); for (int i = 0; i < outputCode.Count; i++) { JavaInstruction instr = outputCode[i]; codeBytesWriter.Write((byte)instr.Opcode); Java.ByteCode.JavaInstructionDescption descr = Java.ByteCode.JavaInstructions[instr.Opcode]; int operandSize = descr.Size - 1; switch (descr.OpType) { case Java.ByteCode.JavaOperandType.ConstValue: switch (operandSize) { case 1: codeBytesWriter.Write((sbyte)instr.Operand); break; case 2: codeBytesWriter.WriteBE((short)instr.Operand); break; case 4: codeBytesWriter.WriteBE((int)instr.Operand); break; } break; case Java.ByteCode.JavaOperandType.ConstPool: if (operandSize == 1) { codeBytesWriter.Write((byte)((ushort)instr.Operand)); } else { codeBytesWriter.WriteBE((ushort)instr.Operand); } break; case Java.ByteCode.JavaOperandType.LocalVar: if (instr.Operand is ushort) { codeBytesWriter.WriteBE((ushort)instr.Operand); } else { codeBytesWriter.Write((byte)instr.Operand); } break; case Java.ByteCode.JavaOperandType.Offset: if (instr.Operand is string) { codeBytesWriter.WriteBE((short)(outputCodeOffsets[outputCode[labels[(string)instr.Operand]]] - outputCodeOffsets[instr])); } else { codeBytesWriter.WriteBE((short)(outputCodeOffsets[(JavaInstruction)instr.Operand] - outputCodeOffsets[instr])); } break; case Java.ByteCode.JavaOperandType.Special: switch (instr.Opcode) { case Java.OpCodes.iinc: if (instr.Operand is int) { codeBytesWriter.WriteBE((int)instr.Operand); } else { codeBytesWriter.WriteBE((short)instr.Operand); } break; case Java.OpCodes.tableswitch: //TODO: Java.OpCodes.tableswitch break; case Java.OpCodes.lookupswitch: LookupswitchOperand lookUpOperand = (LookupswitchOperand)instr.Operand; int padding = (4 - ((outputCodeOffsets[instr] + 1) % 4)) % 4; codeBytesWriter.Write(new byte[padding]); codeBytesWriter.WriteBE(outputCodeOffsets[outputCode[labels[lookUpOperand.DefaultLabel]]] - outputCodeOffsets[instr]); codeBytesWriter.WriteBE(lookUpOperand.Pairs.Length); for (int j = 0; j < lookUpOperand.Pairs.Length; j++) { codeBytesWriter.WriteBE(lookUpOperand.Pairs[j].Item1); codeBytesWriter.WriteBE(outputCodeOffsets[outputCode[labels[lookUpOperand.Pairs[j].Item2]]] - outputCodeOffsets[instr]); } break; case Java.OpCodes.invokeinterface: case Java.OpCodes.invokedynamic: uint op = (uint)instr.Operand; codeBytesWriter.WriteBE((ushort)(op & 0xfff)); codeBytesWriter.WriteBE((ushort)(op >> 16)); break; case Java.OpCodes.newarray: codeBytesWriter.Write((byte)instr.Operand); break; case Java.OpCodes.wide: break; case Java.OpCodes.multianewarray: int data = (int)instr.Operand; codeBytesWriter.WriteBE((ushort)(data & 0xffff)); codeBytesWriter.Write((byte)((data & 0xff0000) >> 16)); break; } break; } } byte[] result = codeBytesStream.ToArray(); codeBytesStream.Close(); return(result); }
private static void Disasm(Attributes.Code codeAttr, ConstantPool pool, CountingStreamWriter writer, string[] sourceFile) { byte[] code = codeAttr.CodeBytes; int i = 0; bool lastWide = false; Attributes.LineNumberTable lnt = codeAttr.Attributes.Where(A => A is Attributes.LineNumberTable).FirstOrDefault() as Attributes.LineNumberTable; Attributes.LineNumberTable newLnt = new Attributes.LineNumberTable(); int lastLine = 0; while (i < code.Length) { if ((lnt != null) && (sourceFile != null)) { try { var lns = lnt.Table.Where(ln => ln.StartPC <= i); if (lns.Count() > 0) { int currLine = lns.Aggregate((i1, i2) => i1.StartPC > i2.StartPC ? i1 : i2).LineNumberInFile; if (lastLine != currLine) { writer.WriteLine(" ## {0}", sourceFile[currLine]); } lastLine = currLine; } } catch (Exception) { } } newLnt.Table.Add(new Attributes.LineNumberTable.LineNumber((ushort)i, (ushort)writer.CurrLine)); OpCodes op = (OpCodes)code[i]; if (!lastWide) { writer.Write(" {0,4:X} : ", i); } if (op == OpCodes.wide) { writer.Write("wide "); i++; lastWide = true; continue; } string opStr = op.ToString(); string operandStr = ""; if (opStr[0] == '_') { opStr = opStr.Substring(1); } writer.Write(opStr); ByteCode.JavaInstructionDescption descr = ByteCode.JavaInstructions[op]; int operandSize = descr.Size - 1; if (lastWide) { operandSize *= 2; lastWide = false; } switch (descr.OpType) { case ByteCode.JavaOperandType.ConstPool: ushort index = (ushort)BitConverterBE.ReadAsInt32(code, i + 1, operandSize); operandStr = pool[index].ToString(); break; case ByteCode.JavaOperandType.ConstValue: case ByteCode.JavaOperandType.LocalVar: operandStr = BitConverterBE.ReadAsInt32(code, i + 1, operandSize).ToString(); break; case ByteCode.JavaOperandType.Offset: short offset = (short)BitConverterBE.ReadAsInt32(code, i + 1, operandSize); operandStr = String.Format("{0,4:X}", (i + offset)); break; case ByteCode.JavaOperandType.Special: switch (op) { case OpCodes.iinc: int op1 = BitConverterBE.ReadAsInt32(code, i + 1, operandSize / 2); int op2 = BitConverterBE.ReadAsInt32(code, i + 1 + operandSize / 2, operandSize / 2); operandStr = String.Format("{0}, {1}", op1, op2); break; case OpCodes.lookupswitch: int paddingLength = (4 - ((i + 1) % 4)) % 4; int _default = BitConverterBE.ReadAsInt32(code, i + paddingLength + 1, 4); int npairs = BitConverterBE.ReadAsInt32(code, i + paddingLength + 5, 4); int pairsStart = i + paddingLength + 9; operandSize = npairs * 8 + 8 + paddingLength; writer.WriteLine(" default: {0,4:X}, npairs: {1}", _default, npairs); for (int pair = 0; pair < npairs; pair++) { int pairValue = BitConverterBE.ReadAsInt32(code, pairsStart + (pair * 8), 4); int pairOffset = BitConverterBE.ReadAsInt32(code, pairsStart + (pair * 8) + 4, 4); writer.WriteLine(" {0,4:X} : {1}", pairOffset, pairValue); } break; case OpCodes.tableswitch: paddingLength = (4 - ((i + 1) % 4)) % 4; _default = BitConverterBE.ReadAsInt32(code, i + paddingLength + 1, 4); int low = BitConverterBE.ReadAsInt32(code, i + paddingLength + 5, 4); int hight = BitConverterBE.ReadAsInt32(code, i + paddingLength + 9, 4); writer.WriteLine(" default: {0,4:X}, low: {1}, hight: {2}", _default, low, hight); int jmpCount = hight - low + 1; int jmpStart = i + paddingLength + 13; operandSize = jmpCount * 4 + 13 + paddingLength; for (int jmp = 0; jmp < jmpCount; jmp++) { writer.WriteLine(" {0,4:X} : {1}", BitConverterBE.ReadAsInt32(code, jmpStart + jmp * 4, 4), low + jmp); } break; case OpCodes.invokeinterface: case OpCodes.invokedynamic: index = (ushort)BitConverterBE.ReadAsInt32(code, i + 1, 2); operandStr = pool[index].ToString(); break; case OpCodes.newarray: operandStr = ArrayTypes[code[i + 1]]; break; case OpCodes.multianewarray: index = (ushort)BitConverterBE.ReadAsInt32(code, i + 1, 2); byte dismensions = code[i + 3]; operandStr = String.Format("{0}, {1}", dismensions, pool[index].ToString()); break; } ; break; } writer.WriteLine(" {0}", operandStr); i += 1 + operandSize; } if (Program.DebugBytecode) { if (lnt != null) { codeAttr.Attributes.Remove(lnt); } codeAttr.Attributes.Add(newLnt); } }