サイト「低レイヤを知りたい人のためのCコンパイラ作成入門」をやってみる 1回目

掲題通りです。コンパイラを作成することでコード解析とアセンブラ出力が学習できれば。

参照サイト

www.sigbus.info

環境

想定する実行環境が64bit LinuxということでWSLをインストールします。 Windows側では/User/hoge/ubuntuというフォルダを用意します。 WSL側で/home/hoge/.bashrcの末尾に cd /mnt/c/users/hoge/ubuntu と記載しておき、WSL起動時に開発ディレクトリにアクセスできるようにしています。

簡単な例

int main() {
  return 42;
}
$ gcc -o test1 test1.c
$ ./test1
$ echo $?
42

gccして終了コードを$?で見れることが分かる。

次に上記コードに対応するアセンブリプログラムを書いてみる

.intel_syntax noprefix
.global main
main:
        mov rax, 42
        ret

呼び出し規約で関数の戻り値はレジスタraxに入れる、とのこと。gccして$?を参照すると先ほどと同様終了コードをみることが出来た。

関数呼び出しのコードがアセンブラでどうなるか

関数呼び出しはただのジャンプと違い、呼び出された関数の終了後、元の場所に戻らなければいけない。 そこで元のアドレス「リターンアドレス」をスタックメモリに保存しておく。 なぜスタックなのかは、多段呼び出しに対応するため。

スタックはスタックの一番上のアドレスを記憶しておけばよい。この一番上のアドレスを記憶しているのがスタックポインタ。x86-64には

がサポートされている。ちなみにスタックにデータを積むことを「プッシュ」と言い、データを取り出すことを「ポップ」という(復習)。(キュー構造ではデータ追加がenqueue、データ取り出しがdequeue)

以下、関数呼び出しの実例。引数x, yを足し合わせる関数plusとそれを呼び出して戻り値を終了コードに乗せるmain関数をアセンブラで書いたもの。Cコードは割愛。

.intel_syntax noprefix #アセンブリ文法指定
.global plus, main #plusとmainがプログラム全体から見えることを指示

plus:
        add rsi, rdi
        mov rax, rsi
        ret

main:
        mov rdi, 3 #お約束
        mov rsi, 4 #第一引数はrdi、第二引数はrsiレジスタ
        call plus
        ret

関数を呼び出す命令callは以下のことを行う。

  • callの次の命令のアドレスをスタックにプッシュ(上述の「リターンアドレス」?)
  • callの引数アドレスにジャンプ

関数の戻り値はraxに入れておく決まりなので、plus関数のret命令の前にraxレジスタへの格納命令がある。

plus関数の最後にret命令がある。ret命令は以下のことを行う。

  • スタックからアドレスを1つポップ(取り出す)
  • 取り出したアドレスにジャンプ

mainの中でcall plusの次の命令のアドレスをスタックにプッシュしていたので、plus関数のret命令によりcall plusの次のアドレスに飛ぶことができる。

章の(個人的)まとめ

  • 関数戻り値はraxレジスタに格納
  • callとretは対。

次章

次は「電卓レベルの言語の作成」をやります。

Blender 練習:歯車

Blender 3DCG モデリング・マスターhttps://www.amazon.co.jp/dp/4800711479/より。 本の内容は歯車1個だけだったので、アニメーションをつけました。

youtu.be

要点

アニメーション

  • ドープシートのフレーム選択が右クリックだった。(Ver.2.79。設定で左右クリックは交換済みなのに)
  • 何もしないとアニメーションの初めと終わりで速度補完がされてしまうので、ドープシートの channel > Extrapolation mode > Linear Extrapolation。これでループになる。
  • キーフレーム挿入のショットカットキーはIキー。
  • 左の歯車を回転させる前にShift + S > Cursor to Selectedで左歯車オブジェクトの中心に3Dカーソルを持ってきた後、回転処理&キーフレーム作成を行う。

保存

Outputメニューのformatでmpeg videoを、EncodingメニューでMPEG-4, H-264を選択して、

f:id:kcha:20190720143837p:plain

RenderメニューのAnimationでレンダリング開始。(この場合だとc:/tmpに保存される。)

f:id:kcha:20190720143225p:plain

なお、twitterに動画ファイルを直接上げることが出来ませんでした。 (そのおかげでブログを書く気になった…)

WSL (Windows Subsystem for Linux)導入メモ

www.sigbus.info このサイトでコンパイラを勉強するために、以前導入していたWSLを使ってあれこれ出来るよう、やったことについてメモを残しておきます。 (といっても開始ディレクトリを変更するための.bashrc編集ぐらいですが。)

WSLからWindowsファイルシステムへのアクセス

my-web-site.iobb.net WSLからWindowsファイルシステムのアクセスは /mnt/c/ なので、上記サイトのとおり .bashrc の末尾に cd /mnt/c/users/[my name]/ubuntu を追加しました。

viは苦手なのでnanoエディタを使いました。(viのコマンドを毎回検索していて、正直めんどい)

逆にWindowsからWSLの領域に触って編集等することはご法度だそうです。もうそろそろWindowsのアップデートでそれも可能になるとのことですが。 forest.watch.impress.co.jp

アップデートとgccの準備

ubuntuでお約束のsudo apt updatesudo apt upgradeを行った後、sudo apt install build-essentialgcc環境をインストールしました。

hello.c編集(Windows) -> コンパイル(WSL)

Windowsf:id:kcha:20190707220904p:plain

WSL側

f:id:kcha:20190707221226p:plain

【Unity】振り子を作る

はじめに

倒立振子(紳士って変換すんのやめーや)をUnity上で再現できないか、と考えていて、その前準備としてHinge Jointの使い方を少し調べてみました。

なお以下のサイトを参考にしています。

matatabi-ux.hateblo.jp

(ただ上記記事はHinge Jointコンポーネントをアタッチする先が逆になっているものと思われるので、自分の方では振り子(動体)の方にHinge Jointコンポーネントを当てています。)

 

単独の振り子を作る場合

単独でぶらぶらさせるのは特に複雑なことはなく、(Rigidbodyのアタッチは当然なので割愛)揺れる対象にHinge Jointをアタッチし、揺れの軸Anchorを(ローカル座標なので)物体からどれだけ離すか設定すればいいだけです。Connected Bodyの設定が空だと動体はグローバル座標(空間?)にピン止めされたようになります。

f:id:kcha:20181111155146p:plain(左上の小さな矢印のようなものが揺れの軸です)このように動きます。 

f:id:kcha:20181111160024g:plain

 

何か動くものに振り子を繋ぐ場合

振り子が動くものにジョイントされるにはConnected Bodyに対象の動体をアタッチする必要があります。(今回は球の上にあるキューブです。)なおConnected Bodyの選択肢にオブジェクトがリストされるにはRigidbodyを持っていないといけないようで、上部のキューブにはRigidbodyをアタッチし、物理計算で落下しないようIs KinematicをOnにしてあります。

f:id:kcha:20181111154841p:plain(Connected BodyにPivot(キューブ)をセットし、Anchor位置をPivotと同位置になるようセット。)すると以下のようになります。(動体に留められていることが分かるよう、キューブには左右の移動アニメーションをつけています。)

f:id:kcha:20181111160452g:plain

(ジョイントが1個なのでキューブと球を繋いでいるのが棒に等しい。ジョイントを複数作れば鎖のようにできるのでしょうが。)

 

終わりに

参考サイトのほぼ丸写しではありますが、ヒンジを持ったオブジェクトの作成ができるようになりました。

Unityのリファレンスでの紹介では犬用ドア付きのドアを例に出していますが、ドアのHingeの軸をY軸に、犬用ドアのそれをX軸にすればいいのだけれど、(犬用ドアの)一部分が欠けたプレートをどうやって作るか頭が回らなくなってきたので、ここまで。

(だいぶ実験用プロジェクトの中身がごちゃごちゃになってきた。)

Jupyter Notebookファイルの貼り付けテスト

覚えておくこと

Jupyter Notebook上に表示された出力は、保存データの中に格納されているようなので、例えば外部ファイルの読み込みから表を出力というフローでも、すでに出力される表自体がJupyterのファイル内に入っているので、データファイルをGistに添付する必要は無い。参考はここ。(D&D後、2つのうち一つはいらないのがミソ)

mashiroyuya.hatenablog.com

 

今回の試したもの

kaggleのタイタニックチュートリアルA Comprehensive Guide to Titanic Machine Learning | Kaggle)の冒頭をGistに張り付けてはてなへ。(Gistもはてなも便利)

Test of Gist Presentation of Jupyter Notebook

R言語 入門(文法)

はじめに

R言語の入門として、基礎的な文法を追っていく。

環境

ここからWindowsのバイナリのインストーラをダウンロード。

Download R-3.5.1 for Windows. The R-project for statistical computing.

実行(およびデモの実行方法)

インストールしたRを実行すると、ExcelのようなWindow in Window(このアプリの形式を何ていったっけ?)で、 コンソールがでてくるので

> demo()

と入力すると、予めインストールされているデモンストレーションのリストが 表示される。この各デモを実行するには(例えばgraphicsパッケージのJapaneseを起動したい場合)

> demo(Japanese, package="graphics")

と入力すると以下のようなデモが立ち上がる。 f:id:kcha:20180915172645p:plain

代入

数値、ベクトルの変数への代入は<-を使う。左から右への代入->もできる。
ベクトルの作成にはc()関数を使う。

> x = c(10.4, 5.6, 3.1, 6.4, 21.7)
> x
[1] 10.4  5.6  3.1  6.4 21.7
> c(x, 0, x) -> y
> y
 [1] 10.4  5.6  3.1  6.4 21.7  0.0 10.4  5.6  3.1  6.4 21.7

(ベクトルの中にベクトルを入れることも可能)

ベクトルの算術計算

ベクトルの四則演算も出来て、ベクトル同士の次元?が等しくなくても動く(警告は出る)。

> y
 [1] 10.4  5.6  3.1  6.4 21.7  0.0 10.4  5.6  3.1  6.4 21.7
> y * 2 -> yy
> yy
 [1] 20.8 11.2  6.2 12.8 43.4  0.0 20.8 11.2  6.2 12.8 43.4

> y
 [1] 10.4  5.6  3.1  6.4 21.7  0.0 10.4  5.6  3.1  6.4 21.7
> x
[1] 10.4  5.6  3.1  6.4 21.7
> x + y
 [1] 20.8 11.2  6.2 12.8 43.4 10.4 16.0  8.7  9.5 28.1 32.1
 警告メッセージ: 
 x + y で: 
   長いオブジェクトの長さが短いオブジェクトの長さの倍数になっていません 

以降、続く(はず)

dB形式の変換

はじめに

ある本で見かけた数式をコードにおこす練習。(兼ブログ練習)

数式

線形値(dB形式が対数であるのでその対称としてこう呼称する)Nは次式によりdB形式に変換される。
 B[dB] = 10log_{10}(N)
逆にdB値Bから線形値への変換は
 N = 10^{B[dB] / 10}
となる。コード(python)は

import math

def from_decibel(b):
    return 10 ** (b / 10.0)

def to_decibel(N):
    return 10 * math.log10(N)

print("10 dB: " + str(from_decibel(10))) # 10 dB: 10.0
print("20 dB: " + str(from_decibel(20))) # 20 dB: 100.0
print("30 dB: " + str(from_decibel(30))) # 30 dB: 1000.0
print("4000 is " + str(to_decibel(4000)) + "dB")

増幅器の利得係数が100の場合、20dBの利得がある。
 10log_{10}(100) = 10 \times 2 = 20[dB]