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

tatsumack blog

エンジニアによる雑記です

はりぼてOSをNASM・GCCで動かす(Mac OSX)

「30日でできる!OS自作入門」を読んだ。

30日でできる! OS自作入門

30日でできる! OS自作入門

この本で開発する「HariboteOS」は作者の独自ツールを使って動かしているが、GNUのツール群で置き換えてビルドできるようにしてみた。

環境

Mac OSX El Capitan(10.11.2)

NASM(Netwide Assembler)に置き換える

作者独自ツールのNASKをNASMに置き換える。
主要なアセンブラとして、NASMの他にGAS(GNU Assembler)が挙げられるが、GASの構文はNASKと大きく異なるので、NASMで置き換えることにした。
参考: Linux のアセンブラー: GAS と NASM を比較する

下記のページに記載のある通り、置き換えをすればアセンブラできるようになる。
http://hrb.osask.jp/wiki/?tools/nask

対応コミット
Replace nask with nasm · tatsumack/HikariOS@877ec9d · GitHub

GCC

C言語で実装されたファイルも作者の独自ツールを使ってコンパイルされていたので、GCCに置き換えてみた。

GCCのビルド

hrb形式のファイルを作成するためには、リンカスクリプトを作成しリンカに渡す必要があるが、
Mac OSXのデフォルトのリンカ(ld)はリンカスクリプトを受け付けるオプションがないので、クロスコンパイラなGCCをビルドする必要がある。
ビルド手順についてはQiitaにまとめた。
qiita.com

その他にやったことの箇条書き

・nasmの出力形式をwin32からelfに変更
・.hrb形式のリンカスクリプト作成
・naskfunc.nasの関数のシンボル名のprefixの_を削除
・色々とライブラリがないので、自作OS本付属のomake/tolsrc/go_0023s/golibcから静的ライブラリを作成し、リンクする
・__builtin_stdarg_startを__builtin_va_startにrename

対応コミット
Replace gocc with gcc · tatsumack/HikariOS@ab4b5d4 · GitHub

「はじめて読む486」を読んだ

はじめて読む486―32ビットコンピュータをやさしく語る

はじめて読む486―32ビットコンピュータをやさしく語る

世間では機械学習・ディープランニングが盛り上がっている中、低レイヤの勉強がマイブームになっている。
この本はIntel486のアーキテクチャについて解説した本で、1994年に書かれた20年以上も前の本ではあるが、名著だと評判なので読んでみた。
(会社の図書スペースにたまたま置いてあったというのもある)

年齢のせいか、1回読んだ本の内容を忘れることが多くなってきたと感じるので、1回読んだ後に再度読み直して、要点をまとめてみた

1. プロローグ

486の3つの動作モード

486は当時広く普及していた8086(x86アーキテクチャの最初のCPU)との互換性を保ちながら、新しい機能と採用するために3つの動作モードがあった。

  • リアルモード
    • 8086との互換性を保つためのモード
    • MS-DOS(マイクロソフトが開発した8086系CPU向けのOS)用アプリケーションを動かす
  • プロテクトモード
    • メモリ管理やタスク管理などの拡張機能を利用できるモード
  • 仮想8086モード
    • プロテクトモードの恩恵を受けながら8086向けのアプリケーションを動かすモード

32bitサポート

486では32bitサポートされ、16bit CPUの8086よりも大きなデータサイズを扱えるようになった。

  • 16bitCPUの64KBの壁
    • 16bitの限界 = 2^16 bit = 64KB
    • 連続して扱える領域は64KBまでに制限される→配列の最大サイズに影響を与える
  • 16bitCPUの640KBの壁
    • 8086ではアドレスを20bitで表すため、利用できるメモリサイズの限界は1MB
    • 360KBをシステムで利用するので、アプリケーションが使えるのは1MB - 360Kb = 640KB
  • 32bit CBUではより大きなデータサイズ、メモリを扱うことができるようになる(物理的な制限は4GB)

2. 486の履歴書

  • 8086から486までのCPUの発展
    • プロテクトモードは286から導入された
    • 32bitサポートは386から
  • 486DX
  • キャッシュメモリ
    • 486の性能向上に最も寄与している
    • CPUの近くに高速なメモリを置いて、一部のデータをキャッシュすることで高速なメモリアクセスを実現した
    • 高速な分、高価なのでデータサイズは小さい(486では8KB)
    • 書き出しのときにキャッシュだけでなく、本来のメモリにも書き込むライトスルー方式を採用している
    • これに対して、キャッシュに書き込むのとは別のタイミングで本来のメモリに書き込むライトバック方式という方法がある
    • ライトバック方式は書き込みの速度を上げることができるが、データの一貫性を保つのが難しい
  • 486SX
    • 486DXの廉価版
    • 実態は486DXと全く一緒で浮動小数点演算機能を無効にしたもの
    • 無効にした分、検査が不要になり、製造コストを下げることができた
  • 486DX2 / ODP
    • 「クロックダブラー」を用いて高速化を実現
    • CPU内部においてクロック速度を2倍にする
    • 低速な外部システムに引きずられることがなくなる

3.オペレーティング・システム

  • プロセス管理
    • Windows 3.1はイベント駆動
      • アプリケーション側でイベント待ちのときに他のタスクに切り替える
      • お行儀の悪いアプリケーションが暴走すると、システム全体が引きずられて停止状態になることがある
    • Windows NTやOS/2プリエンプティブマルチタスク
      • 一定時間ごとのハードウェア割り込みを利用して、割り込み時にタスクの実行権を取り上げ、他のタスクに切り替える
      • 他のタスクに影響されなくなる
  • メモリ管理

4.プロテクトモード

  • CR0(コントロールレジスタ0)のPEビット(Protection Enable)を1にするとプロテクトモードに移行、0にするとリアルモードに移行
  • 移行する際はJMP命令でパイプラインをクリアする必要がある
    • パイプラインとは、命令実行の工程を読み出し・解釈・実行といった複数の段階に分け、ある命令を「実行」している間に次の命令の「解釈」次の次の命令の「実行」を並行して行う処理
    • リアルモードからプロテクトモードに移るとき、リアルモードの命令がパイプラインに残ってしまっているので、パイプラインを無効化する必要がある

5.セグメント

  • セグメントとは、メモリを一定のサイズで区画割りする方式
    • セグメントによって、タスク間のメモリ分離・保護ができる
    • 8086では、メモリ分離・保護機能はなかったものの、16bitレジスタで64KB以上のアドレスにアクセスするためにセグメント機能を採用していた
  • セグメントアドレスとオフセットアドレス
    • CPUが実行するマシン語プログラムでは物理アドレスでメモリを指定することはできず、セグメントアドレスとオフセットアドレスを用いて指定する
    • セグメントアドレスはセグメントに付けた番号、オフセットアドレスはセグメントの先頭から数えた番号
    • セグメントアドレスはセグメントレジスタに格納し、個々の命令ではオフセットアドレスを指定する
  • リアルモードのセグメント
    • セグメントベースは、セグメントアドレスを物理アドレスの上位16bitに当てはめ、下位4bitを0としたものになる
    • アドレスは20bitで表せる範囲=1MBが上限になる
  • プロテクトモードのセグメント
  • 32ビットセグメント
    • リアルモードではオペランドサイズ・アドレスサイズのデフォルト値は16bit
    • プロテクトモードは16bit・32bitのどちらも設定可能
      • CSレジスタが16bitセグメントを指すときはサイズのデフォルトが16bit、32bitセグメントを指すときは32bitになる
      • コードセグメントが16bitか32bitかは、セグメントディスクリプタ中のDビットで決まる

6.保護

  • セグメントリミット
    • すべての命令に先立ち、メモリのオフセットアドレスがリミット値を超えないかチェックする
    • リミット値はセグメントディスクリプタにセットされている
  • セグメント属性
    • セグメント属性によって、使用できるレジスタが制限されている
      • コードセグメントはCSレジスタ、データセグメントはCS以外のセグメントレジスタ(DSなど)
      • リアルモードでは制限されていなかった
  • 特権レベル
    • 実行できる命令の種類とアクセスできるメモリの範囲を規定する
      • 特権レベル0が一番強く、3が一番弱い
      • 0はOS、1~2はデバイスドライバ、3はアプリケーション
    • セグメントごとに特権レベルが定義されており、それをDPLと呼ぶ
    • プログラム実行中の動作レベルをCPLと呼び、実行中のコードセグメントのDPLによって決まる
      • 異なる特権レベルのセグメントに直接ジャンプすることはできない
      • セグメントレジスタセレクタ値をロードする瞬間に、セグメントアクセスのチェックが行われる
      • セグメントの特権レベルが動作レベルよりも高い場合はフォールトを発生させる
    • 上位レベルのコードセグメントを呼ぶときは、コールゲートを介して呼ぶ
      • コールゲートはディスクリプタセグメント中に作成され、セグメントと同様の呼び出し方をする

7.割り込み

  • 割り込み要因
    • ハードウェア割り込み、トラップ、フォールト、アボート
    • 割り込み要因に対応した「割り込み番号」があり、それに対応する割り込み処理ルーチンがある
  • リアルモードでの割り込み処理
    • 割り込み番号と処理ルーチンの対応を「割り込みベクタテーブル」によって設定する
    • 割り込みベクタテーブルは物理アドレス00000Hから固定で1KB確保されている
  • プロテクトモードでの割り込み処理

8.タスク

  • TSS
    • タスク状態の保存・復元に使用するデータ構造
      • タスク1つにつき必ず1つ持つ
      • タスク切り替え時のCPUレジスタの値、OSのファイル・デバイスの管理状況などを持つ
      • TSSを指し示すTSSディスクリプタがある
  • TR
    • 現在のTSSのセレクタ値を保持するレジスタ
    • タスク切り替えでは、jmp命令を用いてTRの指す先を変え、切り替え先のTSSからレジスタ内容を復元し、タスク切り替えを行う

9.ページング

  • ページング方式
    • メモリを固定長に分割して扱う方式
      • セグメント方式はメモリを任意の大きさで区分けする
    • 論理空間におけるページ(論理ページ)を物理メモリのページ(物理ページ)に対応付けてアドレス変換を行う
      • 論理ページと物理ページの対応はタスクごとに独立している
  • 仮想記憶
    • 物理メモリに紐付けられていない論理ページアクセスした際にページフォルトを発生させ、使用されてない論理ページに対応する物理ページをディスクに退避し(ページアウト)、空いた物理ページにディスクから読み込む(ページイン)
    • 実際の物理メモリよりも大きなメモリ空間を扱うことができる
  • 486ではセグメント方式とページング方式を組み合わせてメモリ管理をしている
    • 物理メモリを論理ページに対応付けする(リニアアドレス空間)
    • リニアアドレス空間をセグメント方式によって管理する。つまりページ単位で管理する。
      • セグメント方式のメモリ保護やタスク間のメモリ分離と、ページングの仮想記憶のいいとこ取り
  • ページング機構
    • CR0のPGビットを立てるとページング機構が有効になる
    • リニアアドレスから物理アドレスへの変換では、ページディレクトリテーブル→ページテーブル→ページ→物理メモリと辿っていく
      • 各ページテーブルも仮想記憶の対象とし、最近アクセスのあったページテーブルのみをメモリに置くことで、メモリ効率を高めている
  • PTE
    • ページングに使用されるメモリ上のデータ構造
    • ページ番号
      • PTEの上位20bitに記述され、下位12bitを0で埋めるとページの先頭アドレスになる
    • Pビット
      • PTEに対応するページがメモリに存在するか
    • Aビット
      • 読み書きすると1がセットされる。OSがページアウトの対象を選定するときに用いる。
    • Dビット
      • 書き込み時に1をセットする。ページアウトの際にディスクに書き込むかを判定するのに用いる
  • TLB

10.セキュリティ

  • 要求者特権レベル
    • 本来そのセグメントにアクセスしようとしたプログラムの特権レベル
      • 特権レベルの乗っ取りを防ぐ
  • コンフォーミングセグメント
    • 特権レベルを移行することなく、特権0のプログラムをアプリケーションから呼び出せるしくみ
    • コードセグメントの一種
      • 特権レベル移行時のオーバーヘッドを気にする必要がなくなる
    • コンフォーミングセグメント呼び出し時は動作レベルが変化しない = CPUの動作レベルとセグメントの特権レベルが異なる
  • LDT(ローカルディスクリプタテーブル)
  • I/O許可マップ
    • タスクごとにIOポートのアクセス制限をする
    • TSS内にI/O許可マップを保持する

このあと「11.仮想8086モード」、「12.DOMエクステンダーとDPMI」、「13.486応用プログラミング」と続くが、疲れてきたので割愛。

CPUの挙動の理解が深まる良い本だった。

この本を読み終わった後に、以下の記事などでIntel CPUの歴史を追ってみたりもした。
@IT:PCエンサイクロペディア:第7回 PCのエンジン「プロセッサ」の歴史(1)〜i8088からIntel386までの道のり 1. IBM PCシリーズに採用された86系16bitプロセッサたち
@IT:頭脳放談:第27回 RISCの敗因、CISCの勝因

「君の名は。 Another Side:Earthbound」を読んだ

特に気になっていた三葉の父親の心理描写が描かれており、映画を見てモヤモヤしていた部分がスッキリした。

「君の名は。」を読んだ

年末にようやく「君の名は。」を映画館で見ることができ、その余韻に浸ったままKindleでポチった。
一人称で物語が描かれている点が映画とは異なるが、ストーリーは同じ。なので、異なる描写があることを期待して読むとがっかりするかもしれないが、映画の余韻に浸る分には申し分ない本だった。あとがきで、新海誠監督と川村元気プロデューサーがどういう目線でこの作品を作ったのかを述べているのも興味深い。

「ゲームプログラマになる前に覚えておきたい技術」を読んだ

ゲームプログラマになる前に覚えておきたい技術

ゲームプログラマになる前に覚えておきたい技術

学生時代に3Dゲームを開発する授業があり、その際の参考図書として購入していた本。
去年、サーバーサイドエンジニアからモバイルゲームのクライアントエンジニアに転向するにあたり、もう一度読み直してみた。

いくつかのサンプルゲームの開発を通じて、ゲーム開発に必要なスキルを広範囲に渡って解説しており、ゲーム開発に必要な技術の全体像を掴むのに最適な本だと思う。C++、2D・3Dグラフィクス、シーケンス遷移、衝突処理、サウンド、データ構造・アルゴリズム、マルチスレッド処理と多岐に渡る技術領域を取り上げている。800ページ超の大作だが、説明が丁寧かつ語り口調ベースなので、比較的すらすら読める。ゲーム開発に対する筆者の哲学を所々で語っているのも良かった。

なお、タイトルからは初心者向けの本のように見えるが、C++でのコーディング経験があって、CPUやメモリが何をやっているのかがざっくりイメージできるような方が対象になると思う。

2016年振り返り

🍻を飲みながら雑に振り返っておく。

マネージャー

エンジニア組織のマネージャーになった。模索しながら手探りでやっていたが、振り返ると、メンバーの育成やモチベーションコントロールに意識が取られすぎて、組織がどうあるべきか、組織がどういう方向に進むかを示して引っ張るようなアクションが弱かったように思う。

反省点は多いが、チャレンジングなアサインをしたメンバーがしっかり成果出して成長する姿を見ることができたのは良かった。組織に漂っていた閉塞感を打破しようと、攻めのアサインを行うことを心がけた。組織にとってやはり一定の新陳代謝が必要だと思うので、来年もこれは心がけたい。

バイルネイティブゲームのクライアントエンジニア

主戦場をwebからモバイルネイティブに移した。プログラミング言語的にはPerlJavaScriptから、C++をメインに扱うようになった。メモリ管理面倒だなーと思う一方で、それも含めてCPUの気持ちになってコードを書くのが楽しい。低レイヤをもっと知りたい欲が出てきたし、自作コンパイラ作ってみたいと思うようになった。

筋肉

一念発起して、筋トレを始めた。腹筋も割れてきたし、痩せたし、仕事のパフォーマンスも上がった気がするので、良いこと尽くしだ。

来年やりたいこと

  • OSSへのコントリビュート
  • 英語
  • Rust
  • 自作コンパイラ
  • グラフィックAPI
  • 読んだ本の感想をブログに書く

 

来年は20代最後だし、悔いのない1年にしたい。

 

 

うっすら腹筋が割れるまでにやったこと

この記事は 筋肉 Advent Calendar 2016 8日目の記事です。
qiita.com

腹筋を割るために、3ヶ月前から色々やってきたので、いったんまとめておきたいと思い、筋肉Advent Calendarに参加しました。ダイエットが主目的の筋肉ビギナーによる記事なので、筋肉ガチ勢の皆様におかれましては、赤子の成長を見守るような優しい眼差しで見ていただけると幸いです。

なぜ腹筋を割りたいと思ったのか

社会人になってからゆるゆると体重が増え続け、ゆるふわボディになっている事実から目を背けていたのですが、1年程前に娘が産まれてから家族で写真を撮る機会が増え、ふっくらした自分の顔を見る度に、そろそろ痩せねばと思うようになりました。また、30歳がそろそろ迫ってきて、「20代のうちにやり残したことがないか」ということを最近よく考えるのですが、肉体的にもまだまだいけるうちに腹筋を割っておきたいと思うようになったのがきっかけです。

これまで

元々ダイエット目的で1年前くらいからランニングは続けていたのですが、見た目の変化が特になく、ランニングだけではダメなのだと悟り、3ヶ月前に方針転換をしました。

腹筋を割るための方針

・なるべく低コストで
以前、ジムの回数券を購入して使い切らずに期限が過ぎてしまった苦い思い出があるので、筋トレを習慣化できるようになるまで、なるべく低コストで行うことにしました。

・脂肪を落とす
腹筋の上を覆っている脂肪を落とさない限りは、割れた腹筋が見えてきません。筋トレだけではなく有酸素運動も組み合わせて、脂肪を落としていくことにしました。

・腹筋以外の筋肉も鍛える
リバウンドしにくい体にするために、腹筋以外の筋肉も鍛えることで基礎代謝を上げようと考えました。なるべく大きい筋肉を鍛えた方が良いと思ったので、胸筋を鍛えることにしました。*1

やったこと

・腹筋ローラー
器具を使わずに自分の体重だけで行うトレーニングでは負荷が物足りなく感じたのと、970円と安かったので、腹筋ローラーを買ってみました。

膝をつけてコロコロしているだけでも負荷が高く、最初のうちは数回だけでもしっかり筋肉痛になりました。ただし、腹筋上部には効くのですが、やり方が悪いのか、腹筋下部と横(腹斜筋)にはあまり効きません。腹筋下部と横は、別の自重のトレーニングをしています。

筋トレは超回復を考えると2日ほど間隔を空けた方が良いと聞きますが、筋トレの習慣をつけたかったので、筋肉痛がひどい日以外はほぼ毎日やっています。今は15回×3セットくらいを目安に取り組んでいます。

簡単に分解・組み立てができるし、比較的軽いので、海外旅行に行った際にも持っていきました。

・プッシュアップバー
自重の腕立て伏せだと手首が痛いときがあったのと、こちらも1200円程度と安かったので買ってみました。

トータルフィットネス(TotalFitness) プッシュアップバー  STT020

トータルフィットネス(TotalFitness) プッシュアップバー STT020

手首も痛くならないし、深く沈み込めるのでしっかり胸筋に効かせることができます。
今は15回×2~3セットを目安に取り組んでいます。

・ランニング
平日に5kmを2回、休日に10kmを2回程度走っています。ランニングもただ走るだけだと苦痛なので、楽しく続けられるために色々と自分なりに工夫をしています。

①良いランニングコースを見つけること。以前は5kmも走ると飽きてしまっていたのですが、2ヶ月ほど前に良いランニングコースを見つけてから10km走れるようになりました。特に、走っていて飽きないような景色が自分の中では重要な要素でした。あと、他にもランニングしている人がいるようなコースだと、自分も負けじと頑張ろうと思えます。

②10kmも走っていると1時間近く脳内が暇なので、ポッドキャストを聞きながら走っています。主に Rebuild - Podcast by Tatsuhiko Miyagawa を聞いていて、「ランニングのときにしかrebuild.fmを聞いてはいけない」という制約を自分に課すことで、新しいエピソードが配信されたときにはランニングを待ち遠しく思うようになりました。rebuild駆動ランニングです。

NIKE+ RUN CLUB というアプリで、ランニングした際のログを取っています。走り終わった後に走行距離や消費したカロリーを見て、悦に浸っています。

Nike+ Run Club

Nike+ Run Club

  • Nike, Inc
  • ヘルスケア/フィットネス
  • 無料


プロテインを飲む
鍛えた筋肉に適切な栄養を届けるために、プロテインを飲むようにしています。プロテインにも色々と種類はあるようですが、まずはAmazonで一番人気だった「ザバス ホエイプロテイン100」を飲むことにしました。

ザバス ホエイプロテイン100 ココア味【50食分】 1,050g

ザバス ホエイプロテイン100 ココア味【50食分】 1,050g

プロテインはあまり美味しくないイメージがあったのですが、このザバスプロテインのココア味は美味しく飲めています。
値段は、近所のドラッグストアやいくつかのサイトと比較したのですが、Amazonの定期便で買うのが一番安かったです。Amazon定期便は1回だけの購入も可能なので、迷っている人も定期便で購入するのをオススメします。

・平日断酒
社会人になってから、毎日ビールを1~2杯飲むのが習慣になってしまっていました。アルコールの摂取によって肝臓に負荷をかけてしまうと、脂肪の分解を妨げてしまうと聞いたので、平日はなるべく飲まず、週末だけ飲むようにしました。ビールを飲みたいなーと思う夜も、プロテインを飲むと満足してしまうことが多く、ビールを飲まなくてもいいやと思えるようになったので、平日断酒がうまく続いています。

結果

写真を載せる勇気はないのですが、腹筋がうっすら割れてきました。胸も以前はぷるぷるでしたが、それなりに胸筋がついてきています。体重は3kg落ち、体脂肪率は10%を切り、9.5%前後になりました。久々に会う人にも痩せたねと言われるようになり、割りと満足のいく結果が出ています。

一方、一度に複数のことを始めたので、何が効果的だったのかはよく分かっていないです。特に、プロテインは本当に効果的なのか、ビールは本当にダイエットの敵なのか、は今後きちんと検証したいと思っています。来年の筋肉Advent Calendarで結果報告ができると良いですね。

最後に

筋トレはやればやるほど、見た目の変化だったり、体重や体脂肪率といった数値の変化が表れてくるので、RPGのレベル上げみたいな感覚で楽しく取り組むことができています。また、ランニングや筋トレはストレス発散にもなっていて、精神衛生上にも非常に良いです。エンジニアという職業柄、脳に負荷をかけることが多いですが、筋トレやランニングをすることで、一旦頭の中がリセットされてすっきりします。

この記事が腹筋を割りたいと思っている筋肉ビギナーの方に、少しでもお役に立てば幸いです。

*1:大きい筋肉というと、太ももの裏の筋肉を鍛えることも考えましたが、自重トレーニングだと負荷が物足りなかったのと、ランニングである程度鍛えられるだろうと思い、今回はスコープから外しました。