フォヌトバむトカヌおよびその他ネむティブアメリカン

画像



はい、はい、それは「バむト」であり、むンド語むンドではないです。 順番に始めたしょう。 最近、Habréで、バむトコヌドに関する蚘事が登堎し始めたした。 むかしむかし、フォヌトシステムを曞くのは楜しかったです。 もちろん、アセンブラヌで。 16ビットでした。 x86-64でプログラムしたこずはありたせん。 32でもプレむできたせんでした。 それで、考えが来たした-なぜですか 64ビットの砊を、そしおバむトコヌドでさえも攪拌しおみたせんか はい、Linuxでは、システムも䜜成しおいたせん。



Linuxを搭茉したホヌムサヌバヌがありたす。 䞀般に、私は少しグヌグルで調べお、LinuxのアセンブラヌはGASず呌ばれ、asコマンドであるこずがわかりたした。 私はSSH経由でサヌバヌに接続しおいたす。 すでにむンストヌルしおいたす。 それでもリンカヌが必芁です。ldず入力しおください-はい それで、アセンブラで䜕か面癜いこずを曞いおみおください。 文明がなければ、本物のむンド人のような森だけがありたす:)開発環境がなければ、コマンドラむンずミッドナむトコマンダヌのみ。 ゚ディタヌはNanoで、mcのF4にハングアップしたす。 グルヌプ「れロ」の歌はどうですか 真のむンド人に必芁なものは1぀だけです。 もちろん、デバッガヌ。 「gdb-is」ず入力したす。 さお、Shift + F4を抌しおください



建築



手始めに、アヌキテクチャを決めたしょう。 64ビットのビット深床を既に決定しおいたす。 埓来のFort実装では、デヌタずコヌドセグメントは同じです。 しかし、私たちはそれを正しくしようずしたす。 コヌドセグメントにはコヌド、デヌタセグメントにはデヌタのみが含たれたす。 その結果、プラットフォヌムのカヌネルず、プラットフォヌムに完党に䟝存しないバむトコヌドを取埗したす。



最速のスタックドバむトマシンJITなしを䜜成しおみたしょう。 したがっお、256個のアドレスを含むテヌブルが䜜成されたすバむトコマンドごずに1぀。 䜕よりも少ない-远加のチェック、これは1-2プロセッサ呜什です。 そしお、劥協するこずなく迅速に必芁です。



スタック



通垞、Fort実装では、プロセッサリタヌンスタック* SPがデヌタスタックずしお䜿甚され、フォヌトシステムリタヌンスタックは他の手段を䜿甚しお実装されたす。 実際、私たちのマシンはスタックされ、䞻な䜜業はデヌタスタックで行われたす。 したがっお、同じこずをしたしょう-RSPはデヌタスタックになりたす。 さお、リタヌンスタックをRBPずしたす。これは、デフォルトでスタックセグメントでも機胜したす。 したがっお、コヌドセグメント、デヌタセグメント、スタックセグメントの3぀のメモリセグメントがありたすデヌタスタックずリタヌンスタックの䞡方がありたす。



登録



レゞスタヌx86-64の説明に入りたす。 32たたは16ビットモヌドず比范しお、最倧8぀の远加の汎甚レゞスタR8-R16がありたす。



すでにRSPずRBPが必芁だず刀断したした。 バむトコヌドコマンドのポむンタヌカりンタヌがただ必芁です。 このレゞスタの操䜜のうち、メモリの読み取りのみが必芁です。 メむンレゞスタRAX、RBX、RCX、RDX、RSI、RDIはより柔軟で汎甚的であり、倚くの特別なコマンドがありたす。 これらはさたざたなタスクに圹立ちたす。バむトコヌド呜什カりンタヌには、新しいレゞスタの1぀を䜿甚したす。これをR8ずしたす。



始めたしょうか



Linuxでアセンブリ蚀語でプログラミングした経隓はありたせん。 したがっお、たず最初に、完成した「Hello、world」を芋぀けお、プログラムの開始方法ずテキストの衚瀺方法を理解したす。 予想倖に、゜ヌスずレシヌバヌさえ再配眮される奇劙な構文のオプションを芋぀けたした。 刀明したように、これはATT構文であり、䞻にGASで蚘述されおいたす。 ただし、別の構文オプションがサポヌトされおおり、Intel構文ず呌ばれたす。 考えお、私はそれをすべお同じように䜿甚するこずにしたした。 さお、.intel_syntax noprefixの最初に曞いおください。



「Hello、world」をコンパむルしお実行し、すべおが機胜するこずを確認したす。 ヘルプず実隓を読むこずで、次のコマンドを䜿甚しおコンパむルを開始したした。

$ as fort.asm -o fort.o -g -ahlsm >list.txt





ここで、-oスむッチは結果ファむルを瀺し、-gスむッチはデバッグ情報の生成を指瀺し、-ahlsmスむッチはリスト圢匏を蚭定したす。 そしお、リストに出力を保持したす。そこには、倚くの有甚なものが衚瀺されたす。 䜜業の開始時に、リストを䜜成せず、-gスむッチも指定したせんでした。 デバッガヌの最初の䜿甚埌に-gスむッチを䜿甚し始め、マクロがコヌドに珟れた埌にリストを䜜成し始めたした:)



その埌、リンカを䜿甚したすが、どこにも簡単なものはありたせん。



$ ld forth.o -o forth





さあ、走れ

$ ./forth

Hello, world!






動䜜したす。



これが最初のforth.asmでした実際には「Hellow、world」です。もちろん
 .intel_syntax noprefix .section .data msg: .ascii "Hello, world!\n" len = . - msg #  len    .section .text .global _start #     _start: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, OFFSET FLAT:msg #     mov edx, len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit xor ebx, ebx #    0 int 0x80 #  
      
      





ちなみに、少し埌でx86-64では、int 0x80ではなくシステムコヌルにsyscallを䜿甚する方が正しいこずがわかりたした。 0x80呌び出しは、サポヌトされおいたすが、このアヌキテクチャでは廃止されたず芋なされたす。



開始されたした、そしお今...



行こう



少なくずもいく぀かの詳现が存圚するため、1バむトコマンドのコヌドを蚘述したす。 フォヌトワヌド「0」ずし、スタックの先頭に0を眮きたす。



 bcmd_num0: push 0 jmp _next
      
      





このコマンドが実行された時点で、R8はすでに次のバむトコマンドを指しおいたす。 あなたはそれを読んで、R8を増やし、バむトコマンドのコヌドによっお実行可胜なアドレスを決定し、それに制埡を移す必芁がありたす。



しかし...バむトコマンドアドレステヌブルはどのビット深床になりたすか それから、私は新しいx86-64コマンドシステムをかなり掘り䞋げる必芁がありたした。 残念ながら、メモリ内のオフセットで移動できるコマンドは芋぀かりたせんでした。 したがっお、アドレスを蚈算するか、アドレスの準備が敎いたす-64ビットです。 蚈算する時間がありたせん。぀たり、64ビットです。 この堎合、テヌブルのサむズは256 * 8 = 4096バむトになりたす。 最埌に、_next呌び出しを゚ンコヌドしたす。



 _next: movzx rcx, byte ptr [r8] inc r8 jmp [bcmd + rcx*8] # bcmd -   -
      
      





悪くはないようですが、1぀のバむトコマンドから別のバむトコマンドに切り替えるずき、プロセッサ呜什は3぀しかありたせん。



実際、これらのコマンドは私にずっおそれほど簡単ではありたせんでした。 0x86-64コマンドシステムをもう䞀床調べお、新しいMOVZXコマンドを芋぀ける必芁がありたした。 実際、このコマンドは8、16、たたは32ビットの倀を64ビットのレゞスタに倉換したす。 このコマンドには2぀のバリアントがありたす。䞊䜍の桁にれロが埋め蟌たれる笊号なし、および笊号付きの1぀はMOVSXです。 笊号付きバヌゞョンでは、笊号が拡匵されたす。぀たり、正の数倀の堎合、れロは䞊䜍の桁に、負の数倀の堎合は1になりたす。 このオプションは、lit byteコマンドにも圹立ちたす。



ずころで、このオプションは本圓に最速ですか おそらく誰かがさらに速く提案するでしょうか



さお、これでバむトコマンドのシヌケンスを実行しお実行できるバむトマシンができたした。 少なくずも1぀のチヌムを匷制的に実行するには、実際にテストする必芁がありたす。 しかし、どれですか スタックはれロですか しかし、ここでは、デバッガヌの䞋でスタックを確認しないず、結果さえわかりたせん。しかし、プログラムが開始された堎合、完了できたす:)



特に「Hellow、world」があるので、プログラムを完了しおそれに぀いお曞く別れのコマンドを曞きたす。



 bcmd_bye: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bye #     mov edx, msg_bye_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 0 #    0 int 0x80 #  
      
      





残っおいるのは、バむトコマンドアドレスのテヌブルを䜜成し、レゞスタを初期化し、バむトマシンを起動するこずだけです。 そのため、テヌブルには256個の倀があり、2぀のコマンドがありたす。 他のセルには䜕がありたすか

残りには無効な操䜜コヌドが含たれたす。 しかし、あなたはそれをチェックするこずはできたせん。これらは䞍必芁なチヌムです。私たちは珟圚3぀あり、チェックでは5぀になりたす。 そのため、このようなスタブコマンドを䜜成したす-悪いチヌムです。 たず、テヌブル党䜓を埋めおから、䟿利なコマンドでセルを占有し始めたす。 悪いチヌムにはコヌド0x00を、byeチヌムにはコヌド0x01を、「0」にはコヌド0x02を曞きたす。 これたでの悪いチヌムは、完了コヌドずテキストが異なるだけで、さようならず同じこずをしたすさようならずほが同じように、スポむラヌに入れたした。



bcmd_bad
 bcmd_bad: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bad_byte #     mov edx, msg_bad_byte_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 1 #    1 int 0x80 #  
      
      



次に、アドレステヌブルを描画したす。 䟿宜䞊、各行に8個を配眮し、16個の行がありたすテヌブルのサむズは非垞に倧きくなりたす。



バむトコマンドアドレステヌブル
 bcmd: .quad bcmd_bad, bcmd_bye, bcmd_num0, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad
      
      



バむトプログラムの本䜓を蚘述したす。 これを行うには、コマンドコヌドをアセンブラ倉数に割り圓おたす。 次の契玄を締結したす。





したがっお、バむトプログラムの本䜓は次のようになりたす。



 start: .byte b_bye
      
      





デヌタスタックのサむズをstack_sizeずしお宣蚀したす。 ここたでは1024です。初期化時に、RBP = RSP-stack_sizeを実行したす。



実際、このようなプログラムコヌドforth.asmを取埗したす
 .intel_syntax noprefix stack_size = 1024 .section .data msg_bad_byte: .ascii "Bad byte code!\n" msg_bad_byte_len = . - msg_bad_byte #  len    msg_bye: .ascii "bye!\n" msg_bye_len = . - msg_bye msg_hello: .ascii "Hello, world!\n" msg_hello_len = . - msg_hello bcmd: .quad bcmd_bad, bcmd_bye, bcmd_num0, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad start: .byte b_bye .section .text .global _start #     _start: mov rbp, rsp sub rbp, stack_size lea r8, start jmp _next _next: movzx rcx, byte ptr [r8] inc r8 jmp [bcmd + rcx*8] b_bad = 0x00 bcmd_bad: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bad_byte #     mov edx, msg_bad_byte_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 1 #    1 int 0x80 #   b_bye = 0x01 bcmd_bye: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bye #     mov edx, msg_bye_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 0 #    0 int 0x80 #   b_num0 = 0x02 bcmd_num0: push 0 jmp _next
      
      







コンパむル、実行



$ as fort.asm -o fort.o -g -ahlsm >list.txt

$ ld forth.o -o forth

$ ./forth

bye!







うたくいく 1バむトからの最初のバむトコヌドプログラムが起動したした:)

もちろん、すべおが正しく行われおいれば、これは起こりたす。 そうでない堎合、結果は次のようになりたす。



$ ./forth









もちろん、他のオプションも可胜ですが、私はこれに最も頻繁に出くわしたした。 そしお、デバッガが必芁です。



デバッガヌの歌詞
すでに述べたように、私はGDBを䜿甚したした。 これは非垞に匷力なデバッガですが、コマンドラむンむンタヌフェむスを備えおいたす。 実行は非垞に簡単です。



 $ gdb ./forth GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./forth...done. (gdb)
      
      





次に、コマンドを入力しお、デバッグしたす。 必芁なコマンドを芋぀けお、デバッグに䜿甚する方法を孊ぶのに1時間かかりたした。 ここにありたす

b <label>-ブレヌクポむントを蚭定したす

l <label>-゜ヌスコヌドを衚瀺

r-プログラムを開始たたは再起動したす

ir-プロセッサレゞスタステヌタスの衚瀺

s-ステップ



ずころで、-gスむッチを䜿甚しおプログラムをコンパむルする必芁があるこずを芚えおいたすか そうしないず、タグず゜ヌスコヌドが利甚できなくなりたす。 この堎合、逆アセンブルされたコヌドのみでデバッグし、メモリ内のアドレスを䜿甚するこずができたす。 もちろん、私たちはむンド人ですが、同皋床ではありたせん...


しかし、どういうわけかプログラムはほずんど䜕もしたせん。 私たちは圌女に「こんにちは」ず蚀うだけで、圌女はすぐに「バむ」ず蚀いたす。 バむトコヌドで実際の「Hello、world」を䜜成したしょう。 これを行うには、アドレスず文字列の長さをスタックに配眮し、文字列を衚瀺するコマンドを実行しおから、byeコマンドを実行したす。 これをすべお行うには、新しいコマンドが必芁です。文字列を出力するために入力し、文字列のアドレスず長さを入力するために点灯したす。 最初に型を曞き、そのコヌドを0x80にしたす。 ここでも、sys_write呌び出しでそのコヌドが必芁です。



 b_type = 0x80 bcmd_type: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout pop rdx pop rcx push r8 int 0x80 #   pop r8 jmp _next
      
      





ここでは、POPコマンドを䜿甚しおデヌタスタックからアドレスず文字列の長さを取埗したす。 int 0x80を呌び出すず、R8のレゞスタが倉曎される可胜性があるため、保存したす。 プログラムが終了したため、これは以前は行いたせんでした。 これらのレゞスタの内容は気にしたせんでした。 これは通垞のバむトコマンドであり、その埌はバむトコヌドの実行が継続されるため、自分で行動する必芁がありたす。



それでは、ラむトを曞きたしょう。 これは、パラメヌタヌを䜿甚する最初のチヌムになりたす。 このコマンドのコヌドを含むバむトの埌に、スタックに入れる番号を含むバむトがありたす。 すぐに問題が発生したす-ここではどのビット深床が必芁ですか 任意の数を入力するには、64ビットが必芁です。 しかし、コマンドが9バむトを占有するたびに、䜕が1぀の数字になりたすか そのため、バむトコヌドの䞻芁なプロパティの1぀であるコンパクトさ、およびフォヌトのコヌドも倱われたす...



解決策は簡単です-ビット深床が異なる耇数のコマンドを䜜成したす。 これらは、lit8、lit16、lit32、lit64になりたす。 小さい数字にはlit8ずlit16を䜿甚し、倧きい数字にはlit32ずlit64を䜿甚したす。 小さい数字が最も頻繁に䜿甚され、それらには2バむトを芁する最短のコマンドがありたす。 悪くない..これらのコマンドのコヌドを0x08-0x0Bにしたす。



 b_lit8 = 0x08 bcmd_lit8: movsx rax, byte ptr [r8] inc r8 push rax jmp _next b_lit16 = 0x09 bcmd_lit16: movsx rax, word ptr [r8] add r8, 2 push rax jmp _next b_lit32 = 0x0A bcmd_lit32: movsx rax, dword ptr [r8] add r8, 4 push rax jmp _next b_lit64 = 0x0B bcmd_lit64: mov rax, [r8] add r8, 8 push rax jmp _next
      
      





ここでは、MOVSXコマンドを䜿甚したす。これは、既知のMOVZXコマンドのアむコンバヌゞョンです。 R8バむトコマンドカりンタヌがありたす。 目的のサむズの倀をロヌドし、次のコマンドに移動しお、64ビットに倉換された倀をスタックに配眮したす。



テヌブル内の新しいチヌムのアドレスを目的の䜍眮に远加するこずを忘れないでください。



これで、最初のプログラム「Hello、world」をバむトコヌドで曞く準備が敎いたした。 コンパむラヌで䜜業したしょう :)



 start: .byte b_lit64 .quad msg_hello .byte b_lit8 .byte msg_hello_len .byte b_type .byte b_bye
      
      





2぀の異なるlitコマンドを䜿甚したす。lit64は文字列のアドレスをスタックに配眮し、lit8は長さをスタックに配眮したす。 次に、さらに2぀のバむトコマンドを実行したすtypeずbye。

コンパむル、実行



 $ as fort.asm -o fort.o -g -ahlsm >list.txt $ ld forth.o -o forth $ ./forth Hello, world! bye!
      
      





バむトコヌドを獲埗したした これは、すべおが正垞な堎合の結果です。



完党な゜ヌス
 .intel_syntax noprefix stack_size = 1024 .section .data msg_bad_byte: .ascii "Bad byte code!\n" msg_bad_byte_len = . - msg_bad_byte #  len    msg_bye: .ascii "bye!\n" msg_bye_len = . - msg_bye msg_hello: .ascii "Hello, world!\n" msg_hello_len = . - msg_hello bcmd: .quad bcmd_bad, bcmd_bye, bcmd_num0, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x00 .quad bcmd_lit8, bcmd_lit16, bcmd_lit32, bcmd_lit64, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x10 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x20 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x30 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x40 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x60 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_type, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x80 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad start: .byte b_lit64 .quad msg_hello .byte b_lit8 .byte msg_hello_len .byte b_type .byte b_bye .section .text .global _start #     _start: mov rbp, rsp sub rbp, stack_size lea r8, start jmp _next _next: movzx rcx, byte ptr [r8] inc r8 jmp [bcmd + rcx*8] b_bad = 0x00 bcmd_bad: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bad_byte #     mov edx, msg_bad_byte_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 1 #    1 int 0x80 #   b_bye = 0x01 bcmd_bye: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bye #     mov edx, msg_bye_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 0 #    0 int 0x80 #   b_num0 = 0x02 bcmd_num0: push 0 jmp _next b_lit8 = 0x08 bcmd_lit8: movsx rax, byte ptr [r8] inc r8 push rax jmp _next b_lit16 = 0x09 bcmd_lit16: movsx rax, word ptr [r8] add r8, 2 push rax jmp _next b_lit32 = 0x0A bcmd_lit32: movsx rax, dword ptr [r8] add r8, 4 push rax jmp _next b_lit64 = 0x0B bcmd_lit64: mov rax, [r8] add r8, 8 push rax jmp _next b_type = 0x80 bcmd_type: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout pop rdx pop rcx push r8 int 0x80 #   pop r8 jmp _next
      
      







しかし、可胜性はただ非垞に原始的であり、条件、サむクルを䜜るこずはできたせん。



どうしお䞍可胜ですか できたす、すべおが私たちの手にありたす この行をルヌプで10回実行しおみたしょう。 これには、条件付き分岐コマンドずスタック挔算のビットが必芁になりたす。スタック䞊の倀を1枛らすコマンドfort "1-"ず頂点耇補コマンド "dup"です。



算術では、すべおが簡単です、私もコメントしたせん



 b_dup = 0x18 bcmd_dup: push [rsp] jmp _next b_wm = 0x20 bcmd_wm: decq [rsp] jmp _next
      
      





条件付きゞャンプ。 手始めに、タスクをより簡単にしたしょう。無条件の移行です。 レゞスタR8の倀を倉曎するだけでよいこずは明らかです。 最初に頭に浮かぶのは、バむトコマンドずそれに続くパラメヌタヌです。遷移アドレスは64ビットです。 再び9バむト。 これらの9バむトが必芁ですか 通垞、遷移は短距離で発生し、倚くの堎合数癟バむト以内です。 したがっお、アドレスではなくオフセットを䜿甚したす



ビット深床 倚くの堎合、8ビット前方/埌方127で十分ですが、堎合によっおはこれで十分ではありたせん。 したがっお、litコマンドず同じように、2぀のオプションを䜜成したす。8桁ず16桁、コマンドコヌドは0x10ず0x11です。



 b_branch8 = 0x10 bcmd_branch8: movsx rax, byte ptr [r8] add r8, rax jmp _next b_branch16 = 0x11 bcmd_branch16: movsx rax, word ptr [r8] add r8, rax jmp _next
      
      



条件付き遷移の実装が簡単になりたした。 スタックが0の堎合は_nextに進み、そうでない堎合はbranchコマンドに進みたす

 b_qbranch8 = 0x12 bcmd_qbranch8: pop rax or rax, rax jnz bcmd_branch8 inc r8 jmp _next b_qbranch16 = 0x13 bcmd_qbranch16: pop rax or rax, rax jnz bcmd_branch16 add r8, 2 jmp _next
      
      



これでルヌプを䜜成するためのすべおができたした。
 start: .byte b_lit8 .byte 10 #  #  m0: .byte b_lit64 .quad msg_hello .byte b_lit8 .byte msg_hello_len .byte b_type .byte b_wm .byte b_dup .byte b_qbranch8 .byte m0 - . .byte b_bye
      
      





最初の2぀のコマンド-ルヌプカりンタヌをスタックに配眮したす。次に、文字列Helloを出力したす。次に、カりンタヌから1を枛算し、耇補しお遷移を実行したすたたは実行したせん。条件分岐コマンドはスタックの先頭から倀を取埗するため、耇補コマンドが必芁です。ここでの遷移は、距離が数バむトしかないため、8ビットです。



新しいコマンドのアドレスをテヌブルに入れ、コンパむルしお実行したす。



私はそれをネタバレに入れたす、さもなければ私たちのプログラムは冗長になりたす
 $ as fort.asm -o fort.o -g -ahlsm >list.txt $ ld forth.o -o forth $ ./forth Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! bye!
      
      







たあ、私たちはすでに条件ずサむクルを行うこずができたす



完党な゜ヌス
 .intel_syntax noprefix stack_size = 1024 .section .data msg_bad_byte: .ascii "Bad byte code!\n" msg_bad_byte_len = . - msg_bad_byte #  len    msg_bye: .ascii "bye!\n" msg_bye_len = . - msg_bye msg_hello: .ascii "Hello, world!\n" msg_hello_len = . - msg_hello bcmd: .quad bcmd_bad, bcmd_bye, bcmd_num0, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x00 .quad bcmd_lit8, bcmd_lit16, bcmd_lit32, bcmd_lit64, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_branch8, bcmd_branch16, bcmd_qbranch8, bcmd_qbranch16, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x10 .quad bcmd_dup, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_wm, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x20 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x30 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x40 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x60 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_type, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x80 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad start: .byte b_lit8 .byte 10 #  #  m0: .byte b_lit64 .quad msg_hello .byte b_lit8 .byte msg_hello_len .byte b_type .byte b_wm .byte b_dup .byte b_qbranch8 .byte m0 - . .byte b_bye .section .text .global _start #     _start: mov rbp, rsp sub rbp, stack_size lea r8, start jmp _next _next: movzx rcx, byte ptr [r8] inc r8 jmp [bcmd + rcx*8] b_bad = 0x00 bcmd_bad: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bad_byte #     mov edx, msg_bad_byte_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 1 #    1 int 0x80 #   b_bye = 0x01 bcmd_bye: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bye #     mov edx, msg_bye_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 0 #    0 int 0x80 #   b_num0 = 0x02 bcmd_num0: push 0 jmp _next b_lit8 = 0x08 bcmd_lit8: movsx rax, byte ptr [r8] inc r8 push rax jmp _next b_lit16 = 0x09 bcmd_lit16: movsx rax, word ptr [r8] add r8, 2 push rax jmp _next b_lit32 = 0x0A bcmd_lit32: movsx rax, dword ptr [r8] add r8, 4 push rax jmp _next b_lit64 = 0x0B bcmd_lit64: mov rax, [r8] add r8, 8 push rax jmp _next b_type = 0x80 bcmd_type: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout pop rdx pop rcx push r8 int 0x80 #   pop r8 jmp _next b_dup = 0x18 bcmd_dup: push [rsp] jmp _next b_wm = 0x20 bcmd_wm: decq [rsp] jmp _next b_branch8 = 0x10 bcmd_branch8: movsx rax, byte ptr [r8] add r8, rax jmp _next b_branch16 = 0x11 bcmd_branch16: movsx rax, word ptr [r8] add r8, rax jmp _next b_qbranch8 = 0x12 bcmd_qbranch8: pop rax or rax, rax jnz bcmd_branch8 inc r8 jmp _next b_qbranch16 = 0x13 bcmd_qbranch16: pop rax or rax, rax jnz bcmd_branch16 add r8, 2 jmp _next
      
      





しかし、完成したバむトマシンが別の非垞に重芁な機胜を倱うたで。バむトコヌドから別のものを呌び出すこずはできたせん。ルヌチン、プロシヌゞャなどず呌ばれるものはありたせん。砊では、これがないず、䞀郚の単語でカヌネル単語以倖の単語を䜿甚できたせん。



私たちは仕事を終わらせたす。ここで初めお、リタヌンのスタックが必芁になりたす。callコマンドずreturnコマンド呌び出しず終了の2぀のコマンドが必芁です。



呌び出しコマンドは、原則ずしお、ブランチず同じこずを行いたす-制埡を別のバむトコヌドに転送したす。ただし、ブランチずは異なり、リタヌンスタックにリタヌンアドレスを保存しお、リタヌンしお実行を継続できるようにする必芁がありたす。別の違いがありたす-そのような呌び出しは、はるかに長い距離で発生する可胜性がありたす。したがっお、callコマンドはブランチのようになりたすが、8、16、32ビットの3぀のバヌゞョンになりたす。



 b_call8 = 0x0C bcmd_call8: movsx rax, byte ptr [r8] sub rbp, 8 inc r8 mov [rbp], r8 add r8, rax jmp _next b_call16 = 0x0D bcmd_call16: movsx rax, word ptr [r8] sub rbp, 8 add r8, 2 mov [rbp], r8 add r8, rax jmp _next b_call32 = 0x0E bcmd_call32: movsx rax, dword ptr [r8] sub rbp, 8 add r8, 4 mov [rbp], r8 add r8, rax jmp _next
      
      





ご芧のずおり、ここでは、移行ずは異なり、3぀のチヌムが远加されおいたす。そのうちの1぀はR8を次のバむトコマンドに再配眮し、残りの2぀は受信した倀をリタヌンスタックに栌玍したす。ずころで、ここでは、プロセッサパむプラむンがコマンドを䞊列に実行できるように、プロセッサ呜什を互いに䟝存させないようにしたした。しかし、これがどれほどの効果をもたらすかはわかりたせん。必芁に応じお、テストを確認できたす。



callコマンドの匕数の圢成は、ブランチの匕数の圢成ずは倚少異なるこずに留意しおください。分岐の堎合、オフセットは分岐アドレスずバむトコマンドに続くバむトのアドレスずの差ずしお蚈算されたす。 callコマンドの堎合、これはゞャンプアドレスず次のコマンドのアドレスの差です。なぜこれが必芁なのですかこれにより、プロセッサヌ呜什が少なくなりたす。



次にreturnコマンド。実際、圌女の仕事は、リタヌンスタックからR8を埩元し、制埡をバむトマシンにさらに転送するこずだけです。



 b_exit = 0x1F bcmd_exit: mov r8, [rbp] add rbp, 8 jmp _next
      
      





これらのコマンドは非垞に頻繁に䜿甚されるため、最倧限に最適化する必芁がありたす。exit byteコマンドは、3぀のマシン呜什を占有したす。ここで䜕かを枛らすこずは可胜ですかそれはあなたができるこずが刀明したした単に移行コマンドを削陀できたす:)



これを行うには、_nextバむトマシンの゚ントリポむントの䞊に配眮したす。



 b_exit = 0x1F bcmd_exit: mov r8, [rbp] add rbp, 8 _next: movzx rcx, byte ptr [r8] inc r8 jmp [bcmd + rcx*8]
      
      





ずころで、コンパむラが短いゞャンプコマンドを圢成できるように、最も重芁で頻繁に䜿甚されるコマンドたずえば、呌び出しなどをバむトマシンの近くに配眮する必芁がありたす。これはリストにはっきりず衚瀺されたす。以䞋に䟋を瀺したす。



  262 0084 490FBE00 bcmd_lit8: movsx rax, byte ptr [r8] 263 0088 49FFC0 inc r8 264 008b 50 push rax 265 008c EB90 jmp _next 266 267 b_lit16 = 0x09 268 008e 490FBF00 bcmd_lit16: movsx rax, word ptr [r8] 269 0092 4983C002 add r8, 2 270 0096 50 push rax 271 0097 EB85 jmp _next 272 273 b_lit32 = 0x0A 274 0099 496300 bcmd_lit32: movsx rax, dword ptr [r8] 275 009c 4983C004 add r8, 4 276 00a0 50 push rax 277 00a1 E978FFFF jmp _next 277 FF 278
      
      





ここで、265行目ず271行目では、jmpコマンドはそれぞれ2バむトを䜿甚し、277行目では、ゞャンプ距離が短いコマンドの長さを超えおいるため、同じコマンドがすでに5バむトにコンパむルされおいたす。



したがっお、bad、bye、typeなどのバむトコマンドはさらに再配眮され、call、branch、litなどはより近くに再配眮されたす。残念ながら、127バむトの遷移に適合するこずはあたりありたせん。

コヌドに埓っお、コマンドアドレスのテヌブルに新しいコマンドを远加したす。



だから、私たちは今挑戊ず埩垰を持っおいたす、私たちはそれらをテストしたすこれを行うには、別の手順でラむンプリントを遞択し、ルヌプで2回呌び出したす。そしお、サむクルの繰り返し回数は3回に枛りたす。



 start: .byte b_lit8 .byte 3 #  #  m0: .byte b_call16 .word sub_hello - . - 2 .byte b_call16 .word sub_hello - . - 2 .byte b_wm .byte b_dup .byte b_qbranch8 .byte m0 - . .byte b_bye sub_hello: .byte b_lit64 .quad msg_hello .byte b_lit8 .byte msg_hello_len .byte b_type .byte b_exit
      
      





ここではCall8を䜿甚できたすが、最もよく䜿甚されるものずしおcall16を䜿甚するこずにしたした。倀2は、私が曞いたcall byteコマンドのアドレスを蚈算する特性のために差し匕かれたす。call8の堎合、call32の堎合、それぞれ1がここから差し匕かれたす。4。

コンパむルしお呌び出したす。



 $ as forth.asm -o forth.o -g -ahlsm>list.txt $ ld forth.o -o forth $ ./forth Hello, world! Bad byte code!
      
      





おっず...圌らが蚀うように、䜕かがうたくいかなかった:)さお、私たちはGDBを起動し、そこで䜕が起こるか芋おみたしょう。sub_hello呌び出しが通過し、プロシヌゞャの本䜓が実行されおいるこずは明らかであるため、bcmd_exitにブレヌクポむントをすぐに蚭定したした... すぐにバむトコマンドコヌドの疑いがありたした。そしお、確かに、その理由は圌にありたした。b_exit倀0x1fを割り圓お、アドレス自䜓はテヌブルセル番号0x17に配眮されたした。それでは、b_exitの倀を0x17に修正しお、再詊行したす。



 $ as forth.asm -o forth.o -g -ahlsm>list.txt $ ld forth.o -o forth $ ./forth Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! bye!
      
      





䞁床6回の挚拶ず、さようなら。あるべきです:)



完党な゜ヌス
 .intel_syntax noprefix stack_size = 1024 .section .data msg_bad_byte: .ascii "Bad byte code!\n" msg_bad_byte_len = . - msg_bad_byte #  len    msg_bye: .ascii "bye!\n" msg_bye_len = . - msg_bye msg_hello: .ascii "Hello, world!\n" msg_hello_len = . - msg_hello bcmd: .quad bcmd_bad, bcmd_bye, bcmd_num0, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x00 .quad bcmd_lit8, bcmd_lit16, bcmd_lit32, bcmd_lit64, bcmd_call8, bcmd_call16, bcmd_call32, bcmd_bad .quad bcmd_branch8, bcmd_branch16, bcmd_qbranch8, bcmd_qbranch16, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_exit # 0x10 .quad bcmd_dup, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_wm, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x20 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x30 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x40 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x60 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_type, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad # 0x80 .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad .quad bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad, bcmd_bad start: .byte b_lit8 .byte 3 #  #  m0: .byte b_call16 .word sub_hello - . - 2 .byte b_call16 .word sub_hello - . - 2 .byte b_wm .byte b_dup .byte b_qbranch8 .byte m0 - . .byte b_bye sub_hello: .byte b_lit64 .quad msg_hello .byte b_lit8 .byte msg_hello_len .byte b_type .byte b_exit .section .text .global _start #     _start: mov rbp, rsp sub rbp, stack_size lea r8, start jmp _next b_exit = 0x17 bcmd_exit: mov r8, [rbp] add rbp, 8 _next: movzx rcx, byte ptr [r8] inc r8 jmp [bcmd + rcx*8] b_num0 = 0x02 bcmd_num0: push 0 jmp _next b_lit8 = 0x08 bcmd_lit8: movsx rax, byte ptr [r8] inc r8 push rax jmp _next b_lit16 = 0x09 bcmd_lit16: movsx rax, word ptr [r8] add r8, 2 push rax jmp _next b_call8 = 0x0C bcmd_call8: movsx rax, byte ptr [r8] sub rbp, 8 inc r8 mov [rbp], r8 add r8, rax jmp _next b_call16 = 0x0D bcmd_call16: movsx rax, word ptr [r8] sub rbp, 8 add r8, 2 mov [rbp], r8 add r8, rax jmp _next b_call32 = 0x0E bcmd_call32: movsx rax, dword ptr [r8] sub rbp, 8 add r8, 4 mov [rbp], r8 add r8, rax jmp _next b_lit32 = 0x0A bcmd_lit32: movsx rax, dword ptr [r8] add r8, 4 push rax jmp _next b_lit64 = 0x0B bcmd_lit64: mov rax, [r8] add r8, 8 push rax jmp _next b_dup = 0x18 bcmd_dup: push [rsp] jmp _next b_wm = 0x20 bcmd_wm: decq [rsp] jmp _next b_branch8 = 0x10 bcmd_branch8: movsx rax, byte ptr [r8] add r8, rax jmp _next b_branch16 = 0x11 bcmd_branch16: movsx rax, word ptr [r8] add r8, rax jmp _next b_qbranch8 = 0x12 bcmd_qbranch8: pop rax or rax, rax jnz bcmd_branch8 inc r8 jmp _next b_qbranch16 = 0x13 bcmd_qbranch16: pop rax or rax, rax jnz bcmd_branch16 add r8, 2 jmp _next b_bad = 0x00 bcmd_bad: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bad_byte #     mov edx, msg_bad_byte_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 1 #    1 int 0x80 #   b_bye = 0x01 bcmd_bye: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout mov ecx, offset msg_bye #     mov edx, msg_bye_len #   int 0x80 #   mov eax, 1 #   № 1 — sys_exit mov ebx, 0 #    0 int 0x80 #   b_type = 0x80 bcmd_type: mov eax, 4 #   № 4 — sys_write mov ebx, 1 #  № 1 — stdout pop rdx pop rcx push r8 int 0x80 #   pop r8 jmp _next
      
      







結果は䜕ですか



完党か぀かなり高速な64ビットスタックバむトマシンをテストしたした。速床においおは、おそらくこのバむトマシンはクラスで最速のマシンの1぀JITを持たないスタックバむトマシンです。圌女は、コマンドを順番に実行し、条件付きゞャンプず無条件ゞャンプを行い、プロシヌゞャを呌び出し、それらから戻る方法を知っおいたす。同時に、䜿甚されるバむトコヌドはかなりコンパクトです。基本的に、バむトコマンドは1〜3バむトかかりたすが、それ以䞊は非垞にたれです倧きな数字のみで、非垞に遠いプロシヌゞャコヌル。バむトコマンドの小さなセットもスケッチされおおり、簡単に拡匵できたす。スタックを操䜜するためのすべおの基本的なコマンドドロップ、スワップ、オヌバヌ、ルヌトなどを20分で曞くこずができ、同じ量が算術敎数コマンドに送られるず仮定したす。



もう䞀぀の重芁なポむント。バむトコヌドは、埓来のフォヌトの盎接瞫補コヌドずは異なり、機械語呜什を含たないため、再コンパむルせずに別のプラットフォヌムに転送できたす。カヌネルを新しいプロセッサの呜什システムに䞀床曞き換えれば十分であり、これは非垞に迅速に行うこずができたす。



バむトマシンの珟圚のバヌゞョンは、特定の蚀語に固有のものではありたせん。しかし、私はそれを䜿っおFort蚀語の実装を䜜りたいず思っおいたす。私はそれを䜿った経隓があり、そのためのコンパむラは非垞に迅速に行うこずができたす。



これに興味があれば、このマシンに基づいお、次の蚘事で、文字列ず数字、砊蟞曞、およびむンタプリタの入出力を行いたす。手でチヌムに「觊れる」こずができたす。さお、3番目の蚘事ではコンパむラヌを䜜成し、ほが完党な砊システムを取埗したす。その埌、いく぀かの暙準アルゎリズムを䜜成およびコンパむルし、パフォヌマンスを他の蚀語およびシステムず比范するこずが可胜になりたす。たずえば、゚ラトステネスのふるいなどを䜿甚できたす。



オプションを詊しおみるのは面癜いです。たずえば、コマンドテヌブルを16ビットにし、これがパフォヌマンスにどのように圱響するかを確認したす。_next゚ントリポむントをマクロに倉曎するこずもできたす。この堎合、各バむトコマンドのマシンコヌドは、2぀のコマンド遷移ず_nextからの3぀のコマンドを陀くのサむズが増加したす。぀たり、最埌には_nextぞの遷移はありたせんが、_nextの内容自䜓はこれは14バむトです。これがパフォヌマンスにどのように圱響するかを知るこずは興味深いです。レゞスタを䜿甚しお最適化を詊みるこずもできたす。たずえば、砊にカりンタヌがある暙準ルヌプは、カりンタヌをリタヌンスタックに栌玍したす。登録バヌゞョンを䜜成し、テストするこずもできたす。



叀兞的な圢匏たずえば、A = 5 +B + C * 4で蚘述された匏のコンパむラヌを䜜成するこずもできたす。



䞀般的に、実隓の䜙地がありたす :)



続きネむティブアメリカンの砊のバむトマシンだけでなくパヌト2



All Articles