読者です 読者をやめる 読者になる 読者になる

ヾノ*>ㅅ<)ノシ帳

技術ブログに見せかけて、ジャンル制限のないふりーだむなブログです。

セキュリティ・キャンプ全国大会2015 僕の応募用紙 前編ヾノ*>ㅅ<)ノシ

問題12の盛り上がりがないので晒しますよ。 ほぼ原文ママ。【】は今回のために加筆。一部カット。 前編は選択問題5までです。

選択した問題

  • 3(作ったもの)
  • 5(大学の講義の「計算機アーキテクチャ」と「コンパイラ」に相当)
  • 9(フロントエンドのセキュリティ対策)
  • 11(WiresharkとHeartbleed)
  • 12(ログインシェル)

■ 共通問題1

セキュリティ・キャンプに応募した自分なりの理由とセキュリティ・キャンプで学んだことを何に役立てたいかを教えてください。

セキュリティ・キャンプに応募した自分なりの理由

本当はセキュリティ・キャンプ(全国大会)は中学3年生の時から参加したいと思っていました。セキュリティ・キャンプを知った最初のきっかけは、旧「現役高校生サーバー管理者の考察日誌」(現「isidaiの考察日誌」)の、ドラマ「ブラッディ・マンデイ」のクラッキングシーンを考察したエントリを読んでいたからです。その後、同ブログでブログ主の石森大貴さんが2007年のセキュリティ・キャンプに参加したと知り、セキュリティ・キャンプの存在を知りました。考察記事のレベルから察するに、これほどすごい人が参加するイベントなのだからそれだけすごいレベルのイベントなのだろうと当時思いました。一応当時でも応募可能な年齢でしたが、自身の技術力・知識では選考が通らないだろうと卑屈になっていました。この態度が高校・大学になっても続きました。

元々キュリティへの関心は小学5, 6年生の頃からあり、小学時代はセキュリティソフトの仕組みやウイルスの種類についてトレンドマイクロシマンテックの記事を読んだりして深めていました。セキュリティに関する調べ事はその後も続き、今ではRSSリーダーTwitterを駆使しながら収集しています。 今までスルーしてきたセキュリティ・キャンプの存在を無視できなくなった直接のきっかけは、研究室のメーリングリストでお誘いのメールが回ってきたからです。参加上限の年齢が22歳で、今回応募しなければもう応募の機会さえありません。いっそダメ元で応募しようとなったわけです。

いざ応募問題を解いてみると案外解けてしまいました。自分が気づかずとも、RSSや大学に入ってから知り合ったすごい人、大学1年生の春休みから始めたWeb開発などのお陰で、技術力・知識力がセキュリティ・キャンプ応募に値するレベルまで上がったことを確認できました。

以上の心境の変化があり、最終的に応募のためにメールを差し上げることとなりました。

セキュリティ・キャンプで学んだことを何に役立てたいか

将来どの業界に進むのかはまだモヤモヤしています。セキュリティ業界に進む可能性は無きにしもあらず。たとえ、進んだ先がセキュリティ業界でなくても、近年はセキュリティ対策が重要視されているので(いずれはIoTにも?)、セキュリティの素養は職業的に重要です。長期的に見た場合、セキュリティ・キャンプで学んだことを何に役立てたいかの答は、いずれは仕事で役立てたいとなります。

短期的に見た場合でも役立ちます。現在の情報源はRSSTwitterに限られているため、どうしも得られる情報には限界があります。キャンプがきっかけで(人脈や情報源が増え、)ブレイクスルーが起こることを期待しています。現在進行形でセキュリティに関する話題をRSSTwitterを駆使して収集しており、可能な限りコーディングの場面(趣味プログラミング、学内バイト)で注意しています。一応技術ブログ的なものはちょこちょこ書いているのでどこかの場面で啓蒙できるかもしれません。【2文カット】

■ 共通問題2

セキュリティに関することで、過去に自分が経験したことや、ニュースなどで知ったことの中から、最も印象に残っていることを教えてください。また、その印象に残った理由も教えてください。

印象に残ったこと

【Heartbleedが本命でしたが、選択問題にこれをネタ元とするものがあったため、OpenSSL関連でCCS Injection脆弱性(CVE-2014-0224)を選びました】

印象に残った理由

まず目に飛び込んだ理由(関心をもった理由)は、この脆弱性の公表(2014年6月5日に同社Twitterで公表)がHeartbleedのそれから日が浅かったからです。またOpenSSLか、と思いながら読み始めた記憶があります。

実際に読んでみると、脆弱性を発見できたきっかけが論理証明によるものだと知って驚きました。なぜならうちの名古屋大学には「プログラムが特定の性質を満たすことを数理的な手法を用いて証明する研究」をしている結縁研究室(http://www.sqlab.jp/)があるからです。身近にそのようなことをしている人たちがいるため、彼らの研究成果がセキュリティの場面でも活かせるのかもしれないと思いを馳せました。短文ですが、以上がCCS Injection脆弱性が一番印象に残った理由です。

■ 共通問題3

その他に自己アピールしたいことがあれば自由に書いてください。(たとえば、あなたが希望する講座を受講する上で、どのような技術力を持っているか、部活動、技術ブログ、GitHub、ソフトウェア開発、プログラミングコンテスト、勉強会での発表・運営などの実績や熱意があれば、あるだけ書いてください。)

受講するときに役立つであろう技術力

  • C言語PHPJavascriptは不自由なく使える
  • リファレンスに頼っていいならrubypythonも可
  • プログラミング自体は大学一年後期から始めた
    • 一年後期のときはプログラミング雑魚過ぎてテストは60点(周りは7, 80点)
    • ↑よくここまで這い上がったな…(by 今の自分)
  • Windowsは主戦力として10年以上使ってるので、苦労なくそこで(Web)開発できる
  • 大学の講義の演習はLinux環境だったので基本的な操作(SSH接続含む)ができる
  • Linuxコンテナでなんかやってと言われれば、Vagrantを立ち上げてなにかし始められる
    • 選択問題12で、実際にVagrantで攻撃環境を構築したのでチェックしてくだされ!
  • Web開発は大学一年生春休みのときからしている(Web開発歴3年)
  • セキュリティ対策の知識は徳丸浩氏や大垣靖男氏のブログなどをチェックして仕入れた
  • 成果物
  • RSSリーダーを駆使して勉強会資料や技術者のブログ、セキュリティインシデント報告情報(←Twitterで騒ぎになるレベルのもの:技術評論社のあれやHeatbleedレベルのもの)などを読み漁っているのでWeb関連のテクノロジー全般に詳しく、今流行っているっぽいことを多く知っている
    • 今流行っているっぽいこと
      • 【セキュキャンに行けたときに備え、その場の会話ネタのためにとっておきますよ】

他の技術力

  • Google Apps Script
    • 最近、研究室で自分の勤怠管理をするためのシステムを構築
    • 週単位で集計結果をメールしてくれる
  • ModRewrite芸(一部の人はモッヨリライヨ芸)
    • ただし知識が不完全なのでhtaccessを完成させるのに時間がかかってしまう…
  • Selenium
    • ブラウザの自動操作のアレ
  • MS Access、シェル芸(awk含む)、VBA
    • 学内バイトの業務の一貫で、サーバの移行でデータを取り出すために活用

所属している研究室について

【身バレ要素なのでカット】

技術ブログ

ソフトウェア開発とGitHub

スッ(‘ω’)✌

高校3年生のとき、春期の基本情報技術者試験(FE)に合格

  • 午前:82.50点
  • 午後:76.80点

熱意

熱意はすべて選択問題5題にぶつけたのでよろしくお願いします(各問題2000字程度の回答)。

■選択問題3 

過去に作成したプログラムのうち最も気に入っているものについて答えてください。
ここでいうプログラムは、Webサービスやモバイルアプリ、サーバ/デスクトップアプリケーションあるいはOS、VMなどといったソフトウェア全般のことです。
(1)どのようなソフトウェアであるかを教えてください
(2)何の目的のためにそれを作ろうと思ったのか、理由を教えてください
(3)開発するにあたって工夫したところを教えてください
(4)新たな課題、今後勉強してみたいと思っている内容を書いてください

(1)どのようなソフトウェアであるか

概要

Kiitaというアプリケーションを気に入っています。increments株式会社がWebサービス「Qiita」(http://qiita.com/) を提供しており、技術者・(趣味)プログラマがMarkdownという記法で書いたテキストをWebページ向けに表示してくれます。KiitaはこのWebサービスの機能:MarkdownをレンダリングしてHTMLで表示する、を模倣したものです。ぱっと見Webサービスに見えますが、正確にはサーバアプリケーション(厳密にはライブラリ)です。実際の動作は http://katc.sakura.ne.jp/Kiita/ を訪問すれば分かります。リンク先のサイトを含めたアプリケーションのコードはGitHubで公開しています。

ソフトウェアの挙動

ライブラリ呼び出し部を含めると、Markdownファイルの入力が起こってからHTMLファイルが出力されるまでの流れは次のようになっています。

  1. 呼び出し側はAPIを通して変換したいMarkdownファイルを入力する
  2. Kiitaは入力されたMarkdownファイルをプロセッサ(外部ライブラリ)に投げてHTMLに変換する

これを見ると、Kiitaが何らかのライブラリのラッパーであることが分かりますね。

詳細

【長いのでカット】

(2)何の目的のためにそれを作ろうと思ったのか

目的

Qiitaでは自分が書いたMarkdownを簡単に公開することができます。しかし、Qiitaは地味にSEOが強く、それだけに自分が書いたことに責任を持たねばなりません。これでは物書きの手軽さがないなと思ったので、MarkdownファイルをWebページで公開するための仕組み(フレームワーク)を独自に持って置かねばならないと思い立ちました。このフレームワークはTexts 非公式日本語マニュアル(http://katc.sakura.ne.jp/works/TextsManual/) でも活躍してくれています。

きっかけ

Kiitaを作ろうと思ったもっと直接的な理由は、incrementsがQiitaのプロセッサ(qiita-markdown)をGitHubで公開したからです(https://github.com/increments/qiita-markdown)。ソースコードをざっと見てプログラムやファイルの構造がとても綺麗だったので真似してみようと思ったのです。実際にそれを動かそうとしましたがgemのエラーが出まくりで悔しかったこともきっかけの一つです。

(3)開発するにあたって工夫したところ

綺麗なソースコードの構造

qiita-markdownのソースコードは本当に綺麗です。本体の大元のファイルは必要な機能を読み込むだけです。その「必要な機能」はモジュール化されており、チーム開発において複数人で一つのファイルをいじり合うという気持ち悪いことが起こりにくくなっています。

Kiitaではこの構造をclassで実現しました。大元のファイルはclassを定義し、機能を拡張したくなったらファイルを増やして、そこで定義したものを大元から引っ張ってきます。

PHPでclassを用いたプログラミングをしたことがある諸氏ならば、特定のclassの定義は1つのファイルでしかできないだろと思うかもしれません。この問題点はtrait(http://php.net/manual/ja/language.oop5.traits.php)を用いて解決しました。traitのおかげで見通しの良いコーディングをすることができました。

サーバサイドのセキュリティ

とくに何も対策しなければKiitaは変換したいファイルを与えられると無条件にそのファイルを変換してしまいます。セキュリティ対策としてKiita自体で入力バリデーションをすると安全かもしれませんが、Kiitaを複数のプログラムで利用しあうことを考えると、呼び出し側によってバリデーションの要件が異なるのは明らかです。よって、Kiitaでは入力バリデーションは呼び出し側の義務としました。

ユーザ入力はファイル名(正確にはパス名)です。ユーザ入力の前にプレフィックスを付加するのでユーザ入力は相対パスに限られます。よって、入力バリデーションの内容はユーザ入力が相対パスであることをチェックするになります【ただし、ディレクトリトラバーサル注意】。ただし、この辺りはphp.iniに依りますが、phpのファイルの内容を読み取る関数file_get_contentsは引数にURLも指定可能なので、ユーザ入力がURLでないこともチェックするとフェールプルーフになると思って行うようにしました。

キャッシュ(負荷低減)

一般のWebサービスではmemchachedが使われるようですが、あいにく僕のさくらインターネットレンタルサーバーのライトプランではそれができません。ハード寄りの改善は自力でなんとかせねばなりません。

ユーザの要求に対して一々Markdownの変換処理をしていてはサーバの資源がもったいないです。Kiitaは変換結果を一定時間保持できるようなオプションを用意しています(キャッシュ機能)。キャッシュが効いているときに限り、コンマ数秒レスポンスが早くなりました。

車輪の再発明をしないというプログラミングの原則

車輪の再発明は避けたいものです(プログラマの三大美徳?)。Kiitaを実現する上で車輪の再発明となりうるものは次の機能です。

今回は既存の以下のライブラリを利用しました。

(4)新たな課題、今後勉強してみたいと思っている内容

新たな課題

Qiitaっぽさだけでではなく、GitHub風などいろいろな表示形式に対応できるようテンプレートを変えられるように出来るようにすればKiitaの活用幅が広くなると思います。よって、テンプレートの変更容易性の確保が新たな課題であると考えます。

今後勉強したい内容

外部ライブラリに任せていた「字句解析」「構文解析」を一度はやってみたいと思っています。ただ、どの「道具」(yacc, flex, 自力…etc)でそれをやってみるかが問題です…

といっても一番勉強せねばならないことは、自分の成果を広めるための施策を学ぶことかもしれませんね^^;

■選択問題5 

以下のようなC言語の関数functionがあるとします。

void function(int *array, int n) { int i; for(i = 0; i < n; i++) { array[i] = i * n; } }

上記プログラムをコンパイルした結果の一例 (i386)は以下となりました。

 00000000 <function>:
    0:   56                   push   %esi
    1:   53                   push   %ebx
    2:   8b 5c 24 0c          mov    0xc(%esp),%ebx
    6:   8b 4c 24 10          mov    0x10(%esp),%ecx
    a:   85 c9                test   %ecx,%ecx
    c:   7e 18                jle    26 <function+0x26>
    e:   89 ce                mov    %ecx,%esi
   10:   ba 00 00 00 00       mov    $0x0,%edx
   15:   b8 00 00 00 00       mov    $0x0,%eax
   1a:   89 14 83             mov    %edx,(%ebx,%eax,4)
   1d:   83 c0 01             add    $0x1,%eax
   20:   01 f2                add    %esi,%edx
   22:   39 c8                cmp    %ecx,%eax
   24:   75 f4                jne    1a <function+0x1a>
   26:   5b                   pop    %ebx
   27:   5e                   pop    %esi
   28:   c3                   ret  

このとき以下の(1)~(5)の設問について、回答と好きなだけ深い考察を記述してください。知らない点は、調査したり自分で想像して書いてもらっても結構です。どうしてもわからない部分は、具体的にここがわかりませんと記述しても良いです。(1)~(2)の回答は必ず答えてください。(3)~(5)の回答は任意です。わかることを書いてください。CPU やコンパイラは特定の実装を例に説明しても良いですし、理想を自由に考えても良いです。

(1)【必須】上記の C 言語のプログラムはどのような動作をしますか。また、この関数を呼び出して利用する main 関数の例を作成してください。

(2)【必須】上記のアセンブリコードを、いくつかのブロックに分割して、おおまかに何をしている部分かを説明してください。もし、上記のアセンブリが気に入らないのであれば、好きなアーキテクチャコンパイラアセンブル結果を載せて説明しても良いです。

(3)【任意】 コンパイラソースコードの関数を解釈して、ターゲットのアーキテクチャのバイナリを生成するまで、どのように内部で処理を行っていると思いますか。(キーワード: 構文解析、変数、引数、呼出規約、レジスタ、スタック、アセンブラ、命令セット)

(4)【任意】CPU の内部では、プログラムのバイナリはどのように解釈され実行されていると思いますか。(キーワード: フェッチ、デコード、オペコード、オペランド、命令パイプライン、回路)

(5)【任意】現在の CPU やコンパイラの不満点があれば自由に記述してください。

(1)

回答:C 言語のプログラムはどのような動作をするか

まずint型変数iを0で初期化する。次に、iがn未満であることを確認し、配列のサイズnとiの値の積をarray[i]に格納し、iをインクリメントする(処理A)。もし、iがn以上であればループを抜け、そうでなければ処理Aを繰り返すことになる。

ループを抜けた後は呼び出し元に制御が戻る。

回答:この関数を呼び出して利用する main 関数の例

#define ARRAY_LENGTH 4

int main(void){

    int array[ARRAY_LENGTH];
    int i;
    function(array, ARRAY_LENGTH);
    printf("--- content of array ---\n");
    for(i = 0; i < ARRAY_LENGTH; i++) {
        printf("[%d] %d\n", i, array[i]);
    }
    return 0;
}

参考:プログラム出力

--- content of array ---  
 [0] 0  
 [1] 4  
 [2] 8  
 [3] 12

考察

このプログラムはnによって、与えた配列arrayを各要素について添字のn倍の値で初期化するような関数であると見ることができます。関数(fucntion)にfunctionという名前をつけているので、この処理には深い意味がないように見えます。

(2)

回答:(特に指定がなかったので)基本ブロックに分割

次のようにB1~B6の6つの基本ブロックに分割できる。

 [B1]
   0:   56                   push   %esi             
   1:   53                   push   %ebx             
   2:   8b 5c 24 0c          mov    0xc(%esp),%ebx   [array]
   6:   8b 4c 24 10          mov    0x10(%esp),%ecx  [n]
   a:   85 c9                test   %ecx,%ecx        [n],[n]

 [B2]
   c:   7e 18                jle    26 <function+0x26>

 [B3]
   e:   89 ce                mov    %ecx,%esi        [n],[n]
  10:   ba 00 00 00 00       mov    $0x0,%edx        [n]
  15:   b8 00 00 00 00       mov    $0x0,%eax        [i]

 [B4]
  1a:   89 14 83             mov    %edx,(%ebx,%eax,4) [tmp],[array[i]]
  1d:   83 c0 01             add    $0x1,%eax        [i]
  20:   01 f2                add    %esi,%edx        [n],[tmp]
  22:   39 c8                cmp    %ecx,%eax        [n],[i]

 [B5]
  24:   75 f4                jne    1a <function+0x1a>

 [B6]
  26:   5b                   pop    %ebx
  27:   5e                   pop    %esi
  28:   c3                   ret  

回答:各ブロックが何をしているのかを大まかに説明

英文は「INTEL 80386 PROGRAMMER'S REFERENCE MANUAL 1986」(http://pdos.csail.mit.edu/6.828/2008/readings/i386.pdf) からの引用

ブロック1

汎用レジスタESI, EBXの内容を退避させ、関数functionの引数array, nの内容をスタック領域から読み込みます(呼び出し規約?)。

ブロック2

flag(flagは特定の命令の実行結果の副作用によって変更される)を見て、ジャンプ可能であるかを判定します。成立時はブロック6にジャンプします。判定の成立可否については考察で検討します。

ブロック3

ブロック4を見るとEAXに対してインクリメントをしているのでEAXがiに相当すると判断できます。そして同ブロックの最後ではcmpがあり、iとECXを比較しています。Cのプログラムを見るに、iと比較されうるのはnだけです。よって、ECXがnに相当すると判断できます。

以上より、このブロックは、次のブロックの先頭で行われる格納のためにarray[0]の内容(”0”)をTDXに入れ、forループ内で使うESI(実質n)に引数n(ECX)を格納し、i(EAX)を初期値0でセットするブロックであることが分かります。

ブロック4

まず1行目は汎用レジスタEDXの値をarray[i]の内容を書き込む命令がきています。MOVの命令の内opcode 89の意味は次の通りです。

88 /r MOV r/m8,r8 2/2 Move byte register to r/m byte
89 /r MOV r/m16,r16 2/2 Move word register to r/m word
89 /r MOV r/m32,r32 2/2 Move dword register to r/m dword

次にiをインクリメントし、EDXにnを足しています。

ブロック5

flagを見て、ジャンプ可能であるかを判定します。成立時はブロック4にジャンプします。(後の考察で提示するフローグラフで分かるように、)直前のcmp、つまりブロック4の最後の命令の副作用でflagが変わるのでどこかのタイミング(言ってしまうとn(ECX)とi(EAX)が等しくなるとき←forループの終了条件はi>=n)でジャンプします。

ブロック6

一部の汎用レジスタの内容を荒らしてしまったので、ブロック1で退避した値を呼び戻して何もなかったことにします(呼び出し規約?)。

考察:フローグラフの作成

せっかくなのでフローグラフもどきを作成してみました。添字だけ表記します

1→2→3→4→5→6, 2→6, 5→4

1→2→3→4→5→6の主流があり、2から6・5から4に伸びる矢印あるという意味です。

考察:おや?かけ算がなくなっているな?

よく見ると掛け算に相当する命令がなく、足し算だけが散見されます。掛け算の命令は足し算に比べ計算コストが高いと聞いたことがあります。それを最適化の名目で足し算にしたのかもしれません。確かに今回の場合、かけ算の部分は足し算で書き換え可能です。

考察:最適化されたコードをC言語で表現してみた

このi386のコードをC言語で書き直してみます。まず着目すべきはforループの部分が前判定から後判定になっている点です(nとiのcmpがブロック4の終わりにある)。次に、かけ算が足し算で書きなおされている点です。この場合、足し算の結果を蓄積しないといけませんが、前回配列に書き込んだ時の値EDXで事足ります。つまり、 次に配列に書き込む値=EDX+n (ESI) となります。

以上の分析により、コンパイル結果をC言語で次のように書き下すことができます。

void function(int *array, int n) { //B1 ~ B2

  // if(n == 0) return; ←謎のtest命令

  // B3
  int i = 0;
  int edx = 0;

  // B4 ~ B5
  for(; i \< n; i++) {
    array[i] = edx;
    edx += n;
  }

  // B6
  /* return */
}

実行結果は

--- content of array ---  
 [0] 0  
 [1] 4  
 [2] 8  
 [3] 12

考察:謎のtest命令

a:   85 c9                test   %ecx,%ecx

で、同じ値同士をビット積演算(test)しようとしています。今回の場合はECXが0でなければ結果が1になます。testはFLAGを変更するみたいですが…(CF ← 0;OF ← 0;)

TEST computes the bit-wise logical AND of its two operands. Each bit of the result is 1 if both of the corresponding bits of the operands are 1; otherwise, each bit is 0. The result of the operation is discarded and only the flags are modified.

ブロック2からブロック6にジャンプ(jle 26)する場合はどのような場合なのでしょうか?jleの仕様を確認すると、

0F 8E cw/cd JLE rel16/32 7+m,3 Jump near if less or equal (ZF=1 and SF≠OF)

とあります。甘い検討ですが、とりあえず直前の演算(test)で0になってゼロフラグが立てば(ZF=1)ブロック6にジャンプしそうです。つまり、ジャンプの成立条件は n = 0 っぽいです。

(3)

フロントエンド

ソースコードはbisonやlexなどのパーサーによって字句解析・構文解析されます。処理系によってはこの部分を自力で書いたり、LLVMを使ってここを省略(?) したりするものもあるようです。 中間コードを生成する前に、変数、関数名、関数の引数についてのテーブル(シンボルテーブル)が作成されます(実装によるかも;コンパイラの講義ではシンボルテーブルを利用したPascalコンパイラを作成しました)。

バックエンド(1) 最適化

中間コードを生成する前に抽象構文木(AST)を生成します。抽象構文木構文木(文法)と中間コードの中間の存在で、解析木からコード生成に必要な部分のみを残して変形したものです。抽象構文木は最適化及び目的コード生成の処理に都合の良い形であることから、処理に重点を置き、高品質のコードを生成するコンパイラの中間コードとして用いられます。 最適化は、例えば小さいものだと、そもそも不要なコードを削除したり、アグレッシブなものだと総和を計算するforループを公式に置き換えてしまったりするようなものがあるらしいです。最適化では数に限りのあるレジスタ複数の変数にどう割り当てるのかの問題にも取り組みます。 (*は「コンパイラの理論と作成技法」(大山口通夫・三橋一郎著)より引用)

バックエンド(2) アセンブリコード生成

呼出規約に関わるコードの生成では、サブルーチンを呼び出した際、レジスタをどう退避させたり、引数を(スタックから)どう受け取ったり、戻り番地をどこに控えるかなどが考慮されます。呼び出し規約はcdeclやfastcallなどがあるようです。CやC++などでは中間コードは最終的にアセンブラに落とし込まれますが、どの命令が使えるかがコンパイルのターゲット環境(CPU)によって決まっています。その環境で使える命令のひとまとめを命令セットと言い、x86, x64, ARM, MIPSなどがあります。

(4) (参考:パタヘネ)

まず命令をメモリからフェッチ(取得)しデコード(解釈)します。デコードされた命令ではオペコード(命令の意味)とオペランド(命令で使うデータ)を解釈可能となります。 RISCでは、命令パイプラインは次の5つのフェーズに分かれます。

  1. IF:命令フェチ
  2. ID:命令デコードとレジスタ・フェッチ
  3. EX:命令実行/アドレス生成
  4. MEM:データ・メモリ・アクセス
  5. WB:書き込み

次のように、複数の命令パイプラインを用意し、各フェーズが重ならないように配置すれば命令を並列に実行できるようになります。

IF   ID   EX   MEM  WB         
     IF   ID   EX   MEM  WB
          IF   ID   EX   MEM  WB 

ただし、前の命令でレジスタの内容が書き換わり、更新したレジスタの内容を読み取る命令がある場合は、データハザードが起こり、後続の命令が待たされねばならない場合があります。

命令は何種類もありますが、大抵の場合はいくつかの回路は同じ回路を共有します(例にもれずIntelのCPUはこの辺がとても複雑な模様。例えば整数と浮動小数点とではそもそも回路のブロック自体が違うとか…←可能ならどこかの場面でこの辺を整理した情報がほしいです)。マルチプレクサを駆使しながら制御信号によって信号が回路の必要な部分に流れるようにスイッチします。

(5)

回答なし


後編へ続く

katc.hateblo.jp