GetModRMBinaryメソッド修正
DIV命令の説明で述べましたが、MUL命令とDIV命令の違いはModR/Mです。ですから、GetModRMBinary
メソッドでその違いを表現することになります。これから筆者の実装例を提示しますので、MUL命令とDIV命令を分ける部分に注目して下さい。
'ModR/Mのバイナリを取得する Public Shared Function GetModRMBinary(ByVal cmd As CommandName, ByVal reg As RegisterName) As Byte Dim result As ModRM = New ModRM(0) result.ModValue = 3 Select Case cmd Case CommandName.Mul result.RegOrOpeValue = 4 Dim bit As Byte = GetRegisterBit(reg) If bit = 8 Then result.RMValue = GetRegisterByteModRMValue(reg) ElseIf bit = 32 Then result.RMValue = GetRegister32ModRMValue(reg) Else Throw New ArgumentOutOfRangeException("MULでは16ビットのレジスタを指定できません。") End If Case CommandName.Div result.RegOrOpeValue = 5 Dim bit As Byte = GetRegisterBit(reg) If bit = 8 Then result.RMValue = GetRegisterByteModRMValue(reg) ElseIf bit = 32 Then result.RMValue = GetRegister32ModRMValue(reg) Else Throw New ArgumentOutOfRangeException("DIVでは16ビットのレジスタを指定できません。") End If Case Else Throw New ArgumentOutOfRangeException(cmd & "はサポートしていません。") End Select Return result.Binary End Function
一見したところ前回と変わりませんが、重要な違いがあります。それはRegOrOpeValue
プロパティの設定箇所です。よく見ると、MUL命令ではRegOrOpeValue
プロパティの値が4、DIV命令の場合RegOrOpeValue
プロパティの値に5が設定していることに気づくと思います。これがMUL命令とDIV命令の違いです。
これで命令を完全に判別する材料が揃いましたので、次項にてIntelCpu
オブジェクトがMUL命令とDIV命令を判別できるようにします。
命令の判別法
MUL命令とDIV命令を判別するには、バイナリの解析機能であるAnalyzeBinary
メソッドを修正します。後で内容を解説しますので、まずは筆者の実装例を見て下さい。
'読み込まれたバイナリ値を解析して実行する命令を特定します。 Public Sub AnalyzeBinary() Dim binary As Byte While binarys.Count <> 0 '指定されている命令とレジスタを決定 binary = binarys.Dequeue() Dim ope As OpeCode = SearchOpeCodeMap(binary) '値を導出 Dim modrm As ModRM If ope.NextInfo = InfoType.Value Then '即値をバイナリから取得 If ope.BitCount = 32 Then Dim values(3) As Byte For i As Integer = 0 To 3 values(i) = Me.binarys.Dequeue() Next 'Intelはリトルエンディアンなので値を逆にする values = GetLittleEndianValue(values) '取得したバイト配列からダブルワードの値を構築 Dim value As UInteger = ConvertValues(values) ope.Value = New Register(value) Else ope.Value = New Register(binarys.Dequeue(), ope.IsHi) End If ElseIf ope.NextInfo = InfoType.Register Then 'レジスタから値を取得 modrm = New ModRM(Me.binarys.Dequeue()) If ope.BitCount = 32 Then Dim reg As RegisterName = GetRegister32Name(ModRM.RMValue) ope.Value = New Register(Me.GetRegister32Value(reg)) ElseIf ope.BitCount = 8 Then Dim reg As RegisterName = GetRegister8Name(modrm.RMValue) ope.Value = New Register(Me.GetRegisterByteValue(reg)) End If End If '命令が確定していないのならば決定 If ope.State <> OpeCodeState.Fixed Then Select Case modrm.RegOrOpeValue Case 4 ope.Name = CommandName.Mul Case 5 ope.Name = CommandName.Div Case Else Throw New ArgumentOutOfRangeException("ModR/MのRegOrOpeValueフィールドには" & modrm.RegOrOpeValue & "を指定しないで下さい") End Select ope.State = OpeCodeState.Fixed End If '実行する命令を記憶 cmds.Enqueue(ope) End While End Sub
ポイントは「命令が確定していないのならば決定」の部分です。ここまでの処理で、SearchOpeCodeMap
メソッド内で、ope
変数のState
プロパティにFixed
以外の値が設定されています。そこで、この部分では、ModR/MのRegOrOpeValue
プロパティの値で命令の判別を行っています。
これでオペコードのバイナリ値が同じ、MUL命令とDIV命令の判別ができるようになりました。後はDIV命令を実装して実行するだけです。