目次:

Machine.netを使用する場合は、C#のみを備えたプラットフォームに依存しない仮想マシンを作成したい場合。
現在、X64のみがサポートされており、Intel 8253、8259チップセット、HPETがサポートされています。現在、可能性を追加するのではなく、X64エミュレーターで既存の問題を解決することに焦点を当てています。 X64エミュレーターが成功を示し始めたら、新機能が追加されますが、必要に応じて新機能を提案できます。
このリポジトリにスターを配置して、プロジェクトをサポートしてください。
Machine.netを使用すると、ICEDと呼ばれるNUGETパッケージもインストールされています。これは、命令を解読してエンコードするための人気のあるパッケージであり、Machine.netで命令を解読するために使用されます。
まず、Iced.intelを使用して、必要な指示を組み立てます。私たちの場合、それは次のとおりです。
mov rcx, 150
rep add rax, 4
それは次のとおりです。
using Iced . Intel ;
using Machine . X64 . Runtime ;
using static Iced . Intel . AssemblerRegisters ;
var assembler = new Assembler ( 64 ) ;
assembler . mov ( rcx , 150 ) ;
assembler . rep . add ( rax , 4 ) ;
var stream = new MemoryStream ( ) ;
var streamCodeWriter = new StreamCodeWriter ( stream ) ;
assembler . Assemble ( streamCodeWriter , rip : 0uL ) ;
stream . Position = 0 ;
var reader = new StreamCodeReader ( stream ) ;
var decoder = Decoder . Create ( 64 , reader ) ;
decoder . IP = 0 ;
var instrs = new List < Instruction > ( ) ;
while ( stream . Position < stream . Length )
{
decoder . Decode ( out var instr ) ;
instrs . Add ( instr ) ;
}そして今、単にcpuruntimeクラスの新しいインスタンスを作成します。メモリの量(バイト単位)とI/Oポートの数を渡すことができます。私たちの場合、これは64kbのメモリと8 I/Oポートです。
var runtime = new CpuRuntime ( memorySize : 65536 , ioPortCount : 8 ) ; CpuRuntimeの.Run(in Instruction)メソッドを呼び出して、命令を呼び出すことができます。すべての指示を呼びましょう:
foreach ( var instr in instrs )
{
runtime . Run ( in instr ) ;
} .Runメソッドは、ジャンプとブランチの指示をサポートする場合にわずかに制限する場合があります。その場合、直接バイトコードをRAMにロードしてそこからロードすることができます。
var cpu = new CpuRuntime ( ioPortCount : 8 ) ;
ulong x = 0uL ;
cpu . IOPorts [ 1 ] = new InputOutputPort (
read : ( ) =>
{
return 1234uL ;
} ,
write : ( value ) =>
{
x = value ;
} ) ;
byte [ ] code = CodeGen . MakeBranchTestCode_1 ( ) ;
cpu . LoadProgram ( code , 0uL ) ;
cpu . ProcessorRegisters . Cs = 0 ;
cpu . ProcessorRegisters . Rip = 0 ;
cpu . Use8086Compatibility ( ) ;
cpu . SetRsp ( 0x400uL ) ;
try
{
cpu . RunUntilNotBusy ( 35 ) ;
}
catch ( ArithmeticException )
{
throw new InvalidOperationException ( cpu . LastOrExecutingInstruction . Code . ToString ( ) ) ;
}
Assert . Equal ( 42uL , x ) ;
static class CodeGen
{
public static byte [ ] MakeBranchTestCode_1 ( )
{
var assembler = new Assembler ( 64 ) ;
Label lblA = assembler . CreateLabel ( "A" ) ;
Label lblC = assembler . CreateLabel ( "C" ) ;
Label lblB = assembler . CreateLabel ( "B" ) ;
assembler . Label ( ref lblA ) ;
assembler . mov ( ax , 42 ) ;
assembler . @out ( 1 , ax ) ;
assembler . call ( lblB ) ;
assembler . Label ( ref lblC ) ;
assembler . mov ( ax , bx ) ;
assembler . @out ( 1 , ax ) ;
assembler . hlt ( ) ;
assembler . Label ( ref lblB ) ;
assembler . mov ( bx , ax ) ;
assembler . call ( lblC ) ;
return Assemble ( assembler ) ;
}
private static byte [ ] Assemble ( Assembler assembler )
{
using var memoryStream = new MemoryStream ( ) ;
assembler . Assemble ( new StreamCodeWriter ( memoryStream ) , 0uL ) ;
return memoryStream . ToArray ( ) ;
}
}実際、Xは42です。.RununtilNotBusyメソッドは、CS:RIPまたはRIPのメモリからの指示の実行を開始します。 2つの過負荷があります。1つはINTとそうでないものです。実行する必要がある命令の最大量を表すものは、無限ループの場合に心配している場合に使用する方が安全です。パラメーターを取得しないものは、HLT命令まで実行され続けます。
また、 CpuRuntimeクラスの.ProcessorRegistersプロパティにアクセスして、CPUレジスタとフラグを検査し、いつでも変更することもできます。結果を確認するには、 raxレジスタを表示します。
Console . WriteLine ( runtime . ProcessorRegisters . Rax ) ;これにより600になりますが、これは正しいです。
外部デバイスを添付するには、独自のI/Oポートを作成して、読み取り/書き込み操作に必要なものを配置できます(はい、新しいウィンドウを作成して表示します。必要に応じて)。
var cpu = new CpuRuntime ( ioPortCount : 8 ) ;
ulong x = 42uL ;
cpu . IOPorts [ 1 ] = new InputOutputPort (
read : ( ) =>
{
return 1234uL ;
} ,
write : ( value ) =>
{
x = value ;
} ) ;たとえば、エミュレートされたCPUで次のコードを実行する場合:
mov eax , 7777
out 1 , eax
in eax , 1次に、CPUが7777をI/Oポートインデックス1に送信したことがわかります(I/Oポートは0からインデックス化されています)、EAXは1234に等しい(この単体テストをチェックしてください、かなりクールです):
Assert . Equal ( 7777uL , x ) ;
Assert . Equal ( 1234uL , cpu . ProcessorRegisters . Eax ) ;
// No failuresMachine.netを構築するには、.NET 8.0をインストールする必要があります。公式.NET Webサイトからダウンロードできます。
ビジュアルスタジオをご希望の場合:
.NET CLIをご希望の場合:
dotnet buildを入力します。または、 dotnet build -c Releaseを入力してリリースモードをビルドします(たとえば、最適化を有効にしてReal WorldアプリでMachine.netを使用する場合)。| ライブラリ名 | nuget url | このレポのソースコード |
|---|---|---|
| machine.x64.component.registers | クリックしてリダイレクトを送信します |
MITライセンス。著作権(c)Winscripter、2023-2024。