大熱血! アセンブラ入門

概 要

アセンブラは「難しい」というイメージがあり、敷居が高い言語です。しかし、アセンブラがわかるとCPUのアーキテクチャや設計思想、高速化や省メモリのための工夫がわかり、プログラマとして大きく成長できます。本書は、アセンブラ本なのに気負わずに軽く読めると評判になった前著『熱血!アセンブラ入門』を加筆し、50種類に及ぶアセンブラの読み方を解説しました。あなたも、アセンブラいじりの面白さをぜひ感じてください。

著者 坂井弘亮
価格 本体4600円(税別)
ISBN 978-4-7980-5154-3
発売日 2017/9/15
判型 B5変
ページ数 1164
CD/DVD
ダウンロード
表紙イメージ
購入 アマゾンで購入する
楽天で購入する

※リンク先によっては、販売ページが用意されていないことがあります。あらかじめご了承ください。

新しいウィンドウで開く 書籍購入のご案内

サポート

サポート情報は以下からご参照下さい。

サポート情報へのリンク

目次

Part 1 基礎編:まずはアセンブラに慣れよう

01 まずは基本操作を覚えて,アセンブラに慣れよう!

01.01 アセンブラを見てみよう

01.01.01 3つの関数だけを見てみる

01.01.02 まずは,目的を意識して読んでみよう

01.01.03 アセンブラの読み方を知ろう

01.01.04 「機械語」と「ニーモニック」

01.01.05 固定長の命令

01.01.06 リターン命令

01.01.07 「アセンブラ」と「アセンブリ言語」

01.01.08 レジスタの使われかたを推測しよう

01.02 バイナリエディタで確認しよう

01.02.01 バイナリエディタで見てみる

01.02.02 機械語コードの書き換え

01.02.03 再度,逆アセンブルする

01.03 まとめ

02 PowerPCの数値の扱いかたを見てみよう

02.01 まずは,サイズを見てみよう ?? PowerPCのビット数を知る ??

02.01.01 int型のサイズ

02.01.02 ポインタ型のサイズ

02.01.03 short型とlong型のサイズ

02.02 値の代入を見てみよう ?? PowerPCの代入の方法 ??

02.02.01 2バイト値の代入

02.02.02 ひとつの疑問

02.02.03 4バイト値の代入

02.02.04 2回に分けて代入する

02.03 引数の渡しかた

02.03.01 第1引数と第2引数を渡す

02.03.02 第1引数と戻り値のレジスタは同じ

02.04 まとめ

03 MIPSのアセンブラを見てみよう

03.01 MIPSって何?

03.02 アセンブラを見てみる

03.02.01 アセンブラのファイル

03.02.02 MIPSのアセンブラ

03.03 関数からの返りかた

03.03.01 ジャンプ命令

03.03.02 命令の順序がひっくり返っている?

03.03.03 MIPSは遅延スロットを持つ

03.03.04 ゼロの代入が特別扱いになっている?

03.03.05 MIPSはゼロレジスタを持つ

03.04 数値の扱いかた

03.04.01 MIPSは32ビットCPU

03.04.02 大きな値は2回に分けて代入する

03.04.03 引数の渡しかた

03.04.04 MIPSは第1引数と戻り値のレジスタが異なる

03.05 レジスタ番号

03.05.01 レジスタ番号を見てみる

03.05.02 特殊レジスタの扱い

03.06 まとめ

04 演算処理を見てみよう

04.01 レジスタ間の演算

04.01.01 add命令のオペランド

04.01.02 オペランドの順番を推測する

04.02 オペランドの指定方法

04.02.01 add命令を並べて比較してみる

04.02.02 オペランドのフォーマットを推測する

04.02.03 第2,第3オペランドのフォーマット

04.03 バイナリエディタで確認してみる

04.03.01 書き換え位置の計算方法

04.03.02 アドレスの計算方法

04.04 レジスタと即値の演算

04.04.01 レジスタと即値の演算

04.04.02 後半2バイトが即値のフィールドになっている

04.04.03 or命令による論理演算

04.04.04 MIPSではどうなっているのか?

04.05 まとめ

05 その他のCPUを見てみる ~RISC編

05.01 SHを見てみよう

05.01.01 SHの機械語コードは2バイト長

05.01.02 2バイト命令で,どうやって即値を扱うのか?

05.01.03 絶対アドレスと相対アドレス

05.01.04 SHはPC相対のアドレッシングモードを持つ

05.01.05 SHのPC相対はややこしい

05.01.06 4バイトの定数値は?

05.01.07 オフセット値の範囲外のアドレスはどうなるのか?

05.01.08 1命令で代入できる場合もある

05.01.09 引数の扱いはどうなっているのか

05.01.10 2オペランド方式と3オペランド方式

05.02 ARMを見てみよう

05.02.01 ARMは条件コードを持っている

05.02.02 ARMはリトルエンディアン

05.02.03 ARMのリターン命令

05.02.04 多バイト値の扱いに特徴がある

05.02.05 ARMはプログラムカウンタが2つ先の命令を指す

05.02.06 ゼロ付近の値は1命令で生成できる

05.02.07 複雑な値は複数命令で生成する

05.02.08 引数の渡しかたはPowerPCと似ている

05.02.09 加算処理は3オペランド方式で行なわれる

05.03 まとめ

06 命令のエイリアス

06.01 PowerPCのli命令の場合

06.01.01 li命令の機械語コードを見てみる

06.01.02 li命令とaddi命令はオペコードが同じになっている

06.01.03 li命令はゼロ指定のaddi命令になっている

06.01.04 アセンブラのエイリアス

06.02 PowerPCのmr命令の場合

06.02.01 mr命令の機械語コード

06.02.02 mr命令はor命令のエイリアスになっている

06.03 MIPSのli命令の場合

06.03.01 MIPSも「li」という命令を持っている

06.03.02 レジスタ番号を出力させてみる

06.03.03 レジスタを指定している部分を探す

06.03.04 li命令はaddiu命令のエイリアスになっている

06.04 MIPSのmove命令の場合

06.04.01 move命令はaddu命令のエイリアス

06.04.02 並べて比較してみる

06.04.03 2箇所のどちらなのかを調べる

06.04.04 ゼロレジスタが指定されている?

06.05 nop命令もエイリアスになっている

06.05.01 nop命令もエイリアスになっている

06.05.02 sll命令とは何か?

06.05.03 sll命令はシフト演算を行う命令

06.05.04 PowerPCではnopはori命令になっている

06.06 まとめ

07 メモリ操作

07.01 PowerPCのメモリ操作

07.01.01 ロードとストア

07.01.02 構造体のメンバのアクセス

07.01.03 アドレッシングモード

07.01.04 静的変数のアドレスの格納

07.01.05 静的変数へのアクセス

07.02 MIPSでのメモリ操作

07.02.01 ロード/ストアはPowerPCと似ている

07.02.02 グローバルポインタ

07.03 ARMでのメモリ操作

07.03.01 ARMでもディスプレースメント付きレジスタ間接が利用できる

07.03.02 PC相対によりアドレスを設定する

07.04 まとめ

08 の他のCPUを見てみる ~CISC編

08.01 RISCとCISC

08.01.01 RISCは高速化のためのアーキテクチャ

08.01.02 CISCはメモリが低速だった時代のアーキテクチャ

08.01.03 CISCはアセンブラプログラマのためのアーキテクチャ

08.01.04 RISCはパイプラインを意識したアーキテクチャ

08.01.05 RISCとCISCの区別

08.01.06 命令セットでRISCとCISCを区別する

08.01.07 CISCライクな命令セットは,組込み分野に向いている

08.01.08 「RISC」「CISC」と,もうひとつの分類「マイコン」

08.02 H8

08.02.01 H8は可変長命令

08.02.02 H8は16ビットCPU

08.02.03 H8は16ビットCPUなのに,32ビット値をどうやって扱うのか

08.02.04 引数の渡しかた

08.02.05 加算命令は2オペランドになっている

08.02.06 レジスタの個数は?

08.02.07 H8は省メモリサイズを意識したアーキテクチャ

08.02.08 メモリ操作を見てみる

08.02.09 H8では,値の移動はすべてmov命令で行う

08.02.10 ディスプレースメント付きレジスタ間接も使える

08.02.11 アドレスは16ビットになっている

08.03 i386

08.03.01 i386は,もっと極端な可変長命令になっている

08.03.02 多バイト値をそのまま扱うことができる

08.03.03 引数はスタック経由で渡される

08.03.04 メモリ上の値を直接加算することができる

08.03.05 インクリメントするだけの専用命令がある

08.03.06 6バイトや7バイトの命令もある

08.03.07 直接アドレスによるメモリアクセスも行なえる

08.04 まとめ

09 スタックの使いかた

09.01 スタックとは何か?

09.02 MIPSのスタック操作

09.02.01 volatileで最適化を抑止してコンパイルする

09.02.02 関数の先頭ではスタックポインタの操作が行われている

09.02.03 スタックフレーム

09.02.04 スタック上の値を利用する

09.02.05 最適化をしないとどうなるか?

09.02.06 関数の処理内容はブロック単位に分けることができる

09.02.07 MIPSのスタックポインタの実体は何か?

09.02.08 ABIはバイナリの規約

09.03 PowerPCのスタック操作

09.03.01 PowerPCではr1レジスタがスタックポインタになっている

09.03.02 PowerPCのスタックフレームは解析しやすい構造になっている

09.03.03 スタック操作はアトミックに行う必要がある

09.04 ARM,SH,H8,i386のスタック操作も見てみよう

09.04.01 ARMはMIPSやPowerPCと似ているようだ

09.04.02 SHも似ているようだ

09.04.03 H8もだいたい同じなようだ

09.04.04 i386は1命令で自動変数を用意している

09.04.05 スタックの一般的な共通事項

09.05 まとめ

10 関数呼び出し

10.01 MIPSの関数呼び出し

10.01.01 MIPSの関数呼び出しはjal命令で行われる

10.01.02 関数呼び出し時に,レジスタをスタックに保存している

10.01.03 raレジスタには戻り先のアドレスが格納されている

10.01.04 raレジスタはハードウェア的に特別なものになっている

10.02 PowerPCの関数呼び出し

10.02.01 PowerPCとMIPSの関数呼び出し手順は似ている

10.02.02 PowerPCはリンクレジスタを持っている

10.02.03 特殊レジスタに対するMIPSとPowerPCの考え方の違い

10.02.04 PowerPCのリンクレジスタの保存先は,ひとつ前のスタックフレームになっている

10.02.05 RISC系CPUはレジスタベースで動作している

10.03 ARMの関数呼び出し

10.03.01 ARMは複数レジスタをスタックに保存する命令がある

10.03.02 ARMは特殊レジスタを汎用レジスタとして持っている

10.03.03 ARMのスタック構造を考える

10.03.04 ポインタ経由での関数呼び出し

10.03.05 ARMの命令セットは,あまりRISCっぽくないように思える

10.03.06 フレームポインタとは何か?

10.03.07 フレームポインタを有効化してみる

10.04 SHの関数呼び出し

10.04.01 SHは「プリデクリメントレジスタ間接」というアドレッシングモードを持つ

10.04.02 SHではポインタ経由で関数呼び出しが行われる

10.04.03 関数呼び出しのアドレス指定方法

10.04.04 SHは多ビットのオペランドを取れない

10.05 CISC系CPUの関数呼び出し

10.05.01 H8では,戻り先アドレスはスタックに保存される

10.05.02 i386では引数もスタック経由で渡される

10.06 まとめ

11 条件分岐

11.01 「ジャンプ」と「分岐」

11.02 H8の条件分岐

11.02.01 「cmp」が比較命令のようだ

11.02.02 分岐命令は頭に「b」がつく

11.02.03 比較結果の保存先

11.02.04 ループ処理はどうなっているのか?

11.02.05 ループの継続の判断も,条件分岐によって行なわれている

11.02.06 ループの先頭でも条件分岐を行なっている

11.03 PowerPCの条件分岐

11.03.01 「cmpw」という比較命令があるようだ

11.03.02 比較結果はCRレジスタに格納される

11.04 i386の条件分岐

11.04.01 i386は「ブランチ」でなく「ジャンプ」と呼ぶようだ

11.04.02 「分岐(ブランチ)」と「ジャンプ」

11.05 SHの条件分岐

11.05.01 SHでは,比較命令のほうで分岐条件を指定する

11.05.02 条件分岐では真か偽かのみを見て判断している

11.05.03 なぜフラグを1本にしぼっているのか

11.06 MIPSの条件分岐

11.06.01 比較と分岐を1命令で行っている

11.07 ARMの条件分岐

11.07.01 そもそも条件分岐を行っていない

11.07.02 では,条件分岐したい場合にはどうするのか?

11.08 まとめ

12 複雑な処理を読んでみよう

12.01 MIPSの場合

12.01.01 関数をブロック分けして読みとく

12.01.02 関数の先頭と末尾に着目する

12.01.03 関数のプロローグとエピローグ

12.01.04 関数の処理の本体

12.01.05 ブロック化してみる

12.01.06 もう少し複雑な処理も見てみよう

12.01.07 保存されるレジスタと,保存されないレジスタ

12.01.08 なぜs0レジスタが利用されるのか?

12.02 PowerPCの場合

12.02.01 やはりMIPSとだいたい似ているようだ

12.02.02 関数内部で行なわれる処理

12.03 ARMとSHの場合

12.03.01 ARMもほとんど同じようだ

12.03.02 そしてSHも,ほとんど同じようだ

12.04 H8とi386の場合

12.04.01 H8やi386では,戻り先アドレスを退避する必要が無い

12.04.02 不揮発性レジスタの扱いはMIPSなどと同じようだ

12.05 まとめ

Part 2 応用編:さまざまなCPUのアセンブラを見てみよう

13 他のRISC系CPUを見てみよう

13.01 SPARC

13.01.01 SPARCはコテコテのRISCプロセッサのようだ

13.01.02 レジスタ・ウィンドウとは何か?

13.01.03 SPARCのレジスタ・ウィンドウの仕組み

13.01.04 レジスタ・ウィンドウと関数呼び出し

13.01.05 restore命令でのレジスタ指定

13.01.06 リーフ関数ではレジスタ・ウィンドウの操作は不要になる

13.01.07 32ビット値の複数回での代入は,異なるビット数で行われる

13.01.08 レジスタ指定のフィールドが分散しているようだ

13.01.09 まとめ

13.02 PA-RISC

13.02.01 遅延スロットの有無を切替えられる

13.02.02 符号ビットが最下位にある

13.02.03 即値が16ビットずつになっていない

13.02.04 引数を渡すレジスタが逆順になっている

13.02.05 静的変数へのアクセスには,グローバルポインタが利用される

13.02.06 スタックは上方伸長のようだ

13.02.07 RISCでディスプレースメント付きレジスタ間接が多い理由

13.02.08 まとめ

14 64ビット・プロセッサも見てみよう

14.01 Alpha

14.01.01 Alphaは64ビット・アーキテクチャ

14.01.02 リトルエンディアンになっているようだ

14.01.03 ひとつ大きな値が格納されている?

14.01.04 シフトされた値が代入されている

14.01.05 レジスタ名がMIPSと似ているようだ

14.01.06 レジスタ番号を推測してみる

14.01.07 まとめ

14.02 その他の64ビット・プロセッサ

14.02.01 PowerPC(64ビット)

14.02.02 MIPS(64ビット)

14.02.03 SH(64ビット)

14.02.04 x86-64

14.02.05 IA-64

14.02.06 MMIX

14.02.07 まとめ

15 組込み向け32ビットCPUのアセンブラを見てみよう

15.01 M32R

15.01.01 2命令が1セットで扱われている?

15.01.02 4バイト命令も使われているようだ

15.01.03 ゼロ付近の値は効率的に代入することができる

15.01.04 演算は2オペランド形式になっている

15.01.05 メモリ操作はRISCっぽい感じのようだ

15.01.06 24ビットアドレスは1命令で扱える

15.01.07 関数の先頭は4バイトアラインメントされている必要がある?

15.01.08 まとめ

15.02 V850

15.02.01 即値が機械語コードの先頭にある?

15.02.02 4バイト値は符号拡張を考慮して代入する

15.02.03 レジスタの扱いかたを見てみる

15.02.04 ディスプレースメント付きレジスタ間接でのアクセスもできる

15.02.05 ディスプレースメントは2の倍数になる

15.02.06 関数呼び出しのために関数が呼び出される?

15.02.07 nop命令がオールゼロになっている

15.02.08 まとめ

15.03 i960

15.03.01 関数の先頭が16バイトアラインメントされている

15.03.02 ごくごくフツーのRISCプロセッサみたい

15.03.03 スタックが上方伸長のようだ

15.03.04 レジスタウィンドウを持っているのか?

15.03.05 まとめ

15.04 MN10300

15.04.01 1バイト命令を持っている

15.04.02 3バイト命令や6バイト命令もあるようだ

15.04.03 第3引数はスタックで渡される

15.04.04 アドレスを扱うレジスタが別にある

15.04.05 代入はすべてmov命令で行なう

15.04.06 まとめ

15.05 FR30

15.05.01 遅延スロットを持つリターンと持たないリターンがある

15.05.02 加算命令は2オペランド形式のようだ

15.05.03 ディスプレースメント付きレジスタ間接が使えないようだ

15.05.04 ディスプレースメントが使えないため,スタック操作が面倒になっている

15.05.05 まとめ

15.06 FR-V

15.06.01 VLIWのため,命令数がそろっている

15.06.02 ゼロレジスタを持っているようだ

15.06.03 グローバルポインタも持っているようだ

15.06.04 まとめ

15.07 Xtensa

15.07.01 .literalというセクションがあるようだ

15.07.02 命令長は2バイトか3バイト固定長?

15.07.03 多バイト定数は.literalからロードする

15.07.04 引数の渡しかたは普通のようだ

15.07.05 メモリアクセスやスタックの使いかたも普通のRISCみたいだ

15.07.06 レジスタウィンドウを持っている?

15.07.07 まとめ

16 マイコンのアセンブラを見てみよう

16.01 AVR

16.01.01 8ビットマイコンだが,int型は16ビットで扱われる

16.01.02 命令によっては使えないレジスタがある

16.01.03 引数もレジスタ2個のペアで渡されている

16.01.04 加算はキャリフラグを利用して行われている

16.01.05 インデックスレジスタを持っている

16.01.06 スタックの使いかたには,だいぶ癖があるようだ

16.01.07 I/O命令が使われている

16.01.08 スタックはエンプティ・スタックになっている

16.01.09 まとめ

16.02 Xstormy16

16.02.01 アドレス幅は16ビットのようだ

16.02.02 4バイト値はレジスタ2個で扱う

16.02.03 引数の扱いは普通の感じのようだ

16.02.04 メモリアクセスも見てみよう

16.02.05 スタックが上方伸長のようだ

16.02.06 まとめ

17 昔ながらのマイコンのアセンブラも見てみよう

17.01 68HC11

17.01.01 8ビットマイコンでは,1バイトでも節約したい

17.01.02 でもint型は32ビットのようだ

17.01.03 引数はスタックで渡しているようだ

17.01.04 アキュームレータ方式になっている

17.01.05 レジスタ交換命令を持っているようだ

17.01.06 加算は桁上がりにキャリを使っている

17.01.07 単なる加算でも,条件分岐が使われることがある

17.01.08 アドレスを直接指定することもできるようだ

17.01.09 スタックの獲得は,スタック退避命令を繰り返すことで行なわれる

17.01.10 メモリをレジスタがわりに利用する方法がある

17.01.11 まとめ

17.02 68000

17.02.01 実質的に,32ビットのアセンブラになっている

17.02.02 4バイトの即値を直接扱える

17.02.03 引数はスタック経由で渡される

17.02.04 メモリ上の値を直接加算することができる

17.02.05 直接アドレスによるロードが行なえる

17.02.06 即値を2つ指定するような命令もある

17.02.07 まとめ

18 CISC系のCPUを見てみよう

18.01 VAX

18.01.01 「ミニコン」とは何か

18.01.02 ゼロクリア専用の命令を持っている

18.01.03 VAXはPDP-11を32ビット拡張したコンピュータ

18.01.04 可変長命令なので,4バイトの即値もそのまま扱える

18.01.05 引数はスタックで渡される

18.01.06 加算命令のオペランドにメモリを指定することができる

18.01.07 メモリ上の値を直接扱える

18.01.08 movl命令がさまざまな種類のオペランドをとっている

18.01.09 静的変数もやはりmovl命令で扱われている

18.01.10 もはや何でもできそうだ

18.01.11 まとめ

18.02 PDP-11

18.02.01 16ビット・ミニコン

18.02.02 4バイト値はレジスタ2個で扱う

18.02.03 アセンブラは8進数表記になっている

18.02.04 gccのバグだろうか

18.02.05 引数はスタック経由で渡される

18.02.06 「インクリメント演算子」の元になった命令がある

18.02.07 2段階のメモリアクセスも1命令でできる

18.02.08 PC相対を探ってみよう

18.02.09 PC相対で即値を表現する.これは美しい!

18.02.10 PDPエンディアンとは?

18.02.11 まとめ

19 メインフレームのアセンブラを見てみよう

19.01 S/390

19.01.01 リターン命令がわからない!

19.01.02 関数のお尻が埋められている?

19.01.03 プログラムカウンタを扱っているようだ

19.01.04 メモリアクセスはふつうの感じのようだ

19.01.05 スタックが大量に獲得されている?

19.01.06 直後の命令を関数コールすることで,プログラムカウンタの値を取得する

19.01.07 マルチプル・ロード/ストア命令によるスタック操作

19.01.08 まとめ

20 その他のアセンブラについても見てみよう

20.01 縮小命令セットを見てみよう

20.01.01 MIPS16

20.01.02 Thumb(ARMの16ビット命令)

20.01.03 縮小命令セットの呼び出しかた

20.01.04 縮小命令セットの効果と影響

20.02 ビット幅を変化させてみる

20.02.01 AVR(8ビットint)

20.02.02 68HC11(16ビットint)

20.02.03 H8/300H

20.02.04 まとめ

20.03 ARM系プロセッサ

20.03.01 StrongARM

20.03.02 XScale

20.03.03 まとめ

20.04 謎のCPUも見てみよう

20.04.01 ARC

20.04.02 CRIS

20.04.03 M・CORE

20.04.04 まとめ

20.05 大学生が作ったCPUを見てみよう

20.05.01 MIST32向けのクロスコンパイラの作成

20.05.02 16ビットの即値は,分割されて格納されている

20.05.03 演算は2オペランド形式のようだ

20.05.04 ディスプレースメント付きレジスタ間接を持っていない?

20.05.05 スタックフレームの外をアクセスしている?

20.05.06 関数呼び出しは,2命令で行なう

20.05.07 アウトオブオーダー実行のために

20.05.08 まとめ

Part 3 番外編:アセンブラの出力環境を構築しよう

21 アセンブラ出力環境の構築方法

21.01 環境構築の準備

21.01.01 本書で利用するツール

21.01.02 やっていること

21.01.03 まずはホストコンパイラが必要

21.01.04 アーキテクチャ

21.01.05 ベース環境

21.01.06 必要スペック(HDD容量)

21.01.07 必要スペック(CPU速度)

21.01.08 PCをどうするか?

21.02 クロスコンパイル環境の構築

21.02.01 前準備

21.02.02 サポートサイトを確認してください

21.02.03 必要なファイルの準備

21.02.04 スクリプト類の展開

21.02.05 アーカイブの展開とパッチ当て

21.02.06 binutilsのビルド

21.02.07 gccのビルド

21.02.08 gdbのビルド

21.02.09 ビルドをまとめて実施するには

21.02.10 アセンブラを出力してみる

21.02.11 シミュレータで実行してみる

21.02.12 newlibを利用する

21.02.13 アンインストールするには

21.03 makeによる処理の詳細

21.03.01 「make」をすると何が起きるのか

21.03.02 「make」は何をしてくれるのか

21.03.03 「make」が便利なところ

21.04 さらにいろいろやってみるには

21.04.01 gccのバージョン4系を利用する

21.04.02 アセンブラの出力方法を変えてみる

21.04.03 新しいアーキテクチャに対応する

21.05 まとめ

22 「Hello World」を動かしてみる

22.01 シミュレータで「Hello World」を実行する

22.01.01 高機能デバッガ「gdb」

22.01.02 シミュレータで「Hello World」を動作させる

22.01.03 printf()を使わないためには何が必要か?

22.01.04 APIを利用せずにHello Worldを書いてみる

22.02 何をすればシミュレータで文字列出力できるのか?

22.02.01 システムコールをシミュレートする

22.02.02 特殊命令を実装する

22.02.03 周辺デバイスのシミュレートも行う

22.02.04 仮想的なデバイスを実装する

22.03 動作のために必要な対応は?

22.03.01 スタートアップも必要

22.03.02 プログラムの終了の方法

22.03.03 どうやって調べるか?

22.03.04 シミュレータ利用のサンプルコード

22.04 まとめ

23 シミュレータ対応の実際

23.01 H8のシミュレータ対応

23.01.01 シミュレータのソースコードを読む

23.01.02 write()の実行場所

23.01.03 引数は関数呼び出しと互換の方法で渡される

23.01.04 _exit()による終了

23.01.05 スタートアップの実装

23.01.06 実行してみる

23.02 SHのシミュレータ対応

23.02.01 SHも,シミュレータのソースコードはそれほど多くない

23.02.02 トラップ命令を利用するようだ

23.02.03 引数を渡すレジスタがひとつずれている

23.02.04 スタートアップを実装して実行してみる

23.03 ARMのシミュレータ対応

23.03.01 ソースコードはそれなりに多い

23.03.02 大規模なソースコードを読むときのコツは?

23.03.03 write()の処理部分

23.03.04 しかし,うまく実行できないようだ

23.03.05 gdbで動作を追ってみる

23.03.06 条件コードの考慮が必要になる

23.04 MIPSのシミュレータ対応

23.04.01 まずはファイル名で判別する

23.04.02 write()の処理箇所を探す

23.04.03 予約命令?

23.04.04 終了とスタートアップ

23.04.05 それでもうまく実行できない

23.04.06 アドレスが不正?

23.04.07 まだうまく動かない!

23.04.08 グローバルポインタの設定が必要

23.04.09 終了処理を見直す

23.05 PowerPCのシミュレータ対応

23.05.01 NetBSDやLinuxをシミュレートしているようだ

23.05.02 引数は関数呼び出しと同じ方法で渡される

23.05.03 エラー処理について考える

23.05.04 エラーの判断とerrnoの設定

23.06 i386

23.06.01 FreeBSDのシステムコール処理を見てみる

23.06.02 「int 0x80」がシステムコールの入口になっている

23.06.03 FreeBSDではスタック経由で引数が渡される

23.06.04 Linuxのシステムコール処理を見てみる

23.06.05 Linuxではレジスタ経由で引数が渡される

23.06.06 FreeBSDとLinuxの,システムコール引数の渡しかたの違い

23.06.07 バイABIな実行形式を作成する

23.06.08 実行してみる

23.07 残りのアーキテクチャを対応する

23.07.01 AVR

23.07.02 CRIS

23.07.03 FR-V

23.07.04 その他のアーキテクチャ

23.08 その他の対応

23.08.01 エラーの返しかた

23.08.02 printf()を使えるようにする

23.08.03 浮動小数演算について

23.09 まとめ

Part 4 発展編:さらにいろいろなアセンブラを見てみよう

24 最適化の結果を見てみよう

24.01 MIPSでの最適化無しの場合

24.01.01 最適化オプションを調整する

24.01.02 引数の使われかたを見てみる

24.01.03 引数をスタック上に保存している

24.01.04 コンパイラの気持になって考える

24.01.05 引数の実体がスタック上にある

24.01.06 最適化とデバッガ対応は排他になる

24.02 最適化の弊害をデバッガで見てみる

24.02.01 MIPS用のgdbを起動する

24.02.02 ステップ実行で処理を進める

24.02.03 引数の値が壊れている

24.02.04 引数の実体がレジスタにある

24.02.05 レジスタの上書きで,引数の値が消滅する

24.03 MIPSでの最適化有りの場合

24.03.01 引数をスタック上に退避しない

24.03.02 関数呼び出しの最適化

24.03.03 関数のインライン展開

24.04 インライン展開の弊害の実験

24.04.01 通常は期待通りにブレークする

24.04.02 インライン展開されると,期待通りにブレークしない

24.05 他にも弊害が出る場合がある

24.05.01 最適化によるコード削除の弊害

24.05.02 最適化によるコード共通化の弊害

24.05.03 命令入れ換えの弊害

24.06 他のアーキテクチャとの比較

24.06.01 PowerPCの場合

24.06.02 -O1では,MIPSと同様の最適化がされている

24.06.03 -O2以上でも,MIPSと同様の最適化がされている

24.07 まとめ

25 gccバージョン4の利用

25.01 gccバージョン4を使うことの利点

25.01.01 追加された機能

25.01.02 アーキテクチャの追加

25.02 gccバージョン4版のアセンブラ出力環境

25.02.01 gcc-4.9.4によるアセンブラのサンプル

25.02.02 gcc-4.9.4をベースとしたアセンブラ出力環境のビルド

26 64ビットのARMを見てみよう

26.01 AArch64

26.01.01 2種類のレジスタ体系がある

26.01.02 シミュレータのソースコードで確認する

26.01.03 オーソドックスなRISCアーキテクチャのようだ

26.01.04 リンクレジスタの扱い

26.01.05 プログラムカウンタが独立している

26.01.06 31番目のレジスタが特殊扱いになっている

26.01.07 スタックポインタとして扱われることもある

26.01.08 2つのレジスタを操作する命令がある

26.01.09 まとめ

27 最近の新しいマイコンを見てみよう

27.01 RX

27.01.01 1バイト命令がある

27.01.02 旧来のマイコン風の可変長の命令セット

27.01.03 引数はレジスタ渡しになっている

27.01.04 割込みでスタックポインタが切り替わる

27.01.05 演算命令は2と3オペランドの混成?

27.01.06 様々なmov命令がある

27.01.07 スタックポインタの復旧とリターンを同時に行っている

27.01.08 レジスタの復旧も同時に行ってしまう命令もある

27.01.09 プログラムカウンタが,実行中の命令を指している?

27.01.10 まとめ

27.02 RL78

27.02.01 これにも1バイト命令がある

27.02.02 レジスタがアドレス上にも配置されている?

27.02.03 16ビット・アーキテクチャのようだ

27.02.04 ROMとRAMのアドレス空間が分離している

27.02.05 引数はスタックで渡される

27.02.06 アキュームレータを持っている?

27.02.07 インクリメント命令がある

27.02.08 8ビット単位でのレジスタアクセスもできる

27.02.09 まとめ

28 特徴のあるCPUのアーキテクチャを見てみよう

28.01 Blackfin

28.01.01 DSPによるディジタル信号処理のアーキテクチャ

28.01.02 C言語ライクなアセンブラ

28.01.03 アセンブラの文法について考える

28.01.04 レジスタは構造体風にアクセスできる

28.01.05 演算もC言語ライクな文法になっている

28.01.06 なぜC言語ライクな文法になっているのか?

28.01.07 ポインタの表記はC言語ライクではない

28.01.08 プリデクリメントとポストインクリメントはC言語ライク

28.01.09 機械語コードのフォーマットも,数式のようになっているのか?

28.01.10 まとめ

28.02 MSP430

28.02.01 超低消費電力マイコン

28.02.02 レジスタクリアの命令がある?

28.02.03 16ビット・アーキテクチャだがポインタは32ビットにできる

28.02.04 4バイトの値には2つのレジスタを使う

28.02.05 引数はレジスタで渡される

28.02.06 インクリメント命令もある?

28.02.07 同じオペコードで,すべてのアドレッシングモードを扱える

28.02.08 特定の定数は,短い命令で扱える

28.02.09 PDP-11に似た定数値の扱いをしている

28.02.10 まとめ

28.03 SPU

28.03.01 メニーコアのためのコア

28.03.02 ベクトル演算 - スーパーコンピュータのための技術

28.03.03 普通の32ビット・アーキテクチャのように見えるが…

28.03.04 VLIWのアーキテクチャのようだ

28.03.05 演算も普通に行われているように見えるが…

28.03.06 ロード/ストアがまとめて行われる

28.03.07 16バイト単位で処理されている

28.03.08 PowerPCと似ている部分もある?

28.03.09 割込みの考慮が無いのだろうか

28.03.10 まとめ

29 FPGA用のIPコアのアセンブラを見てみよう

29.01 MicroBlaze

29.01.01 遅延スロットを持っている

29.01.02 MIPSに似た32ビット・アーキテクチャ

29.01.03 イミディエイト命令を持っている

29.01.04 イミディエイト命令をシミュレータのソースコードで見てみる

29.01.05 やっぱりMIPSに似ているようだ

29.01.06 まとめ

29.02 Nios II

29.02.01 ゼロレジスタを持っている

29.02.02 32ビットRISCアーキテクチャのようだ

29.02.03 回路規模の削減のための工夫だろうか

29.02.04 MIPSと似た引数渡し

29.02.05 メモリアクセスもMIPSと似ている

29.02.06 グローバルポインタを持っている

29.02.07 関数呼び出しも,やはりMIPSと似ている

29.02.08 まとめ

30 gccが対応していないアーキテクチャを見てみよう

30.01 Z80

30.01.01 sdccとは

30.01.02 1バイト命令を持っている

30.01.03 int型は16ビットになっている

30.01.04 32ビット値は2つのレジスタで表現する

30.01.05 引数はスタック渡しになっている

30.01.06 ロードは8ビット単位で行われる

30.01.07 演算も8ビット単位で行われる

30.01.08 アキュームレータ方式になっている

30.01.09 メモリ上の値を直接演算できる

30.01.10 スタックをベースとしたアーキテクチャになっている

30.01.11 まとめ

30.02 6502

30.02.01 cc65を利用する

30.02.02 やはり1バイト命令を持っている

30.02.03 8ビット・レジスタの組合せで16ビット値を表す

30.02.04 int型は2バイトになっている

30.02.05 謎の格納先

30.02.06 エミュレータ「vice」のソースコードを読む

30.02.07 ゼロページを活用している

30.02.08 引数はスタック経由で渡される

30.02.09 スタックの構成の大きな謎

30.02.10 デュアル・スタックになっている?

30.02.11 引数渡し用の独自スタックを持っている

30.02.12 変則的な独自スタックの構成

30.02.13 自動変数も独自スタックに配置される

30.02.14 サービス関数任せのアセンブラ

30.02.15 キャリフラグ無しの加算命令を持っていない

30.02.16 まとめ

Part 5 熱血編:アセンブラを活用しよう

31 シミュレータの改造

31.01 シミュレータの内部構造を見る

31.01.01 ソースコードの展開

31.01.02 メインループを探してみる

31.01.03 シミュレータ用語

31.01.04 各命令の処理

31.02 シミュレータのシステムコール処理

31.02.01 シミュレータは2種類に大別される

31.02.02 2種類のシミュレータの大きな違い

31.02.03 シミュレータのシステムコール処理を探してみる

31.03 シミュレータを改造する

31.03.01 「カウンタ命令」の仕様

31.03.02 修正を加えるファイル

31.03.03 ファイルの修正に対する差分の表現方法

31.03.04 カウンタ命令を追加する

31.03.05 カウンタ命令を呼び出す関数を追加する

31.03.06 カウンタ命令の関数の呼び出しを追加する

31.03.07 gdbとサンプルプログラムのビルド

31.03.08 改造シミュレータで実行する

31.04 まとめ

32 バッファオーバーフロー脆弱性の検証

32.01 検証における注意(モラルと法律)

32.02 バッファオーバーフロー脆弱性の原理

32.02.01 戻り先アドレスを書き換える

32.02.02 任意のコードを実行する

32.03 バッファオーバーフロー脆弱性の実験用サンプル

32.03.01 サンプルの概要

32.03.02 ビルドの方法

32.04 サンプルプログラムを動作させる

32.04.01 ローカルで動作させる

32.04.02 ネットワーク経由で動作させる

32.04.03 ネットワーク経由で検証する際の注意

32.04.04 異なる環境からの検証

32.05 脆弱性を解析する

32.05.01 脆弱性の場所

32.05.02 静的解析

32.05.03 動的解析

32.05.04 ユーザチェックの解析

32.05.05 ユーザチェックのすり抜けの可能性

32.06 脆弱性を検証する

32.06.01 ネットワーク経由で検証する場合

32.06.02 検証コードの作成

32.06.03 ユーザチェックのすり抜けの検証

32.07 パスワードチェックのすり抜け

32.07.01 パスワードチェックの解析

32.07.02 パスワードチェックのすり抜けの検証

32.08 さらに変数を上書きする

32.08.01 実行コマンドの変更の可能性

32.08.02 lsコマンドを実行するために

32.08.03 lsコマンドの実行の検証

32.09 指定した処理へのジャンプ

32.09.01 戻り先アドレスの書き換え

32.09.02 指定した関数の呼び出しの検証

32.10 シェルを起動する

32.10.01 関数に任意の引数を渡す

32.10.02 シェルの起動の検証

32.11 さらなる攻撃の可能性

32.11.01 スーパーユーザでのシェルの起動

32.11.02 怪しいログを残さない

32.11.03 バックドアを開く

32.12 まとめ

33 多種アーキテクチャでの脆弱性検証

33.01 脆弱性のあるプログラムのサンプル

33.01.01 必要なファイルの準備

33.01.02 サンプルプログラムの内容

33.01.03 脆弱性の内容

33.02 シミュレータで動作させる

33.02.01 ローカルで実行する

33.02.02 ネットワーク経由で検証したい場合

33.02.03 バッファオーバーフローを発生させる

33.03 プログラムの動作を解析する

33.03.01 デバッガ上で動作させる

33.03.02 gdbの操作方法

33.03.03 スタックの構成を調べる

33.03.04 戻り先アドレスの破壊

33.04 攻撃の検証

33.04.01 検証コードを作成する

33.04.02 入力バッファの上書きデータ

33.04.03 注入する機械語コード

33.05 脆弱性の検証をしてみる

33.05.01 任意のファイルの内容の読み出し

33.05.02 ネットワーク経由での検証

33.06 まとめ

34 コンパイラの機能による攻撃検知

34.01 カナリアとは何か

34.02 カナリアの実装を見る

34.02.01 サンプルプログラムの準備

34.02.02 カナリアが無効の場合

34.02.03 カナリアを有効化する

34.02.04 必要な変数と関数をダミーで追加する

34.02.05 カナリアの処理を見る

34.02.06 カナリア値の一致のチェック

34.03 カナリアによる攻撃検知の実験

34.03.01 必要な変数と関数を実装する

34.03.02 カナリア有効で動作させてみる

34.03.03 攻撃を検出する

34.03.04 カナリアをすり抜ける

34.04 乱数命令でカナリア値を設定する

34.04.01 シミュレータに乱数命令を追加する

34.04.02 乱数命令でカナリア値を設定する

34.04.03 乱数によるカナリアの動作を確認する

34.05 まとめ

35 シミュレータでの攻撃検知

35.01 シミュレータで攻撃を検知する

35.01.01 攻撃を検知する方法の3つの案

35.01.02 シミュレータの改造

35.02 CPUへの機能追加で検知する

35.02.01 ハードウェア・カナリア

35.02.02 シミュレータのCPU部分への改造

35.03 OSカーネルへの機能追加で検知する

35.03.01 入力データを監視する

35.03.02 シミュレータのOSカーネル部分への改造

35.04 CPUとOSカーネルの協調動作で検知する

35.04.01 攻撃コードの特徴を考える

35.04.02 シミュレータのCPU部分への改造

35.04.03 シミュレータのOSカーネル部分への改造

35.05 シミュレータでの攻撃検知の実験

35.05.01 ハードウェア・カナリアの検証

35.05.02 検証コードの注入

35.06 必要なものは何か

35.06.01 複数レイヤー間での連携と協調動作

35.07 まとめ

PR

秀和システム