貧乏人のラズパイ(もどき)
Windows7アップデートの嫌がらせが終ったと思ったら、今度は10にすると、 Windows 10のLinux/Ubuntu互換環境でbashを使う こんな楽しい事が出来るとよ、あざ笑うような 記事が流れている。腹立つ事に64Bit版のみですって、今時32Bitを選んで入れる 人も居まい。ああ、古い7ユーザーを締め出す作戦ね。
そんな事で、 Windowsコマンドプロンプトの入門から使いこなしまでの記事が気になった。
Git for Windows を入れると、gitだけではなく、MSYSの新しいのも付いてくるのね。 今入れてる古いMSYSを置き換えるのには良い選択かもね。
いやいや、Windowsと親和する事は止しておこう。なるべく、お近づきにならない 方が幸せってもんです。
Windows10にウブを組み込むを、余計な穴を持ち込む事になるらしい。それに、 組み込むウブが今の所、古いLTSに限られているってどうよ。そこん所が、仮に 自由奔放にどうぞってなっても、間にWinが挟まるって気持ち悪い。
VMWAREとかVBOX上のゲストOSみたいに、Winからきちんと隔離されてる方が、 絶対にトラブルは少ないと思うよ。
やっても、ゲスト側からsmbでマウントして、ファイルを読み書きするぐらいに 留めておいた方が安心、と思うぞ。
FreeBSDではARM出来るか?
変な日本語だ。ARM出来るって、どゆ事? 作るんじゃなくて、使う方ね。 ラズパイって言ったら、Linuxを入れてPythonを動かすってのが定番だけど 、それじゃPCでやるのの何ら変わらない。
そう言っちゃ失礼だろう。I/Oポートが開放されてて、自由に叩けるってのが 売りなんですから。パソコンでそれをやろうとすると、えらく大変になる。
で、ラズパイと言うハードは、色々と付属品やらが必要になり、秋田時に ごみになっちゃうのが心配。そんな理由で、去年、ARMのボードの シュミレータである、qemuを動かした。あの時はLinux上でやったけど、 BSDでは、どうよ? 同じ事が出来るのか? 調べてみよう。 (1年毎の、同じような企画を、ちょっと角度を変えてやるのは、某雑誌 そっくりです。)
$ pkg search qemu aqemu-0.8.2_1 Qt 4 based Qemu frontend kqemu-kmod-devel-1.4.0.p1_5 Kernel Accelerator for QEMU CPU Emulator (development version) qemu-2.5.1.1 QEMU CPU Emulator qemu-cheri-0.d20160624 QEMU emulator with CHERI CPU support qemu-cheri128-0.d20160624 QEMU emulator with CHERI CPU support (128-bit) qemu-cheri128m-0.d20160624 QEMU emulator with CHERI CPU support (128-bit, magic compression) qemu-devel-2.6.0_1 QEMU CPU Emulator - development version qemu-launcher-1.7.4_6 GTK front-end to Qemu
128-Bitって言う、不穏なやつは何でしょ? それはさておき、qemu-userモードって のが無いなあ。あれはLinuxの特技なのか。
CHERI CPUって何かと思って調べてみたら、 Capability Hardware Enhanced RISC Instructions (CHERI)に行き着いた。始まりはいつも英国からですか。 面白いなあ。
で、user modeはLinuxでしか動かないはずなんだけど、portsの下を見ると、 qemu-user-staticなんてのが用意されてたよ。
* User mode emulation (Linux host only). In this mode, QEMU can launch Linux processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator or to ease cross-compilation and cross-debugging. As QEMU requires no host kernel patches to run, it is very safe and easy to use. This is a slave port of emulators/qemu-sbruno to build only static bsd-user targets named like qemu-mips-static. While still being experimental people have already built quite a few armv6/mips/mips64 packages using these and e.g. poudriere. Some notes are also here:
http://wiki.freebsd.org/QemuUserModeHowTo
世の中には、とんがった人が居るなあ。おまいら、頑張りすぎだよ。いいや、もっと やれ!
開発環境としては、クロスコンパイラーとかgdbが用意されてた。世の趨勢として arm版が一番充実してるのは、言うまでもない。
ここまではよい。何でも有りを売りにしてる、FreeBSDなんだから。他のBSDではどうよ。 他のBSDと言っても、NetBSDは、世界CPU遺産にオイラー的には推薦したいぐらいだから、おのずと、OpenBSDがターゲットになろう。
おっと、NetBSDに対して失礼な事言っちゃったな。OpenBSDの本家はNetBSDですから。 本家の方も、色々やってる人が居ましたよ。 qemuでNetBSD/earmを体験する
OpenBSDに有れば、メジャーなものと認定して良いだろう。
OpenBSDではARM出来るか?
調べてみた。CATファイルは、パッケージと提供されてるリスト。これを一度 作っておくと後が楽なんで、OpenBSDをインストール時に手間をかけている。
[ob: ~]$ grep arm CAT arm-1.4.5.0p1.tgz arm-elf-binutils-2.20p1.tgz arm-elf-gdb-7.1p2.tgz arm-none-eabi-binutils-2.25.tgz arm-none-eabi-gcc-linaro-4.9.2015.03.tgz arm-none-eabi-gdb-7.9.1p1.tgz arm-none-eabi-newlib-2.2.0.1.tgz armagetronad-0.2.8.3.3.tgz :
候補が色々出てきたので、ports/develの下を覗いて、どんなものが入るか 一応確認。gccを入れると、必要な物がつられて入ってくる。
# pkg_add arm-none-eabi-gcc-linaro quirks-2.197 signed on 2016-02-24T23:26:39Z arm-none-eabi-gcc-linaro-4....:mpfr-3.1.0.3p0: ok arm-none-eabi-gcc-linaro-4....:libmpc-0.9p1: ok arm-none-eabi-gcc-linaro-4....:arm-none-eabi-binutils-2.25: ok arm-none-eabi-gcc-linaro-4.9.2015.03: ok
# pkg_add arm-none-eabi-gdb quirks-2.197 signed on 2016-02-24T23:26:39Z Can't install arm-none-eabi-gdb-7.9.1p1 because of conflicts (gdb-7.10.1) --- arm-none-eabi-gdb-7.9.1p1 ------------------- Can't install arm-none-eabi-gdb-7.9.1p1: conflicts
続いてarm用のgdbを入れようとしたら、i386用のgdbとコンフリクトするってんで 拒否された。後回しにしよう。libcの代替品を入れる。
# arm-none-eabi-newlib-2.2.0.1.tgz ksh: arm-none-eabi-newlib-2.2.0.1.tgz: not found # pkg_add arm-none-eabi-newlib-2.2.0.1.tgz quirks-2.197 signed on 2016-02-24T23:26:39Z arm-none-eabi-newlib-2.2.0.1: ok
そして、qemuを入れる。
# pkg_add qemu quirks-2.197 signed on 2016-02-24T23:26:39Z qemu-2.2.1p19:libnfs-1.9.8: ok qemu-2.2.1p19:libssh2-1.6.0: ok qemu-2.2.1p19:atk-2.18.0: ok qemu-2.2.1p19:jasper-1.900.1p4: ok qemu-2.2.1p19:shared-mime-info-1.5: ok qemu-2.2.1p19:gdk-pixbuf-2.32.3: ok qemu-2.2.1p19:libcroco-0.6.11: ok qemu-2.2.1p19:librsvg-2.40.13: ok qemu-2.2.1p19:hicolor-icon-theme-0.15: ok qemu-2.2.1p19:gtk-update-icon-cache-3.18.7: ok qemu-2.2.1p19:gnome-icon-theme-3.12.0p3: ok qemu-2.2.1p19:gnome-icon-theme-symbolic-3.12.0p2: ok qemu-2.2.1p19:gtk+2-2.24.29: ok qemu-2.2.1p19:vte-0.28.2p17: ok qemu-2.2.1p19:libusb1-1.0.20: ok qemu-2.2.1p19:libiscsi-1.15.0p0: ok qemu-2.2.1p19:dtc-1.4.1: ok qemu-2.2.1p19: ok Look in /usr/local/share/doc/pkg-readmes for extra documentation.
音をちゃんと鳴らずんだか、qemu用のコントロールターミナル用だか知らないけど 関係者が沢山付いてきた。こういうの選択的に入れられるといいのにと何時も 思っちゃうぞ。
最後に衝突回避で導入を拒否されたgdb。パッキングリストをarm用とi386用で 見比べてみたら、本体はしっかり別の名前になってるのに、shareの下とかに 入るものが、同名になってた。こういう理由で混ざるのを嫌ったんだな。
i386用を削除。arm用をインストール。本体だけを/tmpに退避。arm用を削除。 i386用のパッケージをインストール。最後に /tmpに退避したarm用gdbを 所定の位置に移動。まあ、こうして、美しいパッケージ管理が崩れて行くの です。どうせ、半年経つと、新しいOSから入れなおすんで、多少の事は、 見なかった事にします。
gdbでarmのシュミレート
arm用のgdbを入れた時、runも付いてきた。これはgdbが用意してくれるシュミレータ だろうね。動くかやってみる。ソースは、確かgdbのシュミレータの所に有ったやつと 記憶してる。(巻末に添付)
[ob: arm-asm]$ make arm-none-eabi-as hello.s -o z.o arm-none-eabi-ld z.o arm-none-eabi-run a.out Hello, world.
[ob: arm-asm]$ ./a.out ./a.out[1]: syntax error: `^A$@4・ス$B^B^B^E4' unexpected [ob: arm-asm]$ file a.out a.out: ELF 32-bit LSB executable, ARM, version 1
Linuxでは、単独で動いたけど、そういう支援(qemu-user-static ?)が無い 環境では、シュミレータが必要って事だな。
[ob: arm-asm]$ arm-none-eabi-gdb a.out : This GDB was configured as "--host=i386-unknown-openbsd5.9 --target=arm-none-eabi". Type "show configuration" for configuration details. : Reading symbols from a.out...(no debugging symbols found)...done. (gdb) target sim Connected to the simulator. (gdb) load Loading section .text, size 0x58 vma 0x8000 Start address 0x8000 Transfer rate: 704 bits in <1 sec. (gdb) run Starting program: /home/sakae/src/arm-asm/a.out Hello, world. [Inferior 1 (process 42000) exited normally]
こういう手間をかけない為に、runが有るのだな。
[ob: arm-asm]$ arm-none-eabi-run -d -t a.out pc: 8000, nop ; (mov r0, r0) pc: 8004, bl 0x00000014 pc: 8018, movw r4, #32776 ; 0x8008 pc: 801c, movt r4, #0 pc: 8020, mov r0, #3 pc: 8024, mov r1, r4 pc: 8028, svc 0x00123456 pc: 802c, add r4, r4, #1 pc: 8030, sub r3, r3, r3 pc: 8034, ldrb r5, [r4, r3] pc: 8038, teq r5, #0 pc: 803c, bne 0xffffffe4 pc: 8020, mov r0, #3 pc: 8024, mov r1, r4 pc: 8028, svc 0x00123456 : pc: 8028, svc 0x00123456 Hello, world. pc: 802c, add r4, r4, #1 pc: 8030, sub r3, r3, r3 pc: 8034, ldrb r5, [r4, r3] pc: 8038, teq r5, #0 pc: 803c, bne 0xffffffe4 pc: 8040, mov r0, #24 pc: 8044, ldr r1, [pc, #8] ; 0x00000010 pc: 8048, svc 0x00123456
こんな事も出来たんですねぇ。段々思い出してきたぞ。
ふと、このアセンブラコードに、入力するシステムコールが無いか気になった。 確か、元はgdb/sim/armの中に有るソースで実現されてたはず。広い空き地の有る ウブの/tmpに展開して確認。armos.cが担当してた。
switch (state->Reg[0]) { case -1: /* This can happen when a SWI is interrupted (eg receiving a ctrl-C whilst processing SWIRead()). The SWI will complete returning -1 in r0 to the caller. If GDB is then used to resume the system call the reason code will now be -1. */ return TRUE; /* Unimplemented reason codes. */ case AngelSWI_Reason_ReadC: case AngelSWI_Reason_TmpNam: case AngelSWI_Reason_System: case AngelSWI_Reason_EnterSVC: default: state->Emulate = FALSE; return FALSE;
なんか、入力系は、問題有って駄目みたい。強引に
case AngelSWI_Reason_WriteC: { char tmp = ARMul_SafeReadByte (state, addr); (void) sim_callback->write_stdout (sim_callback, &tmp, 1); OSptr->ErrorNo = sim_callback->get_errno (sim_callback); break; }
を手本に改造してみたけど、思い通りの動きをしなかったぞ。もう、アセンブラ直は 諦めましょ。ああ、それから、runのオプションが微妙に変わってて、-dなんて、 ウブのそれには無かったぞ。
Angelを探していた時に見つけたのを、記念に記録しておく。
DebugMonハンドラ再び ── newlib向けシステムコールの実
newlibを使ってみる
アセンブラだけじゃ体力と言うか知力が足りなくなるので、C語をやってみる。 組み込み用にnewlibが使えるようにgccが構築されてるから。(glibcは大き過ぎて 使えない/使えない)
#include <stdio.h> char buff[256]; int main(){ printf("Hello ARM, input pls.\n"); fgets(buff,255,stdin); fputs(buff,stdout); }
[ob: hello]$ arm-none-eabi-gcc -g hello.c [ob: hello]$ arm-none-eabi-gdb -q a.out Reading symbols from a.out...done. (gdb) target sim Connected to the simulator. (gdb) load Loading section .init, size 0x18 vma 0x8000 Loading section .text, size 0x3a34 vma 0x8018 Loading section .fini, size 0x18 vma 0xba4c Loading section .rodata, size 0x1c vma 0xba64 Loading section .ARM.exidx, size 0x8 vma 0xba80 Loading section .eh_frame, size 0x4 vma 0xba88 Loading section .init_array, size 0x4 vma 0x1ba8c Loading section .fini_array, size 0x4 vma 0x1ba90 Loading section .jcr, size 0x4 vma 0x1ba94 Loading section .data, size 0x958 vma 0x1ba98 Start address 0x8120 Transfer rate: 139136 bits in <1 sec. (gdb) b main Breakpoint 1 at 0x8260: file hello.c, line 6.
出来た物を動かすのは、runを経由するかgdbのシュミレーションモードを 使うとな。
(gdb) run Starting program: /home/sakae/hello/a.out Breakpoint 1, main () at hello.c:6 6 printf("Hello ARM, input pls.\n"); (gdb) s puts (s=0xbe90 "Hello ARM, input pls.") at ../../../.././newlib/libc/stdio/puts.c:138 138 ../../../.././newlib/libc/stdio/puts.c: No such file or directory. (gdb) s _puts_r (ptr=0x1, s=0x1ffff8 "\344\276\001") at ../../../.././newlib/libc/stdio/puts.c:80 80 in ../../../.././newlib/libc/stdio/puts.c (gdb) c Continuing. Hello ARM, input pls. Hoge Funga Hoge Funga [Inferior 1 (process 42000) exited normally]
残念ながらnewlibのソースが入っていないので、見る事は出来ないけど、 printfがputsに置き換えられているぐらいの事は、見て取れる。 後は、昔買ったハロワ本を開いて見れば良いのでしょうか。
見たら、armのシュミレーション環境の作り方とnewlibについて言及されてた。 シュミレーション環境を作ると、newlibの中まで、gdbで潜って行けるとな。 gccやらgdbやらnewlibなんて言うのをコンパイルしてる。
さぞかしコンパイルに時間がかかるだろうと覚悟してFreeBSDに舞台を移してから取り掛かったら、何と 1時間弱で環境が出来た。
$ du -sh /home/sakae/cross2/ 1.1G /home/sakae/cross2/ $ du -sh /usr/local/cross2/ 169M /usr/local/cross2/
大事なソース類が入っているから絶対消すなが、容量1.1G。バイナリ類は、169Mか。 これだけで、syscallが発せられる所を観察出来るって素敵。
$ PATH=/usr/local/cross2/bin:$PATH $ arm-elf-gcc -g hello.c $ arm-elf-run a.out Hello ARM, input pls. Good env ! Good env !
$ arm-elf-gdb a.out GNU gdb (GDB) 7.3.1 : This GDB was configured as "--host=i386-unknown-freebsd10.2 --target=arm-elf". Reading symbols from /usr/home/sakae/hello/a.out...done. (gdb) target sim Connected to the simulator. (gdb) load Loading section .init, size 0x1c vma 0x8000 : Loading section .data, size 0x9d0 vma 0x19b44 Start address 0x8110 Transfer rate: 338080 bits in <1 sec. (gdb) b main Breakpoint 1 at 0x8254: file hello.c, line 6. (gdb) run Starting program: /usr/home/sakae/hello/a.out Breakpoint 1, main () at hello.c:6 6 printf("Hello ARM, input pls.\n"); (gdb) s printf (fmt=0x19b5c "/usr/home/sakae/hello/a.out") at ../../../../../../../toolchain/gcc-3.4.6/newlib/libc/stdio/printf.c:48 48 struct _reent *ptr = _REENT;
今度は、ちゃんと潜れる。
hello.s
# hello.s run on gdb sim mode or run cmd. .macro invalid # This is "undefined" but it's not properly decoded yet. .word 0x07ffffff # This is stc which isn't recognized yet. stc 0,cr0,[r0] .endm .global _start _start: nop bl skip_output hello_text: .asciz "Hello, world.\n" .p2align 2 skip_output: movw r4, #:lower16:hello_text movt r4, #:upper16:hello_text output_next: # Output a character mov r0,#3 mov r1,r4 swi #0x123456 # Load next character, see if done. add r4,r4,#1 sub r3,r3,r3 ldrb r5,[r4,r3] teq r5,#0 bne output_next done: mov r0,#0x18 ldr r1,exit_code swi #0x123456 # If that fails, try to die with an invalid insn. invalid exit_code: .word 0x20026
etc
感の良い人なら、既にお気付きと思うが、オイラーの駄文は書置きしてる。
今、その原稿を溜めておくリングバッファーがFULLになっており、先行記事が 執筆出来ない状態なんだ。よって、これから暫くの間は、記事のフラッシュを 進めるため、更新頻度を上げる事にします。
記事が底を着いたら、頻度を元に戻す事にします。