ぽんこつメモ

https://github.com/kanorimon

12ステップで作る組込みOS入門:8thステップ

8章のコードの実行時にreadyque,*current,TCB(kz_thread),スタック(thread_stack)がどのように変化しているのかを追いました。
なお、図中のアドレスは固定ではないので、実行ごとに変わります。
f:id:uzuramon:20170622161626p:plain

12ステップで作る組込みOS入門:1stステップ

準備したもの

開発環境の準備

  • シリアルポートの準備

    • USB-シリアル変換ケーブルのドライバをインストー

    • バイスマネージャでCOMポート番号を確認

    • COMポート番号はデバイスマネージャから変更することができる

      • 変更した場合は、USBケーブルを抜き差ししておかないとh8writeでopen errorが起きる
  • クロス・コンパイラの準備

  • フラッシュROM書き込みツールの準備

    • H8マイコンボードの付属CD-ROMに入っているh8writeをコピー
  • 端末エミュレータの準備

Hello Worldソースコードを書いてビルド

フラッシュROMへの書き込み

  • ディップスイッチをフラッシュROM書き込みモードに設定

  • H8/3069Fとシリアルポートを接続

  • 電源ケーブルを接続(接続時点で電源ON)

  • make write

    • MakefileのH8WRITE_SERDEVをCOMポート番号(com1,com2,com3など)に修正

    • 複数回make writeを実行すると、Can not to set line speed and put Query mode.でエラーになるので、make writeでフラッシュROMの上書きをする場合は電源ケーブルを抜き差し(電源OFF→ON)する

実行

  • 電源ケーブルを外す(外した時点で電源OFF)

  • ディップスイッチをモード5に設定

  • TeraTermをシリアルポートを接続先にして実行

  • 電源ケーブルを接続(接続時点で電源ON)

2017年はアイナナ年!

アセンブラ短歌を詠んだので、解説を書きます。

68 31 37 21 0a
54 5f b2 21 b0 48 57
20 17 01 07 59
6a 04 5a 89 d0 6a 01
5b cd 80 58 31 c0 c3
push   $0xa213731

push   %esp
pop    %edi
mov    $0x21,%dl
mov    $0x48,%al
push   %edi

and    %dl,(%edi)
add    %eax,(%edi)
pop    %ecx

push   $0x4
pop    %edx
mov    %edx,%eax
push   $0x1

pop    %ebx
int    $0x80
pop    %eax
xor    %eax,%eax
ret
  • アイナナ年なので、17という数字にこだわってみました
  • 2017(年)01(月)07(日)という数字に対応するコードを入れました
  • 20 17 : and %dl,(%edi)
  • 01 07 : add %eax,(%edi)
  • "17!"という文字列を、"20 17 : and %dl,(%edi)"、"01 07 : add %eax,(%edi)"を使って、"i7!"に更新しています
  • pushとpopで韻を踏んで、アイドルっぽさを演出しました
  • 二階堂大和さん推しです

以上です。

年始のご挨拶のアセンブラ短歌

アセンブラ短歌を詠んだので、解説を書きます。

53 6a 02 0f 31
68 30 0a 31 0a 89 e1
83 e0 02 01 c1
5b 5b 6a 02 5a 6a 04
58 cd 80 31 c0 5b c3
push %ebx
push $2
rdtsc

push $('0'|'\n'<<8|'1'<<16|'\n'<<24)
mov %esp,%ecx

and $2,%eax
add %eax,%ecx

pop %ebx
pop %ebx
push $2
pop %edx
push $4

pop %eax
int $0x80
xor %eax,%eax
pop %ebx
ret
  • タイムスタンプカウンタの1bit目を使って、0or1が(体感では)ランダムに出力されるおみくじ仕様
  • 0bit目ではなく1bit目を使うことで、条件分岐でアドレスを2ずらすのをandとaddで書けるようにした

以上です。

季節のアセンブラ短歌(クリスマス)

アセンブラ短歌を詠んだので、解説を書きます。

68 45 76 65 21
68 58 6d 61 73 89 e1
6a 01 6a 02 5b
6a 02 6a 04 58 5a 5b
c1 e2 02 cd 80 01 d4 c3
push $('E'|'v'<<8|'e'<<16|'!'<<24)
push $('X'|'m'<<8|'a'<<16|'s'<<24)
mov  %esp,%ecx

push $1
push $2
pop  %ebx

push $2
push $4
pop  %eax
pop  %edx
pop  %ebx

shl  $2,%edx
int  $0x80
add  %edx,%esp
ret
  • 文字以外の即値には1224だけを使った
  • pop %ebxで韻をふみ、クリスマスのpopな雰囲気を演出した
  • 1字余りで翌日のクリスマスを意識した

以上です。

PDP-11のインタプリタを作った話をする

何のエントリ?

池袋バイナリ勉強会でPDP-11のバイナリをインタプリタ実行するプログラム(以下、インタプリタ)を作った記録です。
間違いや思い込み、より良いやり方があったらご指摘いただけると助かります。
作ったものはkanorimon/pdp11 · GitHubにあります。

誰?

一応動くプログラムが作れる程度の文系SE。

勉強会に参加した発端

パタヘネ読み始めてMIPSで詰み、偶然見つけた池袋バイナリ勉強会へ。

どんな感じでバイナリハックしてたか

  1. 勉強会(だいたい隔週日曜午後)
    • カリキュラムに合わせた課題をもらう
    • 課題や周辺知識を説明してもらう
    • わからない部分を質問しながら課題をもくもく
  2. 自宅
    • わからない部分をメモしながら課題をもくもく
  3. 参考書

もくもくでやってたこと

  1. PDP-11の仕様書とV6本を見ながら、命令とシステムコールを実装する。
  2. インタプリタを実行する。
  3. 期待する結果が出なかった場合、実行ログ(命令実行時に命令・レジスタ・フラグを出力したもの)を出力する。
  4. @7shiさん作成のインタプリタ(7run)の実行ログと見比べ、未実装の箇所や実装のミスを見つける。

バイナリハックのカリキュラム

  1. Brainf*ckのインタプリタ作成
  2. PDP-11の逆アセンブラ作成
  3. PDP-11のインタプリタ作成
  4. UNIX V6のカーネルビルド

詳しくは池袋バイナリ勉強会wiki7shi / ikebin / wiki / Home — Bitbucket)を参照。
次からカリキュラムに沿ってやったことと、わかったことを書いていく。

Brainf*ckのインタプリタ作成

Brainf*ckの以下のコードを読み込んで、標準出力に"HellowWorld"を出力するプログラムを作成した。

++++++++[>+++++++++<-]>.
<+++++[>++++++<-]>-.
<++[>+++<-]>+.
.
+++.
<++++++[>----<-]>.
<++++++[>++++<-]>.
+++.
------.
--------.

わかったこと

  • CPU
    • CPUは0と1(電圧の高低)しか認識できない
  • メモリ
    • メモリ≒byte配列
  • バイナリ

PDP-11の逆アセンブラ作成

以下のアセンブリコンパイルしたPDP-11のバイナリ(a.out)を読み込んで、標準出力に逆アセンブル結果を出力するプログラムを作成した。(単純な逆アセンブラ

mov $1, r0
sys write
hello
6

mov $0, r0
sys exit

.data
hello: <hello\n> 

以下のアセンブリコンパイルしたPDP-11のバイナリ(a.out)を読み込んで、標準出力に逆アセンブル結果を出力するプログラムを作成した。(アドレス指定方式の取り込み)

mov $1, r0
sys write
hello
6

mov $hello, r0
mov $62510, r1
mov r1, (r0)
mov $1, r0
sys write
hello
6

mov $0, r0
sys exit

.data
hello: <hello\n>

わかったこと

PDP-11のインタプリタ作成

以下のアセンブリコンパイルしたPDP-11のバイナリ(a.out)を読み込んで、標準出力に"hello"を出力するプログラムを作成した。(単純なインタプリタ

mov $1, r0
sys write
hello
6

mov $0, r0
sys exit

.data
hello: <hello\n>

以下のアセンブリコンパイルしたPDP-11のバイナリ(a.out)を読み込んで、標準出力に"Hello"を出力するプログラムを作成した。(アドレス指定方式の取り込み)

mov $1, r0
sys write
hello
6

mov $hello, r0
mov $62510, r1
mov r1, (r0)
mov $1, r0
sys write
hello
6

mov $0, r0
sys exit

.data
hello: <hello\n>

以下のソースをコンパイルしたPDP-11のバイナリ(a.out)を読み込んで、結果を標準出力に出力するプログラムを作成した。(各種命令の実装、システムコールの実装)

main(){
    write(1, "hello\n", 6);
}
main(){
    putchar('a');
}
main(){
    printf("hello\n");
}
main(){
    int a;
    a = 1234;
    printf("a=%d\n", a);
}

以下のソースをコンパイルしたPDP-11のバイナリ(a.out)を読み込んで、結果を標準出力に出力するプログラムを作成した。(コマンドライン引数の実装)

main(argc, argv){
    char **argv;
{
    int i;
    for(i = 0; i < argc; i++){
        printf("argv[%d]=%s\n", i, argv[i]);
}

以下のソースをコンパイルしたPDP-11のバイナリ(a.out)を読み込んで、結果を標準出力に出力するプログラムを作成した。(関数呼び出しの実装)

main(){
    printo(012345);
}

printo(v){
    int i;
    putchar(v < 0 ? '1' : '0');
    for(i = 0; i < 5; i++){
        putchar(((v >> 12) & 7) + '0');
    }
}


PDP-11のバイナリ(nm)を読み込んで、標準出力にオブジェクトファイルのシンボルリストを出力するプログラムを作成した。(各種命令の実装、システムコールの実装)

# nm a.out

PDP-11のバイナリ(cc)を読み込んで、Cのソースをコンパイルするプログラムを作成した。(更に命令の種類とシステムコールが増える)

# cc test.c

わかったこと

  • バイナリ
    • 原則として、1命令目から順番に処理される
  • UNIX V6
    • カーネル
    • プロセス
    • ユーザー空間とカーネル空間は異なる
    • プロセスごとに仮想アドレス空間を持ち、MMUがメモリの物理アドレスに変換する
    • 仮想アドレス空間はテキスト/空き領域(マジックナンバ0410の場合)/データ+bss/ヒープ/空き領域/スタックとなっている
    • ファイルはinodeで管理されている
    • ファイル入出力等の基本機能はシステムコールを呼び出すことで実現している
    • 関数呼び出しをする場合は、スタックに引数と戻り先のアドレスを格納してからジャンプする
  • システムコール
    • exit()
    • read()
    • write()
    • open()
    • close()
    • creat()
    • link()
    • unlink()
    • chmod()
    • brk()
    • stat()
    • lseek()
    • getpid()
    • dup()
    • signal()
  • コンパイラ
  • 実装方法
    • ccがライブラリを呼び出す場合、何も対応をしないと/lib,/bin,/tmpを見に行ってしまうので、インタプリタで呼び出したい/lib,/bin,/tmpの場所を指定できるようにする必要がある

UNIX V6のカーネルビルド

UNIX V6のカーネルのソースを読み込んで、コンパイルするプログラムを作成した。

わかったこと

  • システムコール
    • fork()
    • exec()
    • wait()
  • Java
    • Stringの処理はコストがかかるので、できるだけ使わない方が高速
    • インスタンスをnewするとコストがかかるので、できるだけnewせずに使いまわす方が高速

総括

  • できるようになったこと
    • OSが何をやっているのか、なんとなくわかるようになった。
    • コンパイルの手順(コンパイラアセンブラ⇒リンカ)を覚えられた。
    • アセンブリ言語の雰囲気がつかめるようになった。
    • セキュリティ系の本(HACKING本とか)を読めるようになった。
  • まだできないこと
    • アセンブリ言語をすらすら読めるわけではない。
    • 2進数からの直翻訳はできない。(是枝くん@王様達のヴァイキングはすごい)
    • C言語アセンブリの対応はよくわからない。
  • 感じたこと
    • 自作インタプリタのバグを見つけるのは正直しんどかった。まさに苦行。
    • なんとか完成できたのは、@7shiさんをはじめ、要所要所でアドバイスいただいた池袋バイナリ勉強会の方々のおかげです。ありがとうございます。

最後に

バイナリに興味がある方へ

素人でも半年くらいあればなんとかなるので、バイナリ・アセンブラコンパイラ等々に興味がある方はぜひ池袋へどうぞ!

今後の話

コンピュータの仕組みとかパフォーマンスを勉強するのがすごく面白かったので、今年の春から大学生(2回目)してきます。
低レイヤとかセキュリティとかもっと知りたいです。
池袋バイナリ勉強会にはこれからもお世話になります。よろしくお願いします!

JAWS-UG千葉團に行ってきたのです!

誰?

JAWS-UG千葉團

  • JAWS-UGのwebサイトに千葉支部が増えていたので参加してみました。

第一回勉強会メモ

「コスト削減? 拡張性? セキュリティ? 試験にでるかもしれないAWSの話」 @horiuchiさん

 「ここ半年で23支部回ってきて気づいた話、話題の中心」 @yoshidashingoさん

  • cloudpackさんは月額固定料金を日本円の請求書で請求してくれる!
  • AWSカルタ
    • ChefはOpsWorks
    • GitはElastic Beanstalk

JAWS-UGの歴史と最近の私」 @DynaKouさん

「いつ参加するか?いまでしょ!」 @HOKARI_Yutakaさん

  • y=f(x)
    • x=顧客の要求
    • f()=自分のスキル
    • y=提供できるもの

「みんな大好き "全文検索 on AWS" を試してみました」 @maroon1stさん

「保守運用担当からみたAWS」 @czkukさん

  • 保守運用も考えたシステム構築を!
    • OSのEOSL、ミドルウェアのバージョンアップに備えた方針の作成
    • 導入ソフトウェア(バージョン)のバイナリ・ソースを保存
    • フレームワークの仕様等、構築当時の情報を保存
    • ドキュメントの最新化
    • ドキュメント、ソースの構成管理

 「RDS!スケールアップ前のアプリチューニング(ざっくり版)」 @masaru_birdさん

  • slowlogはダメ、ゼッタイ!
    • slowlogを出したままではスケールは難しい
  • 上長には、クラウドだからと言ってDBは簡単にスケールできないことを強調する

 紹介があったイベントのメモ

感想

  • AWSホワイトペーパーはじめて読みました。参考になります。面白いです。
  • AWSカルタ楽しかったです!Redshift札は全力で取りに行きました。
  • エンジニアとして、技術は課題解決のツールである、ということを忘れずにいたいです。
  • 鍵ファイルが見つからない、どの鍵で設定したかわからなくなるはあるある。昨日もそれで1インスタンスターミネートしました。
  • 第二回も楽しみにしてます!懇親会まで行けるように調整する所存です。

*1:AWSサイトでは障害復旧を目的とした Amazon Web Services の使用というタイトルになっている模様です……