(Translated by https://www.hiragana.jp/)
自己書き換えコード - Wikipedia

自己じこえコード(じこかきかえコード、えい: self-modifying code)とは、目的もくてきわず実行じっこう自分じぶん自身じしん命令めいれいえるコードす。

自己じこえコードはアセンブリ言語げんご使用しようすると簡単かんたん記述きじゅつできる(CPUのキャッシュ考慮こうりょする必要ひつようがある)。 また、SNOBOL4LISPのようなインタプリタかた高級こうきゅう言語げんごでもサポートされている。また、COBOLにはALTERという命令めいれい存在そんざいしていた。 コンパイラ実装じっそうするのはむずかしいが、CLIPPERSPITBOLではそのこころみがおこなわれている。 バッチスクリプト自己じこえコードを頻繁ひんぱん使用しようする。

さい構成こうせい可能かのうコンピューティングは、ってみれば「自己じこハードウェア」である。 さい構成こうせい可能かのうコンピューティングはソフトウェアとハードウェアの境界きょうかい曖昧あいまいにする概念がいねんである。

自己じこえコードの用途ようと

編集へんしゅう

自己じこえコードは様々さまざま目的もくてきもちいられる。

  1. 状態じょうたい依存いぞんループの最適さいてき
  2. 実行じっこうコード生成せいせい実行じっこうあるいはロードアルゴリズムとくさせる(これは、リアルタイムグラフィックスなどの領域りょういき一般いっぱんてきである)。
  3. オブジェクトインライン状態じょうたい変化へんかさせる。あるいはクロージャ高度こうど構造こうぞうをシミュレートする。
  4. サブルーチン部分ぶぶんパッチてる。一般いっぱんダイナミックリンクライブラリをロードするときにおこなわれる。しかし、これを自己じこえコードとぶかどうかは場合ばあいによる。
  5. ダイナミックリンクライブラリのロードなどにサブルーチンをすアドレスにパッチをてる。これを自己じこえコードとぶかどうかは微妙びみょうである。
  6. 遺伝いでんてきプログラミングなど
  7. ぎゃくアセンブラデバッガ使つかったリバースエンジニアリングふせぐためにコードをかく目的もくてきおこなう。
  8. コンピュータウイルススパイウェアアンチウイルスソフトウェアからのがれる目的もくてきおこなう。
  9. メモリやディスク容量ようりょうかぎられている環境かんきょうで、コードを圧縮あっしゅくしておき、実行じっこう解凍かいとうしてから実行じっこうする。
  10. 命令めいれいセット非常ひじょうちいさい場合ばあい自己じこえコードを使つか以外いがい機能きのう実現じつげんできない場合ばあいがある。たとえば、「減算げんざんし、その結果けっかまけであれば分岐ぶんきする」 (subtract-and-branch-if-negative) という命令めいれいしかないコンピュータも原理げんりてきには可能かのうだが、この場合ばあいC言語げんごでの "*a = **b" に相当そうとうするような間接かんせつコピーは自己じこえコードを使つかわないと実行じっこうできない。

2と3はLISPのような高級こうきゅう言語げんごでもよく使つかわれる。

Linuxカーネル起動きどう環境かんきょうおうじた自己じこえをおこなったり (alternative.c)、デバッグようのコードを自己じこえで挿入そうにゅうするようにしたり (jump labels) して、コードの最適さいてきはかっている。また、自己じこえによって任意にんい位置いち性能せいのう解析かいせきをすることができる (perf events)。

状態じょうたい依存いぞんループを最適さいてきする自己じこえコード

編集へんしゅう

仮想かそうコードのれい以下いかとおりである。

repeat N かい {
  if STATE == 1
     A = A + 1
  else
     A = A - 1

  A にかんして処理しょりをする
}

自己じこえコードをこの場合ばあいてはめると、単純たんじゅんにループを以下いかのようにえる。

 repeat N かい {

  A = A + 1
  A にかんして処理しょりをする
 }
 
 when STATEが変化へんかしたとき {
    上記じょうき+ 命令めいれい-命令めいれいえる。
 }

ふたつの状態じょうたい対応たいおうした命令めいれいコードのえは、XOR交換こうかんアルゴリズム使つかえば簡単かんたん記述きじゅつできる。

この手法しゅほうをとるかどうかは N(ループ回数かいすう)がおおきいかどうかと、状態じょうたい変化へんか頻繁ひんぱんかどうかによる。

自己じこえコードにたいする態度たいど

編集へんしゅう

ほかにも有効ゆうこう選択肢せんたくしがある場合ばあい自己じこえコードはおすすめできないというひともいる。 というのは、自己じこえコードは理解りかいしにくいし、あとでメンテナンスが困難こんなんになるからである。

またひとは、自己じこえコードはたんにコーディングにやっていることを実行じっこうにやるだけじゃないかとう。

自己じこえコードは初期しょきのコンピュータでかぎりあるメモリ空間くうかん節約せつやくするために使つかわれていた。 また、単純たんじゅん分岐ぶんきしかないシステムでサブルーチンを実装じっそうするために自己じこえコードを使用しようする場合ばあいもあった。ドナルド・クヌースMIXアーキテクチャでもサブルーチンしを実現じつげんするために自己じこえコードを使用しようしていた。

また、未来みらい高度こうど進化しんかした人工じんこう知能ちのう本質ほんしつてき自己じこえをおこなうはずだと主張しゅちょうするものもいる。未来みらいのソフトウェアがユーザーとのやりりから学習がくしゅうし、ほとんど無限むげんパーソナライゼーション提供ていきょうするだろうという見方みかたもある。

偽装ぎそうのための自己じこえコード

編集へんしゅう

自己じこえコードは1980年代ねんだいMS-DOSうえのゲームで、コピープロテクションかくすのに使つかわれた。 フロッピーディスクドライブアクセス命令めいれいint 0x13」は、実行じっこうプログラムのイメージには存在そんざいしないのだが、実行じっこうプログラムがメモリにロードされると自己じこえを実施じっしし、コピープロテクションのためのフロッピーディスクアクセス命令めいれいまれるようになっていた。

自己じこえコードは自身じしん存在そんざいかくしたいプログラムにも使つかわれることがある。 すなわち、コンピュータウイルスなどである。 自己じこえコードを使用しようするウイルスのおおくは、同時どうじポリモルフィックコード使つかっている。 ポリモルフィック(多様たよう)なウイルスは、ある意味いみ自分じぶん突然とつぜん変異へんいさせるプログラムともえる。 動作どうさちゅうのコードをえることはあるしゅ攻撃こうげき(たとえばバッファオーバーラン)にも使つかわれる。

自己じこ参照さんしょうがた機械きかい学習がくしゅうシステムでの自己じこえコード

編集へんしゅう

機械きかい学習がくしゅうシステムは一般いっぱん学習がくしゅうアルゴリズムは事前じぜん用意よういされ固定こていであり、パラメータを変化へんかさせることで学習がくしゅうおこなう。しかし、Jürgen Schmidhuber は1980年代ねんだいから自己じこしき学習がくしゅうアルゴリズムをみずか変更へんこうできるシステムをいくつか発表はっぴょうしている。機能きのう不全ふぜんおちいるような自己じこえにおちいらないように、ユーザー指定していフィットネス関数かんすうなどを使つかって、有効ゆうこうえのみがのこるようにしている。

オペレーティングシステムおよびバイナリファイルフォーマットと自己じこえコード

編集へんしゅう

自己じこえコードはセキュリティじょう問題もんだいがあるため、いくつかのオペレーティングシステムではそれを禁止きんししている。懸念けねんされているのは、そのプログラム自身じしん自分じぶんのコードをえることではなく、他者たしゃ悪意あくいってコードを改変かいへんすることである。たとえばOpenBSD最近さいきんのバージョンは W^X英語えいごばん("write XOR execute")という機能きのうっており、あるメモリページについてプログラムはむことができるか「あるいは」実行じっこうすることができるが、んで実行じっこうすることはできないというものである。W^X 機能きのうった OpenBSDでは自己じこえコードは通常つうじょう動作どうさできない。自己じこえが必要ひつようなプログラムは、mmap で PROT_EXEC | PROT_WRITE 属性ぞくせいでページをマッピングしてそこにコードをまなければならない。

メタなレベルでかんがえれば、適切てきせつなデータ構造こうぞう使つかうことでいを変化へんかさせるプログラムは一種いっしゅ自己じこえともえる(メタプログラミング参照さんしょう)。

バイナリ実行じっこうファイルフォーマットのうち、UnixけいOSにてひろもちいられているELFにあっては、プログラムヘッダの記述きじゅつもとづいて実行じっこうファイルのかくセグメントをメモリじょうにロードないしは確保かくほする。プログラムヘッダにはセグメントへのアクセス権限けんげんふくまれているため、コードセグメントのアクセス権限けんげんみと実行じっこう両者りょうしゃあたえれば理論りろんじょうはコードの自己じこえが可能かのうとなる。ただし、ELFがもちいられている実行じっこう環境かんきょうではメモリ保護ほごによるコードの禁止きんし前提ぜんていとしていることが一般いっぱんてきなため、通常つうじょうリンカはコードセグメントにみと実行じっこうりょう権限けんげんあたえないように設定せっていする。

ジャストインタイムコンパイラ

編集へんしゅう

Javaなどのプログラミング言語げんごには ジャストインタイムコンパイラがあり、ちいさなプログラムを機械きかい変換へんかんして即座そくざ実行じっこうする。

キャッシュと自己じこえコードの問題もんだい

編集へんしゅう

最近さいきんのプロセッサでは自己じこえコードは実行じっこう速度そくどおそくなる。 実行じっこうコードをえると、命令めいれいキャッシュ保持ほじしていたはず命令めいれい使つかえなくなるので、メモリからキャッシュにロードしなおさなければならなくなり、おそくなるのである。

つまり自己じこえコードで性能せいのう改善かいぜんはかれるのは、えがごくまれにしか発生はっせいしない、ループないのスイッチえ(前述ぜんじゅつ状態じょうたい依存いぞんループ)のような場合ばあいだけである。 コードえは一瞬いっしゅんわるわけではないから、これはなに命令めいれいキャッシュにかぎった問題もんだいではない。

最近さいきんのプロセッサは命令めいれい実行じっこうまえ内部ないぶむので、プログラムカウンタにちか箇所かしょえるとプロセッサがそれにづかない可能かのうせいがあり、まえのコードを実行じっこうしてしまうことがある。これについては命令めいれいプリフェッチキュー参照さんしょうされたい。

NASM文法ぶんぽう自己じこx86アセンブラコード:命令めいれいプリフェッチキューのサイズ測定そくてい

code_starts_here:
   xor cx, cx                  ; レジスタ cx をゼロクリア
   xor ax, ax                  ; レジスタ ax をゼロクリア

around:
   cmp ax, 1                   ; ax が変化へんかしたかチェック
   je found_size

   mov [nop_field+cx], 0x90    ; 0x90 = "nop" (NO oPeration)命令めいれいオペコード
   inc cx

   jmp short flush_queue
flush_queue:
 
   mov [nop_field+cx], 0x40    ; 0x40 = "inc ax" (INCrease ax)命令めいれいのオペコード

nop_field:
   nop times 256
   jmp around
found_size:

   ;
   ;    これで、レジスタ cx は命令めいれいプリフェッチキューのサイズを保持ほじしている
   ;

このコードは処理しょりながれを変更へんこうしてちからずくで命令めいれいプリフェッチキューのおおきさを調しらべるものである。 コードを順次じゅんじえていき、どれだけえたらプロセッサが命令めいれいをフェッチするかを調しらべることでキューのながさがわかる。 これをプロテクトモードで実行じっこうするさいにはコンテキストスイッチ発生はっせいしないようにしなければならない。 さもなくば、このプログラムは間違まちがったかえすだろう。

関連かんれん項目こうもく

編集へんしゅう

外部がいぶリンク

編集へんしゅう