public override OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine) { if (string.IsNullOrWhiteSpace(asmLine.Label)) { assemblerState.RaiseError("IS must have a label."); } else { // TODO only integer constants and register substitutions are supported // register if (TryParseRegister(asmLine.Expr, out byte registerRef)) { assemblerState.DefineVariable(asmLine.Label, new RegisterCompilerVariable(registerRef)); } // constant else if (int.TryParse(asmLine.Expr, out int constant)) { assemblerState.DefineVariable(asmLine.Label, new ByteConstantAssemblerVariable((byte)constant)); } else { assemblerState.RaiseError($"IS expression, '{asmLine.Expr}' must be a constant integer or register reference."); } } return(new OperatorOutput()); }
public override OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine) { List <byte> bytes = new List <byte>(); string[] args = new[] { asmLine.X, asmLine.Y, asmLine.Z }; foreach (var arg in args) { if (TryParseConstant(arg, out byte b)) { bytes.Add(b); } else if (arg.StartsWith('"') && arg.EndsWith('"')) { bytes.AddRange(Encoding.ASCII.GetBytes(arg.Trim('"'))); } else if (string.IsNullOrEmpty(arg)) { // do nothing } else { throw new Exception($"Unable to generate byte string. Unknown argument format: '{arg}'."); } } if (!string.IsNullOrEmpty(asmLine.Label)) { assemblerState.DefineVariable(asmLine.Label, new OctaConstantAssemblerVariable(assemblerState.ProgramCounter)); } return(new OperatorOutput() { Output = bytes.ToArray() }); }
protected override AssemblerState CreateAssemblerState(binary_library.IBinaryFile file) { AssemblerState ret = base.CreateAssemblerState(file); ret.cur_bitness = binary_library.Bitness.Bits32; return(ret); }
public override OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine) { if (instructions == null) { instructions = ReflectionUtilities.FindExtendingClasses <mmix.Instructions.AbstractInstruction>().ToArray(); } var instruction = instructions.SingleOrDefault(i => i.Symbol == asmLine.Op); if (instruction == null) { throw new Exception("Unknown OP code."); } var hex = new byte[] { instruction.OpCode, assemblerState.ParseExprToken(asmLine.X).FetchByte(), assemblerState.ParseExprToken(asmLine.Y).FetchByte(), assemblerState.ParseExprToken(asmLine.Z).FetchByte(), }; return(new OperatorOutput() { Output = hex }); }
bool retf(List <OutputBlock> ret, AsmParser.ParseOutput op, List <AsmParser.ParseOutput> prefixes, List <AsmParser.ParseOutput> parameters, AssemblerState state) { ret.Add(new CodeBlock { Code = new byte[] { 0xcb } }); return(true); }
bool mov_r3264_creg(List <OutputBlock> ret, AsmParser.ParseOutput op, List <AsmParser.ParseOutput> prefixes, List <AsmParser.ParseOutput> parameters, AssemblerState state) { Reg r = regs[parameters[1].Name]; Reg rm = regs[parameters[0].Name]; AppendRex(ret, GenerateRex(false, r, rm)); ret.Add(new CodeBlock { Code = new byte[] { 0x0f, 0x20 } }); AppendModRM(ret, r, rm, state); return(true); }
private void AssembleLabel(AsmParser.ParseOutput line_entry, AssemblerState state) { Label l = new Label { Name = line_entry.Name, ObjectType = binary_library.SymbolObjectType.Unknown, Type = binary_library.SymbolType.Local }; if (state.sym_types.ContainsKey(line_entry.Name)) { l.Type = state.sym_types[line_entry.Name]; } if (state.sym_obj_types.ContainsKey(line_entry.Name)) { l.ObjectType = state.sym_obj_types[line_entry.Name]; } state.OutputBlocks.Add(l); }
public override OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine) { // register alias ulong location; if (TryParseConstant(asmLine.Expr, out location)) { assemblerState.ProgramCounter = location; } else { assemblerState.RaiseError("LOC expression must be a constant value."); } return(new OperatorOutput()); }
private void AssembleOperation(AsmParser.ParseOutput line_entry, AssemblerState state) { // Interpret the operation List <AsmParser.ParseOutput> prefixes = new List <AsmParser.ParseOutput>(); AsmParser.ParseOutput op = null; List <AsmParser.ParseOutput> parameters = new List <AsmParser.ParseOutput>(); foreach (AsmParser.ParseOutput p in line_entry.Children) { switch (p.Type) { case AsmParser.ParseOutput.OutputType.Operation: if (op != null) { throw new Exception("More than one operation per line"); } op = p; break; case AsmParser.ParseOutput.OutputType.Prefix: prefixes.Add(p); break; case AsmParser.ParseOutput.OutputType.Parameter: if (p.Children.Count > 1) { throw new Exception("Only one parameter child allowed"); } parameters.Add(p.Children[0]); break; default: throw new Exception("Unsupported operation argument type: " + p.ToString()); } } // Now get the appropriate operations OpcodeImplementation.OpcodeDelegate del = FindOperation(op, prefixes, parameters, state); if ((del == null) || (!del(state.OutputBlocks, op, prefixes, parameters, state))) { throw new Exception("Unable to assemble: " + line_entry.ToString()); } }
public void Assemble(AsmParser.ParseOutput input, binary_library.IBinaryFile output) { AssemblerState state = CreateAssemblerState(output); if (input.Type != AsmParser.ParseOutput.OutputType.Block) { throw new Exception("Expected Block"); } foreach (AsmParser.ParseOutput line in input.Children) { if (line.Type != AsmParser.ParseOutput.OutputType.Line) { throw new Exception("Expected Line"); } foreach (AsmParser.ParseOutput line_entry in line.Children) { switch (line_entry.Type) { case AsmParser.ParseOutput.OutputType.DirectiveCommand: AssembleDirective(line_entry, state); break; case AsmParser.ParseOutput.OutputType.OpCommand: AssembleOperation(line_entry, state); break; case AsmParser.ParseOutput.OutputType.Label: AssembleLabel(line_entry, state); break; default: throw new NotSupportedException(); } } } }
public abstract OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine);
private void AssembleDirective(AsmParser.ParseOutput line_entry, AssemblerState state) { AsmParser.ParseOutput dir = line_entry.Children[0]; // Interpret directives if ((dir.Name == "weak") || (dir.Name == "global")) { // these are of the form <weak | global> <label> [:function | :data] string t_name = line_entry.Children[1].Children[0].Name; binary_library.SymbolType st = binary_library.SymbolType.Undefined; binary_library.SymbolObjectType sot = binary_library.SymbolObjectType.Unknown; if (dir.Name == "weak") { st = binary_library.SymbolType.Weak; } else if (dir.Name == "global") { st = binary_library.SymbolType.Global; } if (line_entry.Children.Count >= 3) { string ot_name = line_entry.Children[2].Children[0].Name; if (ot_name == "function") { sot = binary_library.SymbolObjectType.Function; } else if (ot_name == "data") { sot = binary_library.SymbolObjectType.Object; } } if (st != binary_library.SymbolType.Undefined) { state.sym_types[t_name] = st; } if (sot != binary_library.SymbolObjectType.Unknown) { state.sym_obj_types[t_name] = sot; } } else if (dir.Name == "extern") { string t_name = line_entry.Children[1].Name; if (!state.extern_labels.Contains(t_name)) { state.extern_labels.Add(t_name); } } else if (dir.Name == "bits16") { state.cur_bitness = binary_library.Bitness.Bits16; } else if (dir.Name == "bits32") { state.cur_bitness = binary_library.Bitness.Bits32; } else if (dir.Name == "bits64") { state.cur_bitness = binary_library.Bitness.Bits64; } else { throw new NotImplementedException(); } }
private OpcodeImplementation.OpcodeDelegate FindOperation(AsmParser.ParseOutput op, List <AsmParser.ParseOutput> prefixes, List <AsmParser.ParseOutput> parameters, AssemblerState state) { if (!opcodes.ContainsKey(op.Name)) { return(null); } List <OpcodeImplementation> ops = opcodes[op.Name]; if (ops == null) { return(null); } foreach (OpcodeImplementation oi in ops) { // Match prefixes bool allowed = true; foreach (AsmParser.ParseOutput prefix in prefixes) { if (!oi.AllowedPrefixes.Contains(prefix.Name.ToLower())) { allowed = false; break; } } if (!allowed) { continue; } // Match parameters if (parameters.Count != oi.ParamConstraints.Count) { continue; } for (int i = 0; i < parameters.Count; i++) { Location l = ParseLocation(parameters[i]); if (!MatchConstraint(oi.ParamConstraints[i], l)) { allowed = false; break; } } if (!allowed) { continue; } return(oi.emitter); } return(null); }
public override OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine) { assemblerState.RaiseError($"'{Symbol}' is not implemented."); return(new OperatorOutput()); }
public override OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine) { if (asmLine.ArgCount != 2) { throw new Exception("GETA must have exactly two arguments."); } // TODO don't forget GETAB[ackwards] bool backward = false; var destinationToken = assemblerState.ParseExprToken(asmLine.X); if (destinationToken.TokenType != ExprToken.ExprTokenType.REGISTER) { throw new Exception($"GETA X argument must be a register. {destinationToken.TokenType} received."); } ushort relativePointer; var pointerToken = assemblerState.ParseExprToken(asmLine.Y); if (pointerToken.TokenType == ExprToken.ExprTokenType.VARIABLE) { var octaVar = pointerToken.AssemblerVariable as OctaConstantAssemblerVariable; if (octaVar == null) { throw new Exception($"GETA reference must be an OCTA."); } // calculate relative pointer // TODO a different instruction is emitted if pointer points backwards. Care must be taken with unsigned weirdness. // divide by 4 for tetra alignment. relativePointer = (ushort)((octaVar.Constant - assemblerState.ProgramCounter).ToULong() / 4); } else if (pointerToken.TokenType == ExprToken.ExprTokenType.CONSTANT) { relativePointer = pointerToken.Value; } else { throw new Exception("GETA RA must be an OCTA reference or a constant."); } // GETA code. byte opCode = 0xF4; if (backward) { // GETAB code. opCode = 0xF5; } var hex = new byte[] { opCode, destinationToken.Value } .Concat(relativePointer.ToBytes()) .ToArray(); return(new OperatorOutput() { Output = hex }); }
bool mov_creg_r3264(List <OutputBlock> ret, AsmParser.ParseOutput op, List <AsmParser.ParseOutput> prefixes, List <AsmParser.ParseOutput> parameters, AssemblerState state) { return(true); }
void AppendModRM(List <OutputBlock> ret, byte r, byte rm, byte mod, long disp, AssemblerState state) { bool need_sib = false; bool need_disp32 = false; bool need_disp8 = false; bool absolute_disp = false; bool is_ptr = true; // Decide on addressing mode switch (state.cur_bitness) { case binary_library.Bitness.Bits32: case binary_library.Bitness.Bits64: // OK break; case binary_library.Bitness.Bits16: // Not done yet throw new NotImplementedException(); default: throw new NotSupportedException(); } if (mod == 3) { is_ptr = false; } if ((rm == regs["rsp"].id) && (mod != 3)) { need_sib = true; } if ((rm == regs["rbp"].id) && (mod == 0)) { absolute_disp = true; need_disp32 = true; } if (disp != 0) { if ((disp > Int32.MaxValue) || (disp < Int32.MinValue)) { throw new NotSupportedException(); } else if ((disp > SByte.MaxValue) || (disp < SByte.MinValue)) { need_disp32 = true; } else { need_disp8 = true; } } if (absolute_disp) { mod = 0; } else if (need_disp32) { mod = 2; } else if (need_disp8) { mod = 1; } else if (is_ptr) { mod = 0; } else { mod = 3; } // Encode the ModRM byte byte modrm = (byte)((byte)(rm & 0x7) | (byte)((r & 0x7) << 3) | (byte)((mod & 0x3) << 6)); ret.Add(new CodeBlock { Code = new byte[] { modrm } }); // Encode the SIB if (need_sib) { throw new NotImplementedException(); } // Encode the displacement if (need_disp32 | need_disp8) { byte[] val = BitConverter.GetBytes(disp); if (need_disp32) { ret.Add(new CodeBlock { Code = new byte[] { val[0], val[1], val[2], val[3] } }); } else { ret.Add(new CodeBlock { Code = new byte[] { val[0] } }); } } }
void AppendModRM(List <OutputBlock> ret, Reg r, Reg rm, AssemblerState state) { AppendModRM(ret, (byte)r.id, (byte)rm.id, 3, 0, state); }
public override OperatorOutput GenerateBinary(AssemblerState assemblerState, AsmLine asmLine) { return(new OperatorOutput()); }