HelpConvert asm instruction to corresponding bytes

Posts 31–36 of 36 · Page 3 of 3
kind of wide, hard to fit in one image.


Based on that, I'm going to..
Split each "asm line of code" into 3 parts (if they exist) : instruction | operand1 | operand2
Where each operand might be one of:
for example: reg+reg | [reg+reg] | [reg+num] | [reg] | [num] | reg | num | [reg+reg+num] | ..
.
Basically I'll have a switch for each instruction, and it will know how many operand(s) it should have: and a switch case for operand type it supports(requires). Or something along those lines.
Not entirely sure how well that'll work, it's late, back tomorrow.
.
Not sure if I like how the code is being set up (nested select statements), but you can kind of see where it's headed? Starting from scratch again, won't post update until it's worth posting.
Code:
    Public Function Assemble() As Byte()
        Dim _rtnBytes As New List(Of Byte) '' Final output, as bytes of raw cpu instructions - intel x86.
        Dim _asmCmdType As AsmCommandType        'Number of operands: 0,1,2
        Dim _currentLineCount As Int32 = -1
        Dim _asmInstruction As String = ""       'Only the instruction name (inc,dec,pop etc)
        Dim _firstOccuranceOfSpace As Int32 = -1
        Dim _tmpRightHandSingleOp As String = "" 'Instructions with only 1 operand
        Dim _tmpLeftHandOpString As String = ""  'Instructions with 2 operands: this is left side
        Dim _tmpRightHandOpString As String = "" 'Instructions with 2 opersnds: this is rigt side
        Dim _tmpExpressionType As AsmOperandType 'reg|num|[reg]|[num]|reg+num|[reg+num]|reg+reg|[reg+reg] etc.
        Dim _tmpBytes() As Byte

        For Each asmCmd As String In _asmLines.ToArray
            asmCmd = asmCmd.ToLower().Trim() ''flexibility
            _currentLineCount += 1
            _asmCmdType = GetAsmCommandType(asmCmd) '# of operands: 0,1,2
            If _asmCmdType = AsmCommandType.SingleInstuction Then
                '0 Operands in this inscrution
                Select Case asmCmd
                    Case "rtn"
                        _rtnBytes.Add(&HC3) '
                    Case "nop"
                        _rtnBytes.Add(&H90) '
                    Case "pushad"
                        _rtnBytes.Add(&H60) '
                    Case "popad"
                        _rtnBytes.Add(&H61) '
                    Case Else
                        Throw New Exception("Assemble: asmCmd is simple instruction (no operands), but is UNKNOWN instruction." & Environment.NewLine _
                                            & "Actual asm command issued: " & asmCmd & Environment.NewLine _
                                            & "On line #: " & _currentLineCount.ToString)
                End Select
            ElseIf _asmCmdType = AsmCommandType.InstructionOneOp Then
                'One Operand in this instruction
                _firstOccuranceOfSpace = asmCmd.IndexOf(" ")
                _asmInstruction = asmCmd.Substring(0, _firstOccuranceOfSpace)
                _tmpRightHandSingleOp = asmCmd.Substring(_firstOccuranceOfSpace + 1)
                _tmpExpressionType = GetOperandType(_tmpRightHandSingleOp)
                Select Case _asmInstruction
                    Case "push"
                        Select Case _tmpExpressionType
                            Case AsmOperandType.Numeric
                                If _tmpRightHandSingleOp.Length <= 2 Then
                                    'leave num as 1 byte
                                    _rtnBytes.Add(&H6A)
                                    _rtnBytes.Add(Byte.Parse(_tmpRightHandSingleOp, Globalization.NumberStyles.HexNumber))
                                Else
                                    'make num 4 bytes
                                    _rtnBytes.Add(&H68)
                                    _rtnBytes.AddRange(BitConverter.GetBytes(Int32.Parse(_tmpRightHandSingleOp, Globalization.NumberStyles.HexNumber)))
                                End If
                            Case AsmOperandType.Register
                                'which register is it?
                                Select Case _tmpRightHandOpString 'op1
                                    Case "eax"
                                        _rtnBytes.Add(&H50)
                                    Case "ecx"
                                        _rtnBytes.Add(&H51)
                                    Case "edx"
                                        _rtnBytes.Add(&H52)
                                    Case "ebx"
                                        _rtnBytes.Add(&H53)
                                    Case "esp"
                                        _rtnBytes.Add(&H54)
                                    Case "ebp"
                                        _rtnBytes.Add(&H55)
                                    Case "esi"
                                        _rtnBytes.Add(&H56)
                                    Case "edi"
                                        _rtnBytes.Add(&H57)
                                    Case Else
                                        Throw New Exception("Assemble: asmCmd is complex instruction (with one operand), but is UNKNOWN operand." & Environment.NewLine _
                                                            & "Actual asm command issued: " & asmCmd & Environment.NewLine _
                                                             & "On line #: " & _currentLineCount)
                                End Select
                            Case AsmOperandType.ValueOfRegister
                                'which register is it?
                                Select Case _tmpRightHandSingleOp
                                    Case "[eax]"
                                    Case "[ecx]"
                                        '...
                                End Select
                            Case AsmOperandType.RegisterPlusRegister
                            Case AsmOperandType.RegisterPlusRegisterTimesNumeric

                        End Select
                    Case "pop"
                    Case "inc"
                    Case "dec"
                    Case Else
                        Throw New Exception(Assemble: asmCmd is complex instruction (with one operand)" & Environment.NewLine _
                                            & "UNKNOWN instruction: " & _asmInstruction & Environment.NewLine _
                                            & "(with operand of: " & _tmpRightHandSingleOp & ")" & Environment.NewLine _
                                            & "On line #: " & _currentLineCount.ToString)
                End Select
            Else
                'Two Operands in this instruction : AsmCommandType.InstructionTwoOps
                _firstOccuranceOfSpace = asmCmd.IndexOf(" ")
                _asmInstruction = asmCmd.Substring(0, _firstOccuranceOfSpace)
                _tmpRightHandSingleOp = asmCmd.Substring(_firstOccuranceOfSpace + 1)
                _tmpLeftHandOpString = Split(_tmpLeftHandOpString, ",")(0)
                _tmpRightHandOpString = Split(_tmpLeftHandOpString, ",")(1) 'inefficient to call Split twice. But code is cleaner :\ Could use .IndexOf() and .SubString() again.
                ''this will be the complicated bit. todo:
            End If
        Next
 
bp

Code:
    Public Enum AsmOperandType As Int32
        'reg | num | [reg] | [num] | reg+reg | [reg+reg] | [reg+num] | reg+reg*num | [reg+reg*num]
        Register = 1
        Numeric
        ValueOfRegister
        ValueOfNumeric
        RegisterPlusRegister
        ValueOfRegisterPlusRegister
        ValueOfRegisterPlusNumeric
        RegisterPlusRegisterTimesNumeric
        ValueOfRegisterPlusRegisterTimesNumeric
    End Enum
Code:
    Private Function GetAsmCommandType(ByVal opString As String) As AsmCommandType
        If Not opString.Contains(" ") Then
            ''Single instruction like rtn, popad, pushad, nop : no operands.
            Return AsmCommandType.SingleInstuction
        Else
            ''String has space in it: has operand(s) on right side.
            If opString.Contains(",") Then
                Return AsmCommandType.InstructionTwoOps 'Two operands, like 'mov eax,ebp' , 'mov [eax],ebp'
            Else
                Return AsmCommandType.InstructionOneOp 'One operand like 'push eax' , 'pop eax' 
            End If
        End If
    End Function
Code:
    Public Function GetOperandType(ByVal opString As String, Optional ByVal lineNumber As Int32 = 1) As AsmOperandType
        'reg | num | [reg] | [num] | reg+reg | [reg+reg] | [reg+num] | reg+reg*num | [reg+reg*num]
        'reg*reg | [reg*reg]:[reg*reg+num] | 
        Dim _originalOpString As String = opString
        Dim _valueOf As Boolean = False ''If contains [ ]'s
        Dim _fistOccuranceOfDelimeter As Int32 = -1
        Dim _secondOccuranceOfDelimeter As Int32 = -1
        Dim _op1 As String = "" 'part1 of an operand
        Dim _op2 As String = "" 'optional part2 of an operand
        Dim _op3 As String = "" 'optional part3 of an operand
        Dim _delimeter1 As Char = ""
        Dim _delimeter2 As Char = ""
        Dim _tmpChar As Char = ""
        If opString.StartsWith("[") Then
            _valueOf = True
            If Not opString.EndsWith("]") Then
                Throw New Exception("AbAsm::GetOperandType--> MISSING closing ] bracket." & Environment.NewLine _
                & "Actual instruction issued: " & opString & Environment.NewLine & "On line #: " & lineNumber.ToString)
            Else
                opString = opString.Replace("[", "")
                opString = opString.Replace("]", "") 'Remove the brackets. Use _valueOf if needed, or _origOpString.
            End If
        End If

        For cc As Int32 = 0 To opString.Length - 1
            _tmpChar = opString(cc)
            If _tmpChar = "+" Or _tmpChar = "-" Or _tmpChar = "*" Then 'check string for these 3 chars
                _fistOccuranceOfDelimeter = cc
                _delimeter1 = _tmpChar
                Exit For
            End If
        Next
        If _fistOccuranceOfDelimeter > -1 Then
            'AT LEAST TWO EXPRESSIONS + - * 
            _op1 = opString.Substring(0, _fistOccuranceOfDelimeter)
            _op2 = opString.Substring(_fistOccuranceOfDelimeter + 1)
            'Does _op2 contain another expression?
            For cc As Int32 = 0 To _op2.Length - 1
                _tmpChar = _op2(cc)
                If _tmpChar = "+" Or _tmpChar = "-" Or _tmpChar = "*" Then
                    _secondOccuranceOfDelimeter = cc
                    _delimeter2 = _op2(_secondOccuranceOfDelimeter)
                    _op3 = opString.Substring(_fistOccuranceOfDelimeter + _op2.Length)
                End If
            Next
            Select Case _delimeter1
                Case "+"
                Case "-"
                Case "*"
            End Select
        Else
            'no special char! Is simply one numeric or register!
            If IsHexString(opString) Then
                If _valueOf Then
                    Return AsmOperandType.ValueOfNumeric
                Else
                    Return AsmOperandType.Numeric
                End If
            Else
                If _listOfRegisterNames.Contains(opString) Then
                    If _valueOf Then
                        Return AsmOperandType.ValueOfRegister
                    Else
                        Return AsmOperandType.Register
                    End If
                Else
                    Throw New Exception("AbAsm::GetOperandType--> Operand is unknown REGISTER name?)" & Environment.NewLine _
                                        & "Actual operand string: " & opString & Environment.NewLine & "On line#: " & lineNumber.ToString)
                End If
            End If
        End If
''UNFINISHED
Return AsmOperandType.Unknown

Restarting from scratch, (is it restarting if it's < 100 lines of code? lol) hopefully a little more object-oriented.
This is probably not a good way to go about it. Until next time.
http://www.planetpdf.com/codecuts/pdfs/aoa.pdf - "Art of Assembly "

Is exactly what I was looking for (except a little outdated - author keeps talking about 48bit cpu's coming soon)

Page 127 ish.

Hopefully a code update next week.


 
OldCodeNoPointReally

Code:
Public Structure AsmCommand
    Private _origCommandString As String
    Private _asmInstruction As String
    Private _operandCount As Int32
    Private _leftOperand As AsmOperand
    Private _rightOperand As AsmOperand

    Public Sub New(ByVal fullCommandString As String)
        Me.SetCommand(fullCommandString)
    End Sub
    Public Sub SetCommand(ByVal fullCommandString As String)
        _origCommandString = fullCommandString.ToLower().Trim()
        _asmInstruction = ""
        _operandCount = 0
        Dim _asmCmdString As String = _origCommandString
        Dim _firstOccuranceOfSpace As Int32 = -1
        Dim _firstOccuranceOfComma As Int32 = -1
        Dim _leftOpString As String = ""
        Dim _rightOpString As String = ""
        _firstOccuranceOfSpace = _asmCmdString.IndexOf(" ")
        If _firstOccuranceOfSpace = -1 Then
            _operandCount = 0 'Single command rtn, popad, pushad, nop : no (0) operands.
            Me._asmInstruction = _asmCmdString
            Me._operandCount = 0
        Else 'string has space in it: has operand(s) on right side.
            _asmCmdString = _asmCmdString.Substring(_firstOccuranceOfSpace + 1) 'remove the "instrction+space"
            _asmCmdString = _asmCmdString.Replace(" ", "") 'remove any white-space (un-needed space characters ie. 'mov    eax,   1234' becomes 'mov eax,1234')
            _firstOccuranceOfComma = _asmCmdString.IndexOf(",")
            If _firstOccuranceOfComma = -1 Then
                _operandCount = 1 'Instruction with 1 operand ex. 'push eax'
                Me._leftOperand.SetText(_asmCmdString)
            Else
                _operandCount = 2 'Instruction with 2 operands ex. 'mov' and 'add'
                _leftOpString = _asmCmdString.Substring(0, _firstOccuranceOfComma) 'op1
                _rightOpString = _asmCmdString.Substring(_firstOccuranceOfComma + 1) 'op2
                _leftOperand.SetText(_leftOpString)
                _rightOperand.SetText(_rightOpString)
            End If
        End If

    End Sub
    Public ReadOnly Property OperandCount As Int32
        Get
            Return _operandCount
        End Get
    End Property
    Public ReadOnly Property OperandOne As AsmOperand
        Get
            Return _leftOperand
        End Get
    End Property
    Public ReadOnly Property OperandTwo As AsmOperand
        Get
            Return _rightOperand
        End Get
    End Property
    Public ReadOnly Property InstructionName As String
        Get
            Return _asmInstruction
        End Get
    End Property

#Region "Boilerplate"
    Public Structure AsmOperand
        'mov [eax+ecx*4],1234
        Private _fullOperandString As String
        Private _operandType As AsmOperandType

        Public Arg1 As AsmOperandSubExpression
        Public Arg2 As AsmOperandSubExpression
        Public Arg3 As AsmOperandSubExpression
        Public Operator1 As Char ' +- or *
        Public Operator2 As Char ' +- or *

        Public ReadOnly Property OperandType As AsmOperandType
            Get
                Return _operandType
            End Get
        End Property
        Public ReadOnly Property AsString As String
            Get
                Return _fullOperandString
            End Get
        End Property
        Public Sub SetText(ByVal oppString As String)
            'reg | num | [reg] | [num] | reg+reg | [reg+reg] | [reg+-num] | [reg+reg*num] |reg*reg | [reg*reg]
            _fullOperandString = oppString
            Dim _originalOpString As String = oppString
            Dim _valueOf As Boolean = False ''If contains [ ]'s
            Dim _fistOccuranceOfDelimeter As Int32 = -1 'addition, subtraction, and multiplication operator symbols: + - *
            Dim _secondOccuranceOfDelimeter As Int32 = -1 '+ - *
            Dim _val1 As String = "" 'part1 of an operand
            Dim _val2 As String = "" 'optional part2 of an operand
            Dim _val3 As String = "" 'optional part3 of an operand
            Dim _delimeter1 As Char = ""
            Dim _delimeter2 As Char = ""
            Dim _tmpChar As Char = ""
            If oppString.StartsWith("[") Then
                _valueOf = True
                If Not oppString.EndsWith("]") Then
                    Throw New Exception("AbAsm.AsmOperand.SetText() MISSING ']' (closing bracket)." & Environment.NewLine _
                    & "Actual operand issued: " & oppString)
                Else
                    _valueOf = True
                    oppString = oppString.Replace("[", "")
                    oppString = oppString.Replace("]", "") 'Remove the brackets. 
                End If
            End If
            For cc As Int32 = 0 To oppString.Length - 1
                _tmpChar = oppString(cc)
                If _tmpChar = "+" Or _tmpChar = "-" Or _tmpChar = "*" Then 'check string for these 3 chars
                    _fistOccuranceOfDelimeter = cc
                    _delimeter1 = _tmpChar
                    Exit For
                End If
            Next
            If _fistOccuranceOfDelimeter > -1 Then
                'AT LEAST TWO EXPRESSIONS + - * 
                _val1 = oppString.Substring(0, _fistOccuranceOfDelimeter) 'equals left side of delimeter
                _val2 = oppString.Substring(_fistOccuranceOfDelimeter + 1) 'equals right side of delimeter
                'Does _val2 contain contain 2 sub-expressions?
                For cc As Int32 = 0 To _val2.Length - 1
                    _tmpChar = _val2(cc)
                    If _tmpChar = "+" Or _tmpChar = "-" Or _tmpChar = "*" Then 'delimeter found in string
                        ''3 sub expressions
                        _secondOccuranceOfDelimeter = cc
                        _delimeter2 = _val2(_secondOccuranceOfDelimeter)
                        _val3 = oppString.Substring(_fistOccuranceOfDelimeter + _val2.Length)
                        If _val3.StartsWith("0") Then _val3 = _val3.Remove(0, 1) 'turns 04 into 4 etc.
                        _val2 = _val2.Substring(0, _secondOccuranceOfDelimeter)
                        If _listOfRegisterNames.Contains(_val1) And _listOfRegisterNames.Contains(_val2) Then 'first 2 params are register names
                            If _delimeter1 = "-" Or _delimeter2 <> "*" Then Return AsmOperandType.InvalidFormat 'must be reg+reg*num
                            If _val3 = "2" Or _val3 = "4" Or _val3 = "8" Then
                                If _valueOf Then
                                    Return AsmOperandType.ValueOfRegisterPlusRegisterTimesNumeric
                                Else
                                    Return AsmOperandType.RegisterPlusRegisterTimesNumeric
                                End If
                            Else
                                Return AsmOperandType.InvalidFormat 'invalid multiplier?
                            End If
                        Else
                            Return AsmOperandType.InvalidFormat 'At least one of the first 2 params is not a valid register name
                        End If
                    End If
                Next
                If _secondOccuranceOfDelimeter = -1 Then 'Only 1 delimeter: is either reg+reg or reg+-num.

                End If
            Else
                If IsHexString(oppString) Then
                    'no special chars. Is simply one numeric.
                    If _valueOf Then
                        Return AsmOperandType.ValueOfNumeric
                    Else
                        Return AsmOperandType.Numeric
                    End If
                Else
                    If _listOfRegisterNames.Contains(oppString) Then
                        If _valueOf Then
                            Return AsmOperandType.ValueOfRegister
                        Else
                            Return AsmOperandType.Register
                        End If
                    Else
                        Throw New Exception("AbAsm::GetOperandType--> Operand is unknown REGISTER name?)" & Environment.NewLine _
                                            & "Actual operand string: " & opString & Environment.NewLine & "On line#: " & lineNumber.ToString)
                    End If
                End If
            End If
        End Sub
    End Structure
    Public Structure AsmOperandSubExpression
        Public AsString As String
        Public ExpressionType As AsmOperandSubExpressionType
    End Structure
    Public Enum AsmRegister As Int32
        unknown = 0
        eax
        ecx
        edx
        ebx
        esp
        ebp
        esi
        edi
    End Enum
    Public Enum AsmOperandType As Int32
        'reg | num | [reg] | [num] | reg+reg | [reg+reg] | [reg+num] | reg+reg*num | [reg+reg*num]
        Invalid = -1
        None = 0
        Register
        Numeric
        ValueOfRegister
        ValueOfNumeric
        RegisterPlusRegister
        ValueOfRegisterPlusRegister
        ValueOfRegisterPlusNumeric
        RegisterPlusRegisterTimesNumeric
        ValueOfRegisterPlusRegisterTimesNumeric
    End Enum
    Public Enum AsmOperandSubExpressionType As Int32
        none = 0
        register = 1
        numeric = 2
    End Enum
.

Code:
 Public Function Assemble() As Byte()
        Dim _rtnBytes As New List(Of Byte) '' Final output, as bytes of raw cpu instructions - intel x86.
        Dim _currentLineCount As Int32 = 0 ''source code line # (used for error messages)
        Dim _tmpAsmCmd As New AsmCommand

        For Each asmCmd As String In _asmLines.ToArray
            _tmpAsmCmd.SetCommand(asmCmd)

            Select Case _tmpAsmCmd.OperandCount
                Case 0
                    Select Case _tmpAsmCmd.InstructionName
                        Case "pushad"
                        Case "popad"
                        Case "rtn"
                        Case Else
                            MsgBox("UNKNOWN instruction name (with 0 operands).")
                    End Select
                Case 1
                    Select Case _tmpAsmCmd.InstructionName
                        Case "push"
                        Case "pop"
                        Case "inc"
                        Case "dec"
                        Case "jne"
                        Case "je"
                        Case "jle"
                        Case "jge"
                        Case Else
                            MsgBox("UNKNOWN instruction name (with 1 operand).")
                    End Select
                Case 2
                    Select Case _tmpAsmCmd.InstructionName
                        Case "add"
                        Case "sub"
                        Case "mov"

                    End Select
            End Select
        Next
        Return _rtnBytes.ToArray
    End Function
^^Obviously NOT finished/worked. Should be major changes soon.
You know a Git or SVN repo would be good for this (eg. Github, Bitbucket, Google Code)? That way you can add comments on any commits and whatnot without having to post on this thread with the updated code.
48-bit is way cooler than 64 bit anyways

Just clarifying, address bus size does not mean the bits of a processor. The 20 bit address bus of the 8088 doesn't mean it was a 20 bit processor.

Some things to add.

You also need to add subtraction in the operand types

lea eax, [ebp - 4] is an example




Quote Originally Posted by Auxilium View Post
48-bit is way cooler than 64 bit anyways
Just clarifying, address bus size does not mean the bits of a processor. The 20 bit address bus of the 8088 doesn't mean it was a 20 bit processor.
Some things to add.
You also need to add subtraction in the operand types
lea eax, [ebp - 4] is an example
Yeah, I'm extremely new to the hardware side of programming. I barely know what 'address bus' is/does, and definitely don't know it well enough to understand how it relates to other systems. It's a learning process: basically trying to RE the instruction set without knowing anything about assembly. For example, I know 'lea' stands for 'load effective address', but have no idea how/when to use it (vs. 'mov' ?). I'm starting to study the 'easy' instructions like push/pop, and mov as it seems the most important: will start looking at more once I understand the basics (of asm) well enough.
For the negative number thing: I'll add it once I understand the rest more. From what I thought, basically neg. numbers are just in the "two's compliment" format, and the instruction byte(s) stays the same. For example..
mov eax,+1234; = B8 34120000
mov eax,-1234; = B8 CCEDFFFF

Details are a little fuzzy (been doing this 2 days: you'd think with only 8 general-purpose register it'd be easy, but everything being in hex, and so similar, it's a slow process). Thnx for the reminder. Once I get it to efficiently support what I consider to be the basic commands I'll upload it and ask people to try it out with their code-caves and tell me which things are missing/needed.

edit:
I noticed for example,
Code:
Any time an operand is [reg+reg] , reg+reg is a constant where...

eax,eax = 00
eax,ecx = 08
eax,edx = 10
eax,ebx = 18
eax,esp = 04
eax,ebp = 28
eax,esi = 30
eax,edi = 38
etc
..
And for any instruction (any that I've tested obviously), if there is [reg+reg] as one operand, that 'constant' byte will be in the instruction! For example.. (you can see all the reg+reg constants in the 'wide' pic above)

example: mov [eax+ecx],edx ; 89 14 08
where 08 = the constant r+r
and 14 = constant from the pic (not sure what to call them)
I'm not sure what these relationships means exactly, or why I'm posting it, but I feel it's important. I think I see a way to accomplish what I want, but it involves tons of select statements / cases - I think there is more structure to it than that. Cisc vs risc type stuff. ? Anyway.

----
Question:
The thing that 'threw me off' most was (not being aware of)..the different types the operands can be? For example
Code:
mov reg,reg;
mov reg,num
mov reg,[reg]
mov reg,[num]
mov reg,[reg+num]
mov reg,[reg+reg]
mov reg,[reg+reg+1byte]
mov reg,[reg+reg+4byte]
mov reg,[reg+reg*2] , mov reg,[reg+reg*4], mov reg,[reg+reg*8]
Does that sum up all the possible combinations of 'sub expressions' able to be in an operand?
(excluding addition/subtraction-of-number cases)
Posts 31–36 of 36 · Page 3 of 3

Post a Reply

Similar Threads

Tags for this Thread

None

Talk with us