sh/bashのパイプ/リダイレクションの使い方

sh/bashのパイプ/リダイレクションの使い方についてよく使いがちなものを理解できるようにまとめておく。

モチベーション:挙動がよくわからない

シェルスクリプトに書かれているリダイレクションが理解できない。

これまで、運用とかしてこなかったので人の書いたスクリプトを読むこともなく生きてきて、シェルはtcshでできる部分でいいや、という感じで生きてきた。でも環境はいつもデフォルトで使っちゃう派なので何かしら自動化しようとするとsh/bashを使わないと色々めんどいことに気づいた。しかたがないのでいまさらながらリダイレクションの記法について学ぶことにしてみた。

自分の理解度テスト的に下記を上げてみたけど、こんな感じ。

cmd > file # わかる
cmd >& file # なんだっけ?
cmd1 | cmd2 # わかる 
cmd1 |& cmd2 # わかる気もする。でも自分で書くときはこれが出てこない。

cmd 2>&1 > /dev/null # えっ?

以下に大体の読み方の基本から順番に書いていく。

基本

sh/bashのリダイレクションは基本的に (ディスクリプタ)> (ファイル) の羅列の形式である。
たとえば、

cmd 1> file

だとディスクリプタ1の出力先をfileという名前のファイルに設定する、という意味になる。

基本的にディスクリプタの1は標準出力、2は標準エラー出力なので、下記は「標準出力の出力先をfile1に、標準エラー出力の出力先をfile2に設定する」という意味になる。

cmd 1> file1 2> file2

>の代わりに>>を使うとファイルに追記する意味になる。

cmd 1>> file1
cmd >> file1

パイプは標準出力の出力先を後続のコマンドの標準入力に設定することを意味する。
下記はcmd1の標準出力をcmd2の標準入力に設定する。

cmd1 | cmd2

パイプにはディスクリプタ番号は指定できない。常に標準出力を次のコマンドの標準入力につなぐ。

リダイレクションの省略形

リダイレクションのディスクリプタが省略された場合は1を意味する。
つまり、下記の2つは同じ。

cmd > file
cmd 1> file

ディスクリプタの複製

>& 記号を使ったディスクリプタの複製について説明するが、これは複製?よくわからないので複製というのは「そういう名前」だと思って深く考えないほうが読みやすいかもしれない。

a>&b はディスクリプタaの出力先をディスクリプタbと同じにすることを意味する。
下記は標準エラー出力を標準出力と同じターミナルに出力する。

cmd 2>&1

なお、ディスクリプタaは省略できてデフォルトは2である。bは省略不可。

つまり、下記も同じ意味になる。

cmd >&1

複数の記述がある場合の理解の仕方(これ重要)

基本パターン

複数の記述がある場合、基本的には左から解釈される。
この過程をこれから述べるように表の形式で理解していくと出力結果を考えやすい。

基本的に何もしなければ標準出力等の出力先は下記のように設定されている。

ディスクリプタ 出力先(当初)
1 標準出力(ターミナル)
2 標準エラー出力(ターミナル)

ファイルへのリダイレクションが追加されると

cmd 1> file1 2> file2
ディスクリプタ 出力先(当初) 1> file1 適用後 2> file2 適用後
1 標準出力(ターミナル) file1 file1
2 標準エラー出力(ターミナル) 標準エラー出力(ターミナル) file2

標準出力はfile1へ、標準エラー出力はfile2へ出ることになる。

複製を含む場合

複製を含む場合、上記で説明したように複製を「出力先を同じにする」と理解するのがポイントになる。

下記のような複製がなされた場合、複製は出力先を同じにするので下記のようになる。

cmd 2>&1
ディスクリプタ 出力先(当初) 2>&1適用後
1 標準出力(ターミナル) 標準出力(ターミナル)
2 標準エラー出力(ターミナル) 標準出力(ターミナル)

下記のように順序を逆にすると結果が変わる。

cmd 2>&1 1> file1
ディスクリプタ 出力先(当初) 2>&1適用後 1> file1 適用後
1 標準出力(ターミナル) 標準出力(ターミナル) file1
2 標準エラー出力(ターミナル) 標準出力(ターミナル) 標準出力(ターミナル)

逆パターンだと

cmd 1> file1 2>&1
ディスクリプタ 出力先(当初) 1> file1 適用後 2>&1適用後
1 標準出力(ターミナル) file1 file1
2 標準エラー出力(ターミナル) 標準エラー出力(ターミナル) file1

ディスクリプタの数を増やしてみる。新しいディスクリプタ3にはデフォルトでは何も設定されていない。

cmd 2>&1 3>&2
ディスクリプタ 出力先(当初) 2>&1適用後 3>&2適用後
1 標準出力(ターミナル) 標準出力(ターミナル) 標準出力(ターミナル)
2 標準エラー出力(ターミナル) 標準出力(ターミナル) 標準出力(ターミナル)
3 未設定 未設定 標準出力(ターミナル)

逆にしてみると

cmd 3>&2 2>&1
ディスクリプタ 出力先(当初) 3>&2適用後 2>&1適用後
1 標準出力(ターミナル) 標準出力(ターミナル) 標準出力(ターミナル)
2 標準エラー出力(ターミナル) 標準エラー出力(ターミナル) 標準出力(ターミナル)
3 未設定 標準エラー出力(ターミナル) 標準エラー出力(ターミナル)

パイプを含む場合

パイプを含む場合、標準出力の当初値が変わる。

cmd1 | cmd2
ディスクリプタ 出力先(当初)
1 cmd2の標準入力
2 標準エラー出力(ターミナル)

複製と併用するとこんな感じになる。

cmd1 2>&1 | cmd2
ディスクリプタ 出力先(当初) 2>&1適用後
1 cmd2の標準入力 cmd2の標準入力
2 標準エラー出力(ターミナル) cmd2の標準入力

この例は比較的記法の似た cmd 2>&1 1> file のパターンよりは cmd 1> file 2>&1 のパターンとの類似性を強く感じるものになっている。
よく「左から読め」と言われるのだけれども、パイプだけは右側に書かれているのに、一番左に書いたような挙動をするので非常にわかりにくい感じがする。

複製と他の構文をまとめた記法

複製には他の構文とまとめる記法がある。

ファイル出力とまとめて書くことができる。

cmd 2>& file

これは下記と同じ。

cmd 1> file 2>&1

パイプとまとめて書く記法がある。

cmd1 |& cmd2

これは下記と同じ。

cmd1 2>&1 | cmd2

復習

出だしにあったコマンド群

cmd > file # わかる
cmd >& file # なんだっけ?
cmd1 | cmd2 # わかる 
cmd1 |& cmd2 # わかる気もする。書けない。

cmd 2>&1 > /dev/null # えっ?

は下記であることがわかるようになります。

cmd > file # 標準出力をfileに設定
cmd >& file # 標準出力と標準エラー出力をfileに設定
cmd1 | cmd2 # 標準出力をcmd2の標準入力に 
cmd1 |& cmd2 # 標準出力と標準エラー出力をcmd2の標準入力に
cmd 2>&1 > /dev/null # 標準出力を/dev/nullに、標準エラー出力をターミナルに標準出力として出力

結論

大事なことを書きます。

ググるのもいいけど、man (1) bash 読め。全部書いてある。

その他

2年ぶりに書いた記事がこれかよ、と悲しんでいる。

つらぽよいsecure boot

つらぽよAdvent Calendarにネタを提供したわけでも何でもないんだけど

自宅のデスクトップPCが壊れた。具体的に言うと、HDDがクラッシュした。
もうちょっと正確に言うと、動作真っ最中に子供がぶつかって倒してしまった。
昔のHDDと比べると、あのカツーン、って音がかなりささやかだけど、ありがちなあの音を立てて起動しない現象になった。

PC自体はLenovoのやっすいやつ(H520S)である。キーボードとか、スピーカーとか、こまいパーツコミコミで4万円とかしなかった。Core i5Windows7が載ってた。

でも、我が家では結構ハイスペックマシンである。

どうしようか悩んだ。なぜか換装用のHDDはあった。SATA-II出だしの頃のやつで遅いけど、容量300Gとかあるので、デスクトップ機としては問題ない。Lenovoにはリカバリディスクを送ってくれるサービスがあるらしい。このHDDとリカバリディスクでハッピーになれそう。。。なわけなかった。7000円払う必要があるし、なによりLenovoの窓口自体が年末年始で休業中だ。

あー、じゃー、Linuxとかでいいじゃん。

Ubuntuのインストールディスクを手持ちのネットブックで焼いて、インストールしたら、無事インストールできた。さすが!余裕じゃないですか。いつもVMPlayerでやってるのと同じじゃん!

と思ってインストール後にPCを再起動したら、

 Error1962:No operating system found.

ありー、なんかやり方まずかったかな。。。。

起動ディスクを別途作って起動しようとしても、全然起動しない。


ググってみると
Amazon.com: Customer Reviews: Lenovo H520s Desktop


Linux起動がうまく行かない、というような阿鼻叫喚の嵐。

集めた情報をだいたいかいつまんでまとめてみると

  • 一部のLenovoのUEFI系マシンはsecure bootという仕組みがあり、Windows8が立ち上がるにはこれが必要である。
  • 上記の仕組みを持つハードウェア環境でUbuntuなどの非正規OSはsecure bootにより起動を阻害される。RHELFedoraの一部は正規の認証を受けているものがあるが、それ以外はsecure bootをOFFにしないと起動しない。

なるほど、secure bootをOFFにする必要があるのね、、、どうりで立ち上がらなかったわけだ。

と思い、BIOSのメニューを探してみたが、


secure bootに関するメニューすらない。。。。


マジか、、、同じ機種名の中でもOFFにできないモデルっぽい。


それでも、secureのまま、dual bootに成功している例はあるらしい。でも、逆に言うとdual bootの例しかない。どうも、Windowsのローダーを踏み台にして立ち上がるのは可能だが、それ以外はダメ、という感じらしい。(多分。たぶんね。)

つまり、WindowsのEFIローダーを書いておいて、起動シーケンスを横から頂戴すればいいのね!?


…いや、それやったら普通にリカバリディスク注文するし!


まー、どうしようかさんざん悩んだ挙句、Ubuntuのインストールディスクが起動していたのを思い出した。外部ブートはできるけど、光学ドライブのISOイメージだけってことっぽいんだよな。。。USBからも立ち上がんなかったし。


で、試しに、UbuntuのインストールディスクのgrubからHDD上のgrub.cfgを読み込んでみると、嘘のようにすんなりインストール後のHDDからシステムが起動した。


そういうわけで、当面、光学ドライブを踏み台にして起動する方向になりそうです。
なんだか変な感じではあります。
現時点ではUbuntuのインストールディスクを使っていますが、めんどいしアホいので、そのうちもっと小さなisoイメージ作ろうかなと思っています。

他にいい方法ないのかな。


正直、secure bootなるものにこういう風にいじめられるとは、なにか数奇な関係があるのかもしれません。

Evalモナドを使って無限リストの並列評価

http://partake.in/events/9f226986-2812-441d-98b7-1f5cca9be432 にオンライン参加してきたので、Evalモナドを使った並列評価を行なってみた。

コード

ナイーブな素数探索アルゴリズムです。指定された数以上の一定個数の素数を抽出します。

import Control.Parallel.Strategies

-- rseq first n elements in parallel, then next n..
parListWithN :: Int -> [a] -> Eval ()
parListWithN n l = do
    parSeqListPar $ take n l
    case drop n l of
      [] -> return ()
      _  -> parListWithN n $ drop n l

-- rseq in parallel for finite length list
parSeqListPar :: [a] -> Eval ()
parSeqListPar [] = return ()
parSeqListPar (hd:tl) = do
    rpar hd
    parSeqListPar tl
    rseq hd
    return ()

-- filter f l with parallel precalcuration for l
filterEval :: (a -> Bool) -> [a] -> [a]
filterEval f l = runEval $ do
    rpar $ runEval $ parListWithN 100 l
    return $ filter f l

-- prime testing
isPrime :: Integral b => b -> Bool
isPrime n = not $ or $ map ((==0).(n `mod`)) [2..(n-1)]

-- find 100 successive primes after 435300
main = print $ take 100 $ filterEvalN isPrime [435300..]

このコードの挙動のポイントはいくつかあります。

  • filterEval関数:並列処理のトリガーを引くコードを処理キューに積んで、全体評価を始めます。
  • parListWithN関数:最初のn個の処理を並列処理にかけ、完了したら次のn個、というようにEvalモナドの挙動を指示する関数です。

並列処理がしたければ、rparを使ってタスクを積んでいくだけの簡単なお仕事です。

でも、次のような問題点があります。

  • 全体評価の関数と並列処理が完全に分離していて、コントロールされていない。スケジューリング状況によっては、並列処理だけが進行して、全体評価側にフィードバックされずに進む可能性がある。

Evalモナドはこの辺りのコントロールが難しい感触があります。この後の並列計算ではこの辺りが解消されるか、気になるところです。

実行方法

使用時はthreadedオプションを付けてコンパイルします。

ghc -threaded FindPrime.hs

実行時は並列コアを指定します。

./FinePrime +RTS -N -RTS

threadscopeの実行結果とか見たかったけど、メモってる時点で時間切れなのでまた手が開けばやります。。。

モンゴメリ乗算の例

下記を参考に

モンゴメリ乗算 - Wikipediaを参考に、サンプルとして、モンゴメリ乗算の計算をしてみる。

`11*18(mod 169)`を計算する。

単純に、

11*18 = 198 = 1*169+29

で答えは`29`です。

これをあえてモンゴメリ乗算でやってみる。

モンゴメリ乗算は剰余算を減算回路の繰り返しなしに実現するテクニックです。剰余算、割り算が出てきますが、実際には2のべきしか使わないので、ビットマスクやシフト演算で高速にできるのが特徴。

`R`をひとつ決めると、サブの演算子を下記のようにとって

MR(x) = (x + (x*N' mod R)*N)/R
Ninv : N' * N = -1 (mod R) となる数
R2 = R*R mod N
a * b = MR(MR(MR(a*R2)*MR(b*R2)))

とかけます。`R2`求めるときに`mod N` やってるやん!

R:256

に設定すると、下記のように関連する数値が導出されます。

Ninv:103
R2:133

`A=MR(a*R2)` `B=MR(b*R2)`とすると

A=(a R2+(a R2 Ninv mod R)N)/R
 =(11*133+(11*133*103 mod 256)*169)/256
 =112
B=(18*133+(18*133*103 mod 256)*169)/256
 =45
AB=112*45=5040
MR(AB)=((AB)+(AB Ninv mod R)N)/N
      = 157
MR(MR(AB)=(157+((157*103)`mod`256)*169)`div`256
         =29

あー、戻ってきた!

モンゴメリ乗算処理のテストケースを作ってみたのだけどそのままブログに書いてみましたの巻。

__builtin_ffsはどこへ行くのか?(続編)

GCのマークビット判定などに使用される__builtin_ffsというGCCコンパイラ拡張が気になったので 「__builtin_ffsはどこへ行くのか? - dec9ue's diary」って記事をちょっと前に書きました。

続編です。

さて、何の話だったかというと、__builtin_ffsとは



Other Builtins - Using the GNU Compiler Collection (GCC) http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Other-Builtins.html によると

Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.

ということで、ビットマップ何かを操作するときに使えるGCC拡張のようだ。



ということでした。

そして、今回は

でも、対象をもうちょっとモダンなアーキテクチャに変えちゃうかも。。。

の予告通り、armv7-aのアーキテクチャに変えてみました。

arm-linux-gnueabihf-gcc -O0 -S -std=gnu99 builtin_ffs_test.c 

の結果:

test:
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 1, uses_anonymous_args = 0
        @ link register save eliminated.
        push    {r7}
        sub     sp, sp, #12
        add     r7, sp, #0
        str     r0, [r7, #4]
        ldr     r3, [r7, #4]
        rbit    r3, r3
        clz     r3, r3
        ldr     r2, [r7, #4]
        cmp     r2, #0
        bne     .L2
        mov     r3, #-1
.L2:
        add     r3, r3, #1
        mov     r0, r3
        add     r7, r7, #12
        mov     sp, r7
        pop     {r7}
        bx      lr

ARMv7AのARMインストラクションセットにはclzという先行0ビット判定を行うインストラクションがあります。これ使っちゃえば楽勝じゃん?

本当にありがとうございました。



あ、でもちょっと気になるのは、このインストラクションの発行フローはclzrbitの組み合わせがあれば使う価値があるのですが、これはARMv6T2以降のARM/32bitThumbで使えるはずです。じゃぁ、なんでCortex-M3向けのコードはあんなややこしいコードになってたのか。16bitThumbを使うことを優先したのかな?

Lucky Thirteen Attackの攻撃手法を説明してみるよ

Lucky ThirteenはTLS, DTLSのCBCモードを利用する暗号の脆弱性を突く攻撃です。具体的に言うと、CBCモードに対するPadding処理の弱い部分を狙ったPadding Oracle攻撃の一種です。

その影響とか、脅威とか、対処法とかは結構いろんな所で説明されているのですが、単純な興味とか、知識とか、内容を実感したい、というような方が読むことを想定した記事はあまりないように思われたので、その仕組みを説明したいと思います。

TLSパケットの仕組み

まずはじめに、TLSパケットの暗号処理の仕組みを簡単に説明します。

イメージとしてはこんなかんじで、ヘッダ+平文データのMAC(チェックサム的なもの)をとる→パディングをつける→暗号化する、
と言った流れでパケット(レコード)を構築します。

f:id:dec9ue:20130324132031p:plain

TLSのパディング

ブロック暗号はそのままではブロックの幅に合わないデータを取り扱えないので、パディングを付与して使用します。TLSのパディング処理はとてもシンプルです。(そしてありきたりです)

f:id:dec9ue:20130324132334p:plain

このように、ブロック長の残りがnのとき、(n-1)をn個埋めるのがTLSのパディングです。

TLSのMAC処理

MACは、復号後にデータが変更されていないことを確認するために使用します。
現在、最もよく使われているのはHMAC-SHA1です。ハッシュを繰り返して
20バイトのMACを生成します。

ここで実はちょっとしたポイントがあります。

HMAC-SHA1はデータ長によって使用されるハッシュ処理の回数が違います。
例えば、~55Byteだと4回のハッシュで済むのですが、56Byte~だと5回必要になります。

タイミングリーク

タイミングリークとは、処理のタイミングからデータや鍵に関する情報が漏れてしまうことを言います。

よくあるのは不正なパケットに対するエラー処理のタイミングリークで、Lucky Thirteenもこのケースに当たります。

適当な64バイトのシーケンスを受信者に復号させてみた場合、基本的にエラーになるわけですが、このエラーパターンは激レアなケースを除くと概ね下記のように分類されます。

  1. パディングエラー … ほぼ 255/256の確率
  2. 0x00 で終わる(1Byteパディング) ほぼ 1/256 の確率
  3. 0x01 0x01で終わる(2Byteパディング) ほぼ 2^-16 の確率
  4. : (その他レアケース)


f:id:dec9ue:20130324134008p:plain

ところで、これらについてMACを計算すると、実は0x01 0x01で終わるケースだけが必要なハッシュが少なくなっています。

f:id:dec9ue:20130324134248p:plain

実装に工夫がないと、この2^-16の確率で発生するケースだけが微妙に早くエラーパケットを返すことになります。

これぐらいの差、そうそう発見できないだろ?って思いますよね。でも、外からの観測で実際にわかった、というのがLucky Thirteen Attackの報告の主旨なのです。

Lucky Thirteen Attack

攻撃者がC*という暗号ブロックを復号したい場合、下記のようなヘッダ+4ブロックのレコードパケットを復号者に送りつけます。

ヘッダ || ブロック1 || ブロック2 || 調整ブロック || 解析対象ブロックC*

復号者は最終ブロックC*を下記のようにCBCモードで復号します。

復号後のブロック = (復号後の(解析対象ブロックC*)) XOR 調整ブロック

この復号後のブロックは先に述べたとおり下記のどれかに類型されます。

  1. パディングエラー … ほぼ 255/256の確率
  2. 0x00 で終わる(1Byteパディング) ほぼ 1/256 の確率
  3. 0x01 0x01で終わる(2Byteパディング) ほぼ 2^-16 の確率
  4. : (その他レアケース)

3.の「0x01 0x01で終わる」ケースだった場合、C*の最後の2バイトは

調整ブロックの最後の2バイト XOR 0x01 0x01

で得られるわけです。

攻撃者は2^-16の確率でこのケースを手に入れます。このケースが手に入ったかどうかはエラーが返ったタイミングで判断します。

タイミングを検出出来れば攻撃者は調整ブロックとのXORによりC*の最終ブロックの平文の最後の2バイトを取り出せます。

このような調子で次々にブロックを復号できるのですが、実は大変なのは最初の2^-16の部分だけで、
残りは2^-8の確率で見つけることができます。

こうやって攻撃者は2^16+14*2^8回のトライで暗号文を復号できます。

最後に

2^16という数字は小さいでしょうか?大きいでしょうか?

統計的な攻撃方法については述べませんでしたが、同じ平文を送信するセッションが260万回ぐらい、半分程度だとしても130万回ぐらい必要です。検索サイトのログインクッキーだったらこれくらい行ってしまうでしょうか?ちょっとわからないですね。。。

また、攻撃者の位置によってはネットワークノイズの影響をかなり受けると思われます。

いずれにせよ、リスクと投資のバランスを考えた対応が重要だとは思います。

参考

今回、参考にしたのは下記の文書のみです。おそらく、他にも良資料があるとは思いますが。

Lucky Thirteen: Breaking the TLS and DTLS Record Protocols

__builtin_ffsはどこへ行くのか?

__builtin_ffsとはなにか?

Other Builtins - Using the GNU Compiler Collection (GCC) http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Other-Builtins.html によると

Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.

ということで、ビットマップ何かを操作するときに使えるGCC拡張のようだ。

これ、何やってるかちょっと気になったのでアセンブラ見てみよー!

ということで、x86アセンブラはしばらくやる気ないので、ARMのアセンブラをやってみる。

gcc version 4.7.3 20130102 (prerelease) (Linaro GCC 4.7-2013.01) 
decque@ubuntu:~$ arm-none-eabi-gcc -print-multi-lib 
.;
thumb/arm7tdmi-s;@mthumb@mcpu=arm7tdmi-s
thumb/cortex-m0;@mthumb@mcpu=cortex-m0
thumb/cortex-m3;@mthumb@mcpu=cortex-m3
thumb/cortex-m4;@mthumb@mcpu=cortex-m4
thumb/cortex-m4/float-abi-hard/fpuv4-sp-d16;@mthumb@mcpu=cortex-m4@mfloat-abi=hard@mfpu=fpv4-sp-d16

この人、thumbしか吐けません。

__builtin_ffsを含むコードをアセンブラ化してみると:

ffsl:
        @ Function supports interworking.
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 1, uses_anonymous_args = 0
        stmfd   sp!, {fp, lr}
        add     fp, sp, #4
        sub     sp, sp, #8
        str     r0, [fp, #-8]
        ldr     r0, [fp, #-8]
        bl      __ffssi2
        mov     r3, r0
        mov     r0, r3
        sub     sp, fp, #4
        ldmfd   sp!, {fp, lr}
        bx      lr

__ffssi2へ飛んでいる。


主よ、どこへ行かれるのですか?

探してみた。

バイナリファイル /lib/gcc/arm-none-eabi/4.7.3/thumb/cortex-m0/libgcc.a に一致しました

ほう。

_ffssi2.o:
00000010 N $d
00000000 t $t
         U __ctzsi2
00000001 T __ffssi2

_ffssi2.oを逆アセンブルしてみると

ar x gcc.a _ffssi2.o
objdump -D _ffssi2.o
00000000 <__ffssi2>:
   0:   b508            push    {r3, lr}
   2:   2300            movs    r3, #0
   4:   2800            cmp     r0, #0
   6:   d002            beq.n   e <__ffssi2+0xe>
   8:   f7ff fffe       bl      0 <__ctzsi2>
   c:   1c43            adds    r3, r0, #1
   e:   1c18            adds    r0, r3, #0
  10:   bc08            pop     {r3}
  12:   bc02            pop     {r1}
  14:   4708            bx      r1

だからどこへいくねん。。。

さらに追いかけてみると。。。

00000000 <__ctzsi2>:
   0:   e2601000        rsb     r1, r0, #0
   4:   e0000001        and     r0, r0, r1
   8:   e3a0101c        mov     r1, #28
   c:   e3500801        cmp     r0, #65536      ; 0x10000
  10:   21a00820        lsrcs   r0, r0, #16
  14:   22411010        subcs   r1, r1, #16
  18:   e3500c01        cmp     r0, #256        ; 0x100
  1c:   21a00420        lsrcs   r0, r0, #8
  20:   22411008        subcs   r1, r1, #8
  24:   e3500010        cmp     r0, #16
  28:   21a00220        lsrcs   r0, r0, #4
  2c:   22411004        subcs   r1, r1, #4
  30:   e28f2008        add     r2, pc, #8
  34:   e7d20000        ldrb    r0, [r2, r0]
  38:   e0400001        sub     r0, r0, r1
  3c:   e12fff1e        bx      lr

あー、なんか追い詰めきれないです。。。

  • 知らないインストラクションばっかになってる。。。単語帳引きながら英語読んでるレベル。。。
  • 32bit長になっちゃってるけどなんかARM modeになっているのでは
  • objdumpにもうちょっと頑張ってもらわないといけないのではないだろうか。。。

明日以降もうちょっと追ってみます。。。でも、対象をもうちょっとモダンなアーキテクチャに変えちゃうかも。。。