dc
女房にせかされて、ipad用のカバーを買いに行ってきた。ipadを買った時に 同時に購入したものだ。イタリア製とかで、6000円ぐらいしたと思う。
3年半の酷使で、端の方はボロボロ。かっこ良かった伊達なカバーも今や みすぼらしいものに成り下がってしまったから。貧乏臭いとぬかす。 どうせ、貧乏だから分相応と思うんだけど、変な所に気を使う。 (オイラーは、ボロは着てても、心は錦ですから、女房とは対極に位置します)
ipadもあれから数度の改定を経て、カバーも2016年式とか2014年式とか 言って売ってるのね。脇にすまなそうに、ipad Air2対応とかPro対応とか 書いてある。
もう古いのは売っていないのか? 店員さんに持って行ったipadを見せると 良く使いこまれましたねぇと感心された。その店員さんも同じカバーを 使っていたとか。隅っこの方に、申し訳なさそうに、2012年式ってやつが 置いてあり、これが昔のipadに対応するとの事。
色も形も選択の余地無し。エレコムさん、昔のユーザーも大事にしてよね。 でも、当時と比べて半額の値段で買えたから、佳しとするか。
ついでに、バッテリー交換の窓口電話を教わってきた。0120-277-535
電池の有るうちに交換しておこうと連絡を取ってみた。まず診断をしましょって 言われて、プライバシーの所に有る、アプルの診断をクリック。
ああ、その前にシリアルを教えろと言われたな。やっぱり、フォネテックス コードのやり取りが有ったぞ。アプルのフォネティクス表現は国名なんか。 ブラジルのBとかフランスのFとかイングランドのEとかね。 地名のモナコとかニューヨークとかシカゴとかやっちゃうと、昔のフォント名 みたいだから、国名に進化させたんだな。ああ、モナコってフォント好きだったよ。 オオサカは唯一の漢字フォントだったと、昔を思い出したぞ。
で、アプルケアのおねーさんの言う事には、まだ電池はもりもりしてるんで 交換の必要はありませんです、との事だった。もう少し現状のまま使ってみるぞ。
数日して、アンケートの依頼メールがやってきた。今後のサポート向上に 役立てますから、是非ご協力を、ですって。あんなアンケートで、向上するの かね?
ああ、電話した時に、一発目で製品毎に振り分けられるんだけど、一位が iphone、二位がwatch、三位がipad、四位がmacだったよ。アプルの優先順位が 垣間見られて、興味深いな。
Device tree
前回やって失敗した、armv7版のOpenBSDをqemuから動かす企み、まだ、残骸が 残っているので、検証しておくか。
対象のボードがどうなってるのってのは、Device Treeで表現して、それを 起動時に与えるって事だった。その方式により、カーネルは単一な物を使い 回せる事になった。
そのデバイスツリーを取り出してきて、逆変換すれば、ハードの構成が分かる はず。
[ob: arm]$ fdtdump sun4i-a10-cubieboard.dtb >cubie.dts [ob: arm]$ wc cubie.dts 1234 3782 49340 cubie.dts
1200行余りで、カーネル側が知りたいハードウェア情報を記述出来ているとな。 それも、ボードに載っているかも知れない全ての石を網羅してるのかな。 物は試し、ソースを眺めてみろ。
/dts-v1/; // magic: 0xd00dfeed // totalsize: 0x62a5 (25253) // off_dt_struct: 0x38 // off_dt_strings: 0x5e6c // off_mem_rsvmap: 0x28 // version: 17 // last_comp_version: 16 // boot_cpuid_phys: 0x0 // size_dt_strings: 0x439 // size_dt_struct: 0x5e34 / { #address-cells = <0x00000001>; #size-cells = <0x00000001>; interrupt-parent = <0x00000001>; model = "Cubietech Cubieboard"; compatible = "cubietech,a10-cubieboard", "allwinner,sun4i-a10"; chosen { #address-cells = <0x00000001>; #size-cells = <0x00000001>; ranges; stdout-path = "serial0:115200n8"; framebuffer@0 { compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0-hdmi"; clocks = <0x00000002 0x00000001 0x00000003 0x00000024 0x00000003 0x0000002b 0x00000003 0x0000002c 0x00000004 0x0000001a>; status = "disabled"; }; framebuffer@1 { compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_fe0-de_be0-lcd0-hdmi";
これ、冒頭付近のもの。chosenって、日本語に約すと、選んでちょって事。lcd用の フレームバッファーとかhdmi用のフレームバッファーとかが有るんだな。 statusがdisabledになってるんで、hdmiは選ばれていない(ハード的に搭載されてない) って事か。
memory { device_type = "memory"; reg = <0x40000000 0x80000000>; }; cpus { #address-cells = <0x00000001>; #size-cells = <0x00000000>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a8"; reg = <0x00000000>; clocks = <0x00000005>; clock-latency = <0x0003b9b0>; operating-points = <0x000f6180 0x00155cc0 0x000dea80 0x00149970 0x000d2f00 0x0013d620 0x00098580 0x001312d0>; #cooling-cells = <0x00000002>; cooling-min-level = <0x00000000>; cooling-max-level = <0x00000003>; cpu-supply = <0x00000006>; linux,phandle = <0x00000009>; phandle = <0x00000009>; }; };
メモリーとかcpuの宣言。載ってる石の種別とかが分かる。linux用の宣言て何だろう。 石の特性までLinuxはちょっかい出してるんか? それじゃ、クリーンな石じゃなくなっちゃうじゃん。
serial@01c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x00000400>; interrupts = <0x00000001>; reg-shift = <0x00000002>; reg-io-width = <0x00000004>; clocks = <0x00000034 0x00000010>; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <0x00000035>; };
これはシリアルの宣言が。コントロールするためのレジスターがどのアドレスに 割付られているか、OSが知る必要があるんで、こういう風に定義されてるのね。 まさに、ハードとソフトの接点だな。
Linuxのソースツリーを覗くと、ラズパイ用の定義も載ってるかな。載ってたら、 それをぱくってきて差し替えちゃえば、理論的にはOpenBSDも動くはず。 まだ、ラズパイでOpenBSDを動かしたって報告は無いから、動けば世界初の 快挙になるでしょう。qemuなんかにしがみ付いていないで、ハード買えよ >俺。
Debianに入れてるカーネルを覗いてみた。
sakae@debian:/usr/src/linux-source-3.16/arch/arm/boot/dts$ ls -l bcm283* -rw-r--r-- 1 root root 853 3月 2 2016 bcm2835-rpi-b.dts -rw-r--r-- 1 root root 3877 3月 2 2016 bcm2835.dtsi
ざっと見、そのままでは使うの難しそう。それより、bcm2836とかは、何処に 有るんだろう? Debianの拡張を施したソースという触れ込みだから、ここに 有ってもおかしくないと思うんだけど。
FreeBSDにもdtsファイルが置いてあった。そもそもDevice Treeの発想って NetBSDに遡るんではなかろうか。色々な石、アークテクチャなシステムを NetBSDで侵食したい。
それぞれ用にOSを書き換えていたら、効率よく征服出来ない。どうしよう? OSは一つにしておいて、それぞれに異なるデバイスの差異は、別ファイルに 書いておけばいいじゃん。そうすれば、そのファイルを差し替えるだけで 新しいものに対応する。
/sys/boot/fdt/dts/armとか/sys/gnu/dts/armに色々堆積されてたぞ。 中を探ってみたけど、bcm2836系は無かった。何かトリックが有って、2836系に 対応させているのだろうか?
dc 使い
直流電源の話じゃないよ。
NAME dc – desk calculator SYNOPSIS dc [-x] [-e expression] [file] DESCRIPTION dc is an arbitrary precision arithmetic package. The overall structure of dc is a stacking (reverse Polish) calculator i.e. numbers are stored on a stack. Adding a number pushes it onto the stack. Arithmetic operations pop arguments off the stack and push the results. See also the bc(1) utility, which is a preprocessor for dc providing infix notation and a C-like syntax which implements functions and reasonable control structures for programs. The options are as follows:
unixで計算機と言ったら、普通の人はbcを選択するけど、forth好きな人はdcを 選択します。
[ob: ~]$ dc 123 d * p 15129 1111111111111111111111111111111111 d * p 1234567901234567901234567901234567654320987654320987654320987654321 q
上記は簡単な使用例。入力した数値を2乗した結果を表示する。lispよろしく 無限精度演算が可能。勿論、少数点付き数値の演算も出来る。(1.2e2みたいな E表現の浮動小数点はだめだけど)
[la1+dsa*pla10>y]sy 0sa1 lyx 1 2 6 24 120 720 5040 40320 362880 3628800
こんな風に、マクロを使って、1から10までの階乗も計算出来るようだ。 どういう仕組みか、解析してみる。
括弧内に文字列を書く。この文字列は、マクロとして通常は使う。 文字列は、スタックに置かれる。srで、その文字列を取り出し、レジスタrに 保存する。
0sa1で、0をaレジの保存。1をpush。スタックの内容をモニターするには、f コマンドが便利。 lyx は、yレジスタ(最初に定義したマクロ)を、スタックに積む。xで スタックから値を取り出して、マクロを実行。
問題はマクロの中身。laで、aレジスタから値(0が入っているはず)を取り出し、 1をpush。足し算、dで複製、値をaレジスタに保存、掛け算して、結果を表示。 レジスタaからスタックに呼び戻し、10>yは、10と比較して、 もともとのスタックの先頭が大きい場合、レジスタy(マクロが入っている)を 実行。
図に描いてみないと、理解出来ないな。いや、そんな事は無いぞ。yレジスタは マクロの保存。aレジスタは、nの階乗のnを保存しとく役割。マクロを呼び出す時の スタックトップには、結果の初期値が入っている。 こういう条件で、マクロを追跡すれば、何ら難しい事は無い。なお、一点注意 しなければいけないのは、saとかでレジスタにtopの値をセーブすると、topの 値は消費されて無くなってしまう事。主戦場は常にスタックに有りだ。
dc の動きを追う
例によってどう動くか、追ってみる。ソースは、/usr/src/usr.bin/dcに鎮座してる。 emacsで追えるように、Makefileに小細工(CFLANGSを追加)
# cat Makefile # $OpenBSD: Makefile,v 1.3 2015/10/10 19:28:54 deraadt Exp $ PROG= dc SRCS= main.c dc.c bcode.c inout.c mem.c stack.c COPTS+= -Wall LDADD= -lcrypto DPADD= ${LIBCRYPTO} CFLAGS+= -O0 -gdwarf-2 -g3 .include <bsd.prog.mk>
そしてmakeする。出来上がったdcは適当な所へ移動させとく。
# make cc -O2 -pipe -O0 -gdwarf-2 -g3 -Wall -Werror-implicit-function-declaration -c main.c cc -O2 -pipe -O0 -gdwarf-2 -g3 -Wall -Werror-implicit-function-declaration -c dc.c cc -O2 -pipe -O0 -gdwarf-2 -g3 -Wall -Werror-implicit-function-declaration -c bcode.c cc -O2 -pipe -O0 -gdwarf-2 -g3 -Wall -Werror-implicit-function-declaration -c inout.c cc -O2 -pipe -O0 -gdwarf-2 -g3 -Wall -Werror-implicit-function-declaration -c mem.c cc -O2 -pipe -O0 -gdwarf-2 -g3 -Wall -Werror-implicit-function-declaration -c stack.c cc -o dc main.o dc.o bcode.o inout.o mem.o stack.o -lcrypto # cp dc /tmp
単なる計算器なのに、暗号ライブラリィーを使うって、どゆ事? manを見ていたら、答えが出てた。
HISTORY The dc command first appeared in Version 6 AT&T UNIX. A complete rewrite of the dc command using the bn(3) big number routines first appeared in OpenBSD 3.5.
由緒あるコマンドだけど、ある時、無限数を扱えるbn(3)を導入して、書き直したよ。 そのルーチンは、opensslの一部。だから、暗号に関わってくるとな。 あれ、無限精度と言ったら、昔やったな。確かgmpだったか。但し、あちらは、 積極的にライブラリィーを入れないと使えないし、GPLはいやだって拘りが BSD界隈には有るのよね。
sakae@ub:~$ ldd /usr/bin/dc linux-gate.so.1 => (0xb77ff000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7638000) /lib/ld-linux.so.2 (0x800c7000) sakae@ub:~$ echo '11111111111111111111111111111111d*p' | dc 123456790123456790123456790123454320987654320987654320987654321
ウブではどうかと調べてみたら、libcしか取り込んでいない。でも、BigNumが ちゃんと扱えている。何か手がかりが掴めるかとnmとかstringsしたけど、 手がかりになりそうなものは全て削除されてた。つまんないOSだな。
そんじゃ、例のごとくgdbで追ってみる。与えるデータは、ファイルに書いた 5d*p と言うもの。動きを知るには、これぐらいが適当かな。
起動すると、初期化の後、evalへ飛んでくる素直な作り。
(gdb) bt #0 eval () at bcode.c:1712 #1 0x16c95b91 in dc_main (argc=1, argv=0xcf7e3a48) at dc.c:103 #2 0x16c957fa in main (argc=2, argv=0xcf7e3a44) at main.c:33
このevalの中に文字応じたジャンプテーブルが用意されてて、細かい処理は それに委ねているようだ。
=> if (0 <= ch && ch < UCHAR_MAX) (*jump_table[ch])();
ちょっと先へ進めると、掛け算が出てきた。
(gdb) p/c ch $7 = 42 '*' (gdb) s 1736 (*jump_table[ch])();
static void bmul(void) { struct number *a, *b; struct number *r; => a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bmul_number(r, a, b, bmachine.scale); push_number(r); free_number(a); free_number(b); }
典型的な事をやってるな。相手が無限精度数字なんで、それなりの対応で、 結果を返す場所を用意して、掛け算実施、いらなくなったエリアを開放とか してる。肝心の掛け算ルーチンは、
void bmul_number(struct number *r, struct number *a, struct number *b, u_int scale) { BN_CTX *ctx; /* Create copies of the scales, since r might be equal to a or b */ u_int ascale = a->scale; u_int bscale = b->scale; u_int rscale = ascale + bscale; ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_mul(r->number, a->number, b->number, ctx)); BN_CTX_free(ctx); r->scale = rscale; if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) normalize(r, max(scale, max(ascale, bscale))); }
ここで出てきてるスケールは、少数点以下の桁数。内部は整数で扱ってて、どこに 少数点が有るかを、別管理してるのだな。
ついでに、ジャンプテーブルを見ておくと
static const struct jump_entry jump_table_data[] = { { ' ', nop }, { '!', not_compare }, { '#', comment }, { '%', bmod }, { '(', less_numbers }, { '*', bmul }, { '+', badd }, { '-', bsub }, { '.', parse_number }, { '/', bdiv }, { '0', parse_number }, { '1', parse_number }, { '2', parse_number }, : { 'v', bsqrt }, { 'x', eval_tos }, { 'z', stackdepth }, { '{', lesseq_numbers }, { '~', bdivmod } };
こんな分かり易い風になってた。
Linuxではどうよ
今までソースを見るのは主としてBSD系にしてた。だって、そこにソースが有るなら 見るに限るってね。でも、これ直交性が無いよね。
リナ系でソース読むのはどうしたらいい? Debian 管理者ハンドブック こんな素晴らしいハンドブックが有ったぞ。そして、こんな例も、 DebianやUbuntuで公式パッケージのソースをダウンロード/ビルドする
まずは、ソースのお取り寄せ
sakae@debian:~/testme$ apt-get source dc Reading package lists... Done Building dependency tree Reading state information... Done Picking 'bc' as source package instead of 'dc' NOTICE: 'bc' packaging is maintained in the 'Git' version control system at: git://anonscm.debian.org/collab-maint/bc.git Need to get 387 kB of source archives. Get:1 http://ftp.jp.debian.org/debian/ jessie/main bc 1.06.95-9 (dsc) [2906 B] Get:2 http://ftp.jp.debian.org/debian/ jessie/main bc 1.06.95-9 (tar) [361 kB] Get:3 http://ftp.jp.debian.org/debian/ jessie/main bc 1.06.95-9 (diff) [23.3 kB] Fetched 387 kB in 1s (256 kB/s) gpgv: keyblock resource `/home/sakae/.gnupg/trustedkeys.gpg': file open error gpgv: Signature made Sat Jun 14 19:48:44 2014 JST using RSA key ID 4A11C97A gpgv: Can't check signature: public key not found dpkg-source: warning: failed to verify signature on ./bc_1.06.95-9.dsc dpkg-source: info: extracting bc in bc-1.06.95 dpkg-source: info: unpacking bc_1.06.95.orig.tar.gz dpkg-source: info: unpacking bc_1.06.95-9.debian.tar.xz dpkg-source: info: applying 01_typo_in_bc.diff dpkg-source: info: applying 02_hyphens_as_minus_in_man.diff dpkg-source: info: applying 03_array_initialize.diff dpkg-source: info: applying 04_info_dircategory.diff dpkg-source: info: applying 05_notice_read_write_errors.diff dpkg-source: info: applying 06_read_dcrc.diff dpkg-source: info: applying 07_bc_man.diff
どんな物がやって来たか、一応確認。dcを頼んだのにbcがやってきた。 bcとdcは対になってるんか。
sakae@debian:~/testme$ ls bc-1.06.95 bc_1.06.95-9.dsc bc_1.06.95-9.debian.tar.xz bc_1.06.95.orig.tar.gz
もう、ソースは展開されてた。
sakae@debian:~/testme$ cd bc-1.06.95/ sakae@debian:~/testme/bc-1.06.95$ ls AUTHORS FAQ README configure doc COPYING INSTALL Test configure.in h COPYING.LIB Makefile.am aclocal.m4 dc install-sh ChangeLog Makefile.in bc debian lib Examples NEWS config.h.in depcomp missing
dcをコンパイルするのに必要な関係者を召還する。
sakae@debian:~/testme/bc-1.06.95$ sudo apt-get build-dep dc Reading package lists... Done Building dependency tree Reading state information... Done Picking 'bc' as source package instead of 'dc' The following NEW packages will be installed: bison debhelper flex gettext intltool-debian libbison-dev libfl-dev libreadline-dev libreadline6-dev libtinfo-dev libunistring0 po-debconf 0 upgraded, 12 newly installed, 0 to remove and 2 not upgraded. Need to get 4466 kB of archives. After this operation, 13.6 MB of additional disk space will be used. : Setting up libreadline6-dev:i386 (6.3-8+b3) ... Setting up libreadline-dev:i386 (6.3-8+b3) ... Processing triggers for libc-bin (2.19-18+deb8u4) ...
ソース内で、コンパイル開始
sakae@debian:~/testme/bc-1.06.95$ dpkg-buildpackage -b -uc : dpkg-deb: building package `dc' in `../dc_1.06.95-9_i386.deb'. dpkg-genchanges -b >../bc_1.06.95-9_i386.changes dpkg-genchanges: binary-only upload (no source code included) dpkg-source --after-build bc-1.06.95 dpkg-buildpackage: binary-only upload (no source included)
ソースの上の階に、パッケージが出来上がっていた。
sakae@debian:~/testme$ ls bc-1.06.95 bc_1.06.95-9_i386.changes dc_1.06.95-9_i386.deb bc_1.06.95-9.debian.tar.xz bc_1.06.95-9_i386.deb bc_1.06.95-9.dsc bc_1.06.95.orig.tar.gz
ここで、bcとdcが分離されるのね。
dc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=e51112b241e7486c253f4426620d48f3244ab9ca, not stripped
ソース内に出来上がった物は、debug出来るようにコンパイルされてた。パッケージに する時に、要らない物を全部そぎ落としているんだな。