株式会社はてなに入社しました
卒業決定しました
卒業予定者に名前があったので卒業決定です
— 八雲アナグラ (@AnaTofuZ) March 7, 2019
というわけで卒業決定しました。皆さんありがとうございます。
問題を起こすと卒業できなくなるので、主に @ymckamからセクハラで訴えられたら卒業できなくなります。
四年間の雑感は卒業式後に書く予定ですが、とりあえず4月からは琉球大学大学院理工学研究科情報工学専攻というところに進む予定です。あと2年間は確実に沖縄にいる予定なのでよろしくお願い致します。
飲み会の予定は常に募集中です。よろしくお願い致します。
mac osでPerlのビルドでld関連で死ぬ時
趣味はPerlのビルドなので、plenv経由でPerl5.28.1を入れようとしたところ以下のようなエラーが発生しました。
./miniperl -Ilib make_ext.pl DynaLoader.o MAKE="/Library/Developer/CommandLineTools/usr/bin/make" LIBPERL_A=libperl.a LINKTYPE=static CCCDLFLAGS= Generating a Unix-style Makefile Writing Makefile for DynaLoader "../../miniperl" "-I../../lib" DynaLoader_pm.PL DynaLoader.pm rm -f DynaLoader.xs cp dl_dlopen.xs DynaLoader.xs "../../miniperl" "-I../../lib" "../../lib/ExtUtils/xsubpp" -noprototypes -typemap '/Users/anatofuz/.plenv/build/1549952483.53003/perl-5.28.1/ext/DynaLoader/../../lib/ExtUtils/typemap' DynaLoader.xs > DynaLoader.xsc mv DynaLoader.xsc DynaLoader.c cc -c -fno-common -DPERL_DARWIN -mmacosx-version-min=10.14 -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -DPERL_USE_SAFE_PUTENV -Wall -Werror=declaration-after-statement -Werror=pointer-arith -Wextra -Wc++-compat -Wwrite-strings -O3 -DVERSION=\"1.45\" -DXS_VERSION=\"1.45\" "-I../.." -DLIBC="" DynaLoader.c rm -rf ../../DynaLoader.o cp DynaLoader.o ../../DynaLoader.o rm -f libperl.a /usr/local/bin/ar rc libperl.a op.o perl.o gv.o toke.o perly.o pad.o regcomp.o dump.o util.o mg.o reentr.o mro_core.o keywords.o hv.o av.o run.o pp_hot.o sv.o pp.o scope.o pp_ctl.o pp_sys.o doop.o doio.o regexec.o utf8.o taint.o deb.o universal.o globals.o perlio.o perlapi.o numeric.o mathoms.o locale.o pp_pack.o pp_sort.o caretx.o dquote.o time64.o DynaLoader.o cc -o perl -mmacosx-version-min=10.14 -fstack-protector-strong -L/usr/local/lib perlmain.o libperl.a `cat ext.libs` -lpthread -ldl -lm -lutil -lc ld: warning: ignoring file libperl.a, file was built for archive which is not the architecture being linked (x86_64): libperl.a Undefined symbols for architecture x86_64: "_PL_csighandlerp", referenced from: _main in perlmain.o "_PL_do_undump", referenced from: _main in perlmain.o "_PL_exit_flags", referenced from: _main in perlmain.o "_PL_perl_destruct_level", referenced from: _main in perlmain.o "_PL_sig_name", referenced from: _main in perlmain.o "_PL_sig_num", referenced from: _main in perlmain.o "_Perl_newXS", referenced from: _xs_init in perlmain.o "_Perl_rsignal", referenced from: _main in perlmain.o "_Perl_rsignal_state", referenced from: _main in perlmain.o "_Perl_sys_init3", referenced from: _main in perlmain.o "_Perl_sys_term", referenced from: _main in perlmain.o "_boot_DynaLoader", referenced from: _xs_init in perlmain.o "_perl_alloc", referenced from: _main in perlmain.o "_perl_construct", referenced from: _main in perlmain.o "_perl_destruct", referenced from: _main in perlmain.o "_perl_free", referenced from: _main in perlmain.o "_perl_parse", referenced from: _main in perlmain.o "_perl_run", referenced from: _main in perlmain.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [perl] Error 1 Installation failure: make at /Users/anatofuz/.plenv/plugins/perl-build/bin/perl-build line 10353. ABORT
plenvやperl-buildのエラーではない(ldなのでコンパイルが走った後のエラーである)事から、Perl自体の問題ではあると思っていたので、Perlのバグのページなどを見ていました。
(一応Mojave独自のエラーとしてはこれがあり、ヘッダーファイルをコピるdmgを実行することで回避出来るそうです)
ただbugsのページを確認していても、ld関連のバグ報告がなく、Perl入学式のslackで相談してみました。
僕以外のmojave環境では普通にビルドが通るらしく、これは...となっている時にこのエントリが発見されました。
見事にbinutilsをいれており、arが被り破滅していました。
ということで brew uninstall binutils
して強制的に解決。
その結果見事にperl 5.28.1がビルド出来ました!!!
Perl入学式の皆さん有難うございました!!! 流石にこれは訓練されてないと気づかない...!
完全にMojaveだと疑っていましたがおま環問題でした。Appleの皆さんすいません :bow:
YAPC::Tokyo2019に参加して, 踏み出せたこと
1月25日, 26日とYAPC::Tokyoに参加しました. YAPC自体はKansaiが初参加で, Okinawaではスタッフをしていた.
今回のTokyoでは, 初めてスピーカーとして出させていただき, 当日スタッフもやらせてもらった. 更に前夜祭と本編のLTも出させていただいた.本当にYAPCを楽しむことが出来た.参加者, 運営の皆様ありがとうございます.
前夜祭
スタッフをやらせていただいていたので早めに会場について, ノベルティの荷物詰めなどをしていた. 初めて実際にお会いする方が多かったが, 会場の雰囲気は非常に楽しくて, 疲れはしたが準備をする事が出来た.
前夜祭の資料は大体の枠組みは行きの飛行機と前日に書いていた. 今回は大学の卒業研究などを通して勉強していたMoarVMとNQP(Perl6の実行環境とサブセットの話)で登壇した.
NQP自体はPerl6の内部で利用されているもので, 皆さんの興味がNQPに向くか非常に不安だった. 登壇が終わったあとにid:papixさんから, 「本編に出れる」と言われた時は嬉しかったし, Twitterを見た感じ皆さんに楽しんでいただいたようで非常に良かった.
前夜祭では他にはてなインターン振りにid:cohalzさんとお会い出来たのが良かった. 思えばあの時から, YAPC::Tokyoが前を向かせて貰ったのだと思う.
本編
本編はRoom1の会場の司会などを担当していた.Twitterの中の人もしようかなと思っていたが, 資料を準備したかったのと, 写真を綺麗に取る自信があまり無かったので, Twitterはお願いしていた.
司会は本当にやりやすくて, 自由に喋る事が出来た.司会自体はそんなに上手くなかったかもしれないが, YAPCのスタッフとして関わる事が出来ていたのは嬉しかった. Okinawaの時はコアスタッフだったのだが, 精神を崩していた時期もあり, 本調子で振る舞う事が出来なかった気がする. 今回のYAPCは, しっかり責務を果たせたかなと思った.
初めての登壇は不思議と緊張しなかった.あのRoom1, そしてYAPCの会場が非常に温かい雰囲気であり, 心地よく喋る事が出来た. このスライドに至る前に, ビルドを追求していくにつれてmetaconfigを発見したりと非常に面白かった.
5分前のベルでペース配分を焦ってしまったのが心残りではあるが, 自分としては大体したかったことが出来たと思う. あのスライドは本当に皆さんに興味を持っていただけるか自信がなく, 当日人がくるかどうかも心配していた. いざ時間になると, 本当に皆さん移動し忘れているのではないかと思うほど来ていただいて, トークを聞いてくださっていた. トークの内容も, 皆さんツイートしていただいたり, 途中で盛り上がっていただいたりと, 本当に自分自身も信じられないほどだった.
本当にこれは自分自身だけが面白いと感じているのではないかとずっと思っていた. Roppongi.pmにも呼んでいただいたので, 今考えると周囲の方々も面白いと思っていただいていたと思うのだけれど, あの内容は個人的には誰でも出来ると思ってしまっていて, そんなことを発表していいのかとちょっと思ったりもしていた.
そして登壇して, 席に戻って, タグを見たり, その後の懇親会や二次会, スライドを公開した上でのSNSなどで, 本当に意外なまでに皆さんに好評的な評価を頂いた. これは本当に自分も信じられなくて, その後miyagawaさんにまでNiceなどと言われて, 本当にこれが自分自身に起こっている事なのか信じられなかった. 僕だけが楽しいと思っていた事が, 皆さんにも楽しいと伝わったこと.本当に信じられない気持ちだった.
LTではgolangにPerl1.0を書き換えている話をした.これ自体は結構前から思いついていて, 実際に手を動かし始めたのはYAPCのLTに応募してからだった.
書いてみるとPerl1.0の内部構造がトレースのたびに理解出来るようになった気がして, 非常に楽しく夢中になれた. 当日までに動かすものを作りたかったが, なかなか厳しくて, ふわっとした話になってしまったのは反省している. ただ年内には出せるようにしたいので, 今後も開発していこうと思った. これも, ふわっとした話なので, そんなに評価されないかななどと思っていたが, Twitterを見ると様々な人に言及されていて嬉しかった.
懇親会ではいろいろな人とお会いする事が出来た.YAPCの参加回数が増えている為知り合いが増えてきたのもある気がする. 個人的には皆さんPerl1.0の話とか, Acmeモジュールの話やPerl6と言った好きな話題をする事が出来て, ありがたかった. id:utgwkkさんと初めてリアルで会えたのもいい体験だった.
不思議な感覚は他にもあった.id:ssabcireくんにTwitterで見ていて影響を受けたとか, 入学式の鹿さんに助けてもらったとか, id:kiryuanzuさんにエントリを見たとか言われた. 個人的にはそんなに頑張ってないし, やっているつもりも無かったのだが, そう言っていただけると嬉しかったし, 同時に何か不思議な気持ちになった.
その後は以前のエントリにも書いたが, id:papixさんに自信を持てと言われて, 運営の打ち上げの後に, 秋葉原で飲んでいた皆さんと合流した. id:mackee_wさんやid:xtetsujiさんが待っていただいたのが嬉しかった.
飲み会id:kiryuanzuさんと話しているうちに, 自分が本当に好きだったこと, 大切にしたい事が思い出せたように感じる. そこで, 思い出せた事は, YAPC::Kansaiの時のあの純粋な好奇心と, 自分が好きなことをする気持ちだった. YAPC::Okinawaやハッカーズチャンプルー, いつもの.pmなどで, 少しずつ取り戻しつつあった, 大切な感覚が取り戻せたと思っている. なんというか, 本当に肩の荷が下がり, 気持ちよくプログラミングや情報技術に迎える様になった.
今回のテーマは「報恩謝徳」だった.本当に今回のYAPC::Tokyoでは皆さんから恩をいただく事が出来た. 本当に, 楽しかった以外の感想がないほど楽しかったし, やっていくぞと, 本当に思うことが出来た. Perlコミュニティの皆さんにはいつも助けられてばかりだし, id:papixさんに至っては, 様々な意味でいつも励まされている. 沖縄でPerlを始めるきっかけとなったid:codehexさんとまたお会い出来たし, 本当に様々な人に支えられているんだなと感じた. この恩をいつか返せるように, そして新しくPerlやYAPCに出会った方に, 僕がしていただけたことを逆に出来るように, 今後もやっていきたいと思った.
そういえばいつもYAPCに行くと元気になる気がする.やはりYAPCは人生を変えると思う.YAPC::Kansaiに行ってなければPerlを書いていなかったが, YAPC::Tokyoに行ってなければ, 今後Perlを書いてなかった気がする.
なんとなく同じ内容になってしまったが, まぁいいとして...
YAPC::Tokyo2019で感じたこと
(感想は別で書く予定で, これはYAPCを通じて考えたエモい話です)
最近(1年くらい)は好きなことに対して自信が持てなかった気がする. YAPC::Kansaiの時などは, 勉強したてのPerlとAcmeモジュールが好きで, 書いているAcmeモジュールのロジックがコピペだろうと正直作っているだけで楽しかった. 最近の精神状態では, 意味を理解しないとロジックを書くべきではないとか思ってしまって多分書いてなかった気がする. Perlを書くこと.Acmeモジュールを使ったり読むこと.Perlの本を読んで勉強すること. その全てが純粋に楽しくて,その習得状況や書くコードの質などの差は確かにあるかもしれないが, それには本来優劣などは存在しない行為だと思う. 誰かと戦う為にジョークモジュールを作ることはないし, 何か強制的にコードを書く必要も本来はなかった. 純粋に楽しいからしていて,ただそれだけが活動のベースにあったのだと思う.
しかし最近は, 何をやっても.ことさら好きなはずのコンピュータのことでは, 人と比べることや, その意味を考えるようになってしまった. 「これを勉強してもxxxさんはすでに高校時代に実装していたんだよなぁ...」とか「こんな駄目なコードしか僕は書けないのに,xxxさんはこんなにもOSSを書いたりしている...」とかとかとか. 能力の差や技術力の差は確かに存在している.バズるサービスを開発する能力や, 綺麗なウェブページを作る能力, 難しい言語処理系のシステムを臆すること無くCで実装する事が出来る能力. それらを持っている人と, それらが今すぐに欲しくなってしまって, 自分の現状と比べて辛くなる事が多くなってしまった.
確かにPerlはずっと書いていたが, 最近書くPerlは楽しんで書くというよりは, 何かの為に書く事が多い気がしていた. 最初Perlを勉強した時にがむしゃらに書いていた, あのときの楽しさは無かった気がする.
YAPC::Tokyoのしばらく前, Roppongi.pmの前の時に, 何故か昔のPerlをビルドすることをしていた. 最初は唐突にPerlの初期バージョンに興味がわき, ぐぐったらコードがビルドできたのでおもちゃの様に遊んだ. 詳しくは覚えていないのだが, LTのネタに使えるかなと思ってやったかもしれない.
あの時.昔のPerlをビルドしている時は, 今考えるとKansaiのあの時に, Acmeモジュールを書こうと思って苦戦していた際の精神状況に似ていた気がした. そのコードややる事の意味などはどうでもよく,ただ個人的にやりたいからやっていた.面白そうだから.ただそれだけの純粋な理由だった.
思ったことはそう.僕は例えば何かのサービスを作らなければならないとか.早くしなければならないとか.そういう使命感みたいなのが動作すると途端に気力が無くなってしまうという性質なのかもしれないということだ. 最近webアプリを書く事が以前に比べて好きになれなかったのだが, 考えると, webの勉強をしなければならないという使命感が常につきまとい, その結果重くのしかかった気持ちに純粋な好奇心が負けてしまい, 死んでいたのだと思う.
好きなことは自由な時に自由にやりたい.それが仕事で出来るかはわからないが, 多分僕はそういう感じで技術とか変わっていくのが良い気がしていた.当然やらなければならないドリブンでせざるを得ないものもあるし, そういう時は多少辛くなると思っている.
しかし今思っているのは, そのやろうとしている事が本心で, 純粋な気持ちで面白いと思っているかどうかが重要だということだ. そしてその気持ちに優劣などはなくて, 好きなことは誰との比較も承認も必要なく, 好きと言い張って良いということだ. 好きなもので好きなことを好きようにやる.人生そううまくは行かないし, 業務の内容が好きかどうかなどは必ずすべてがそうではないと思う. だけれども, 自分自身の趣味の時間とか, やっていきたい気持ち自体は, 自分自身で認めていきたいと思った. やはり自分が本当に面白いと思っていることは, 人に喋っていて面白さが伝わるし, みんなに気持ちが伝わると思う. おそらく, 今まで僕が見てきたwebとかのすごい学生や人々は, その純粋な気持ちがたまたまwebに向いていただけで, 彼らは純粋な気持ちを持っている為に優劣などを考える事はなくて, 成長していけているのだと思う.
今は自分自身が何が面白いのか, 取り戻すのと掴むのに時間を要すると思っている. しかしその時間を焦る事をせず, 人々と比べずにやっていきたいと思った.
この考え方に追いついたのは, 個人的に自分だけが楽しいと思っていた昔のPerlをビルドする話をYAPCに採択していただいたこと.
当日のトークで, 自分が面白いと思った事に, 来ていただいた皆さんが同じ様に面白いと思って頂いた事.
id:papixさんに自信を持てと言われたこと, その後の飲み会で id:kiryuanzuさんと過去の話から様々なことを話せた事.
Twitterやブログで予想外に様々な人々から反響をいただいた事などがつながったからだと思う.全員のidを乗せるとすごい事になってしまうので書けないのですが, 北海道から沖縄, 海外や画面の向こうの人まで, 本当に皆さんありがとうございます.
YAPC::Tokyoでは3本も前に出させてもらった.どれも楽しかった.これはこの3本がすべて自分が面白いと思っていた事だからだと思う. 純粋な気持ちで面白いと思える事が, 僕は特にPerlに多いようだ.自分自身気づかなかったが, 好きなことを話している事はかなり楽しそうらしい. 今までのやらなければならないベースの考え方を脱却するのは人間なので難しいのだが, だけれども, 少しずつ純粋な気持ちを取り戻したいと思った.
完全にとりとめのないが, とりあえず今まとめとかないと駄目だと思ったのでまとめておいた.YAPCの感想はあとで書きます
後でまとめようと思っているけれど, 暫くの間好きなものに対して自信が持てなかった気がする.今回のYAPCで好きなことには程度など関係なく自信もって好きだと言っていいと思ったし, 好きなことを自由にするのが一番おもしろいんだなぁと思った.そしてPerl自体がやはり好きだなと思った.
— 八雲アナグラ (@AnaTofuZ) January 27, 2019
brewでinstallしたrakudo-starなPerl6のzefのinstall先をPATHにいれる
タイトル長いですがワンライナーで一発
export PATH="$(readlink $(where perl6) | perl -pne 's[\.\.][/usr/local]; s[(.*)/bin/perl6][$1/share/perl6/site/bin]'):$PATH"
継続を基本とするC言語CbCのご紹介
この記事は琉大情報工学科(知能情報コース) Advent Calendar 2018 の16日目の記事です.
どうせなのでCasl2のエミュレーターでも書くかという気になりましたが,今日はドラゴンボールを見てしまったのでエミュレーターは途中までとなりました.ご了承下さい.
さて今日は一部界隈でまことしやかに盛り上がっている謎の言語CbCことContinuation Based Cについての話です. ただしCbCは沼なので間違えている可能性があります.サイレント修正される可能性がありますがご了承下さい.
Continuation Based Cとは
Continuation Based C(以下CbC)とは継続を基本としたC言語の下位言語です. C言語での関数呼び出しやfor文などのループ文をコードから消滅させ, 状態遷移単位でコードを書くことが出来る言語です. 応用例としては世界最速のgrepやGearsOS, Perl6処理系のCbCMoarVMなどが存在します.
現在はgcc及びllvm/clang上に実装した2種類が存在します.
C言語を使ってプログラミングをする場合,メモリのアロケートやエラーハンドリングなどを記述していく必要があります. しかしこの処理は複雑かつエラーを発生させやすい為,通常の処理と分離して記述することが望ましいとされます. これらの処理をMetaComputationと呼びます. しかしC言語を使ったプログラミングである程度規模が大きいものを行おうとすると,これらの処理と通常の計算処理を分離して記述することは非常に難しいとされます.
CbCでは,関数の代わりにCodeSegmentとDataSegmentを基本単位として導入する事で,これらをやりやすくします.
CodeSegment
CbCでは関数の代わりにCodeSegmentを利用します.
CodeSegmentは関数よりも小さく,ステートメントよりも大きい単位となっています. CodeSegmentを利用したCbCではループ文を持ちません. これはCodeSegmentがコンパイラにおける基本ブロックと呼ばれる単位に該当する為です.
CodeSegmentはCの関数の代わりに __code
と書くことで宣言出来ます.
これは __code
という型が有るわけではなく, CbCプログラマからはCodeSegmentである事を示す指示子の様な役割を果たします.
__code
自体はCbCコンパイラではvoid型として扱います.
CodeSegmentからCodeSegmentへはCのgoto文を利用して遷移します. この遷移はCの関数呼び出しとは異なり,callなどの命令を利用せずjmpを利用した軽量継続で行います. 実際にコード例を見てみましょう.
extern int printf(const char*,...); int main (){ int data = 0; goto cg1(&data); } __code cg1(int *datap){ (*datap)++; goto cg2(datap); } __code cg2(int *datap){ (*datap)++; printf("%d\n",*datap); }
このコードはmain関数で設定した data = 0
をcg1と言うCodeSegmentに入力として渡します.
この時点ではCの世界からCbCの世界に突入する段階ですので, cg1自体はcallで呼び出されます.
cg1では受け取ったdataのアドレスからdataをインクリメントし data = 1
にします.
インクリメントの後 cg2 に軽量継続します.
cg2では同様にdataをインクリメントし, printするという流れです.
#include <stdio.h> __code fact(int n, int result,__code (*print)()) { if (n > 0) { result *= n; n--; goto fact(n,result,print); } else { goto (*print)(result); } } __code print_result(int result){ printf("result is %d\n",result); } int main(int argc, char** argv){ goto fact(20,0,print_result); }
他には上記のような階上を求めるコードも書くことが可能です.
fact(int n, int result,__code (*print)())
の引数として __code
のCodeSegment自体を渡しています.
この様にCodeSegmentの引数にはCodeSegment自体もいれることが可能です. この引数の事をDataSegmentもしくはInterfaceと呼びます. なぜ引数ではなくDataSegmentと呼称するかについては後述します.
軽量継続とは
先程から何回か出ている軽量継続とは何でしょうか. 軽量継続ではなく,継続とはSchemaなどの処理系には実装されています.
Wikipediaによると
継続は、前の状態を引き継ぐこと。持続、保持。 計算機科学における継続(けいぞく、continuation)とは、プログラムの実行においてある時点において評価されていない残りのプログラム(the rest of the program)を意味するものであり、手続き(procedure)として表現される
https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A
詳しくは http://practical-scheme.net/docs/cont-j.html
つまり,CbCではCレベルで次の処理の命令をよりSchemaなどの関数型言語のように記述することが出来るインターフェイスを提供します. この際にSchemaなどでは,現在の位置などを環境として保存する必要がありますが, CbCの場合そのあたりを保存しない為軽量な継続,つまり軽量継続と読んでいます.
うれしいところ
Cで軽量継続を使えると何が嬉しいのでしょうか. それはCの関数呼び出しがコストがかかる事がまず挙げられます.
Cの関数呼び出しでは, 呼び出し側は引数を積み上げ,戻り番地のセーブを行い, 呼び出される方は局所変数を保存したり,スタックやフレームポインタを押し上げるなどの処理が必要となります. これらを一切行わず,プログラムカウンタを変更するのみのjmp命令にCbCのgotoを利用したCodeSegmentは変換する事が可能です.
その為CodeSegmentを直接指定してgotoするなどの処理が書けるようになり,煩わしいfor文やcase-switch文をなくすことが可能です
Cでも末尾再帰と呼ばれる方法を利用すればこの方法が可能であり,実際CbCは内部的に末尾再帰のアルゴリズムを用いて最適化しています.
その為, CodeSegmentのDataSegment部分を同じにする事で,全ての命令がjmp命令にコンパイルされます. jmp命令になるということは,CodeSegment間の引き渡しで引数がレジスタに乗ったまま移動されるということです.最高ですね.
つまりCodeSegmentの引数は入力のみではなく入出力としての意味を持つ為,引数ではなくData SegmentやInterfaceという呼び方をしています.
FizzBuzz
試しにFizzBuzzを書いてみます
#define __environment _CbC_environment #define __return _CbC_return #include <stdio.h> #include <string.h> #include <stdlib.h> __code fizzbuzz(int,int,char*,__code(),void*); __code say2(int,int,char*,__code(),void*); __code fizz(int,int,char*,__code(),void*); __code buzz(int,int,char*,__code(),void*); int main(void){ int n = 100; fizzbuzz(1,n,"",__return,__environment); return 0; } __code fizzbuzz(int i,int n,char* ret_result,__code(*return1)(),void *return1env) { if ( i <= n ) { goto fizz(i,n,ret_result,return1,return1env); } else { goto return1(0,return1env); } } __code fizz(int i,int n,char* ret_result,__code(*return1)(),void *return1env) { if (i % 3 == 0){ ret_result = "fizz"; } else { ret_result = ""; } goto buzz(i,n,ret_result,return1,return1env); } __code buzz(int i,int n,char* ret_result,__code(*result1)(),void *return1env) { char *result; result = (char *)malloc(15); if (i % 5 == 0){ snprintf(result,9,"%s%s",ret_result,"buzz"); } else { snprintf(result,8,"%s",ret_result); } goto say2(i,n,result,result1,return1env); } __code say2(int i,int n,char* ret_result,__code(*return1)(),void *return1env) { if ( ret_result[0] == '\0'){ printf("%i : %i\n" ,i,i); } else { printf("%i:%s\n",i,ret_result); } goto fizzbuzz(i+1,n,"",return1,return1env); }
CbCっぽく書くコツはDataSegmentをそろえる事です.
これを-Sをつけてアセンブラを見てみましょう.
cbclang -S fizzbuzz.cbc
.section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 14 .globl _main..ret0 ## -- Begin function main..ret0 .p2align 4, 0x90 _main..ret0: ## @main..ret0 .cfi_startproc ## %bb.0: ## %entry pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq (%rsi), %rax movl %edi, (%rax) movq 8(%rsi), %rax movq (%rax), %rbp movq 8(%rax), %rsi movq 16(%rax), %rsp jmpq *%rsi .cfi_endproc ## -- End function .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc ## %bb.0: ## %entry pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp pushq %r15 pushq %r14 pushq %r13 pushq %r12 pushq %rbx subq $264, %rsp ## imm = 0x108 .cfi_offset %rbx, -56 .cfi_offset %r12, -48 .cfi_offset %r13, -40 .cfi_offset %r14, -32 .cfi_offset %r15, -24 leaq -208(%rbp), %rax leaq -252(%rbp), %rcx leaq _main..ret0(%rip), %rdx movq ___stack_chk_guard@GOTPCREL(%rip), %rsi movq (%rsi), %rsi movq %rsi, -48(%rbp) movl $0, -212(%rbp) movl $100, -216(%rbp) movl -216(%rbp), %esi movq %rdx, -224(%rbp) movq -224(%rbp), %rdx movq %rdx, -232(%rbp) movq -232(%rbp), %rdx movq %rcx, -248(%rbp) movq %rax, -240(%rbp) movq -240(%rbp), %rax movq %rax, %rcx movq %rbp, %rdi movq %rdi, (%rax) movq %rsp, %rdi movq %rdi, 16(%rax) leaq LBB1_8(%rip), %rax movq %rax, 8(%rcx) movl %esi, -268(%rbp) ## 4-byte Spill movq %rdx, -280(%rbp) ## 8-byte Spill #EH_SjLj_Setup LBB1_8 ## %bb.6: ## %entry xorl %eax, %eax movl %eax, -284(%rbp) ## 4-byte Spill LBB1_7: ## %entry movl -284(%rbp), %eax ## 4-byte Reload movq -240(%rbp), %rcx movq %rcx, %rdx movq %rbp, %rsi movq %rsi, (%rcx) movq %rsp, %rsi movq %rsi, 16(%rcx) leaq LBB1_11(%rip), %rcx movq %rcx, 8(%rdx) movl %eax, -288(%rbp) ## 4-byte Spill #EH_SjLj_Setup LBB1_11 ## %bb.9: ## %entry xorl %eax, %eax movl %eax, -292(%rbp) ## 4-byte Spill LBB1_10: ## %entry movl -292(%rbp), %eax ## 4-byte Reload cmpl $0, %eax je LBB1_2 ## %bb.1: ## %if.then movl -252(%rbp), %eax movl %eax, -212(%rbp) jmp LBB1_3 LBB1_2: ## %if.end leaq -248(%rbp), %rax movq %rax, -264(%rbp) movq -264(%rbp), %rax leaq L_.str(%rip), %rdx movl $1, %edi movl -268(%rbp), %esi ## 4-byte Reload movq -280(%rbp), %rcx ## 8-byte Reload movq %rax, %r8 callq _fizzbuzz subq $8, %rsp movl $0, -212(%rbp) LBB1_3: ## %return movl -212(%rbp), %eax movq ___stack_chk_guard@GOTPCREL(%rip), %rcx movq (%rcx), %rcx movq -48(%rbp), %rdx cmpq %rdx, %rcx movl %eax, -296(%rbp) ## 4-byte Spill jne LBB1_5 ## %bb.4: ## %SP_return movl -296(%rbp), %eax ## 4-byte Reload addq $264, %rsp ## imm = 0x108 popq %rbx popq %r12 popq %r13 popq %r14 popq %r15 popq %rbp retq LBB1_5: ## %CallStackCheckFailBlk callq ___stack_chk_fail LBB1_8: ## Block address taken ## %entry movl $1, %eax movl %eax, -284(%rbp) ## 4-byte Spill jmp LBB1_7 LBB1_11: ## Block address taken ## %entry movl $1, %eax movl %eax, -292(%rbp) ## 4-byte Spill jmp LBB1_10 .cfi_endproc ## -- End function .globl _fizzbuzz ## -- Begin function fizzbuzz .p2align 4, 0x90 _fizzbuzz: ## @fizzbuzz .cfi_startproc ## %bb.0: ## %entry pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp subq $48, %rsp cmpl %esi, %edi movl %esi, -4(%rbp) ## 4-byte Spill movq %r8, -16(%rbp) ## 8-byte Spill movq %rcx, -24(%rbp) ## 8-byte Spill movq %rdx, -32(%rbp) ## 8-byte Spill movl %edi, -36(%rbp) ## 4-byte Spill jg LBB2_2 ## %bb.1: ## %if.then movl -36(%rbp), %edi ## 4-byte Reload movl -4(%rbp), %esi ## 4-byte Reload movq -32(%rbp), %rdx ## 8-byte Reload movq -24(%rbp), %rcx ## 8-byte Reload movq -16(%rbp), %r8 ## 8-byte Reload addq $48, %rsp popq %rbp jmp _fizz ## TAILCALL LBB2_2: ## %if.else xorl %eax, %eax movb %al, %cl movl %eax, %edi movq -16(%rbp), %rsi ## 8-byte Reload movb %cl, %al movq -24(%rbp), %rdx ## 8-byte Reload callq *%rdx addq $48, %rsp popq %rbp retq $8 .cfi_endproc ## -- End function .globl _fizz ## -- Begin function fizz .p2align 4, 0x90 _fizz: ## @fizz .cfi_startproc ## %bb.0: ## %entry subq $56, %rsp .cfi_def_cfa_offset 64 leaq L_.str.1(%rip), %rax movl $3, %edx movq %rax, 48(%rsp) ## 8-byte Spill movl %edi, %eax movl %edx, 44(%rsp) ## 4-byte Spill cltd movl 44(%rsp), %r9d ## 4-byte Reload idivl %r9d cmpl $0, %edx movq 48(%rsp), %r10 ## 8-byte Reload movl %esi, 40(%rsp) ## 4-byte Spill movq %r8, 32(%rsp) ## 8-byte Spill movq %rcx, 24(%rsp) ## 8-byte Spill movl %edi, 20(%rsp) ## 4-byte Spill movq %r10, 8(%rsp) ## 8-byte Spill je LBB3_2 ## %bb.1: ## %if.else leaq L_.str(%rip), %rax movq %rax, 8(%rsp) ## 8-byte Spill jmp LBB3_2 LBB3_2: ## %if.end movq 8(%rsp), %rax ## 8-byte Reload movl 20(%rsp), %edi ## 4-byte Reload movl 40(%rsp), %esi ## 4-byte Reload movq %rax, %rdx movq 24(%rsp), %rcx ## 8-byte Reload movq 32(%rsp), %r8 ## 8-byte Reload addq $56, %rsp jmp _buzz ## TAILCALL .cfi_endproc ## -- End function .globl _buzz ## -- Begin function buzz .p2align 4, 0x90 _buzz: ## @buzz .cfi_startproc ## %bb.0: ## %entry pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp subq $64, %rsp movl $15, %eax movl %eax, %r9d movl %edi, -4(%rbp) ## 4-byte Spill movq %r9, %rdi movl %esi, -8(%rbp) ## 4-byte Spill movq %r8, -16(%rbp) ## 8-byte Spill movq %rcx, -24(%rbp) ## 8-byte Spill movq %rdx, -32(%rbp) ## 8-byte Spill callq _malloc movl $5, %esi movl -4(%rbp), %r10d ## 4-byte Reload movq %rax, -40(%rbp) ## 8-byte Spill movl %r10d, %eax cltd idivl %esi cmpl $0, %edx jne LBB4_2 ## %bb.1: ## %if.then movl $9, %eax movl %eax, %esi xorl %edx, %edx movl $15, %eax movl %eax, %ecx leaq L_.str.2(%rip), %r8 leaq L_.str.3(%rip), %rdi movq -40(%rbp), %r9 ## 8-byte Reload movq %rdi, -48(%rbp) ## 8-byte Spill movq %r9, %rdi movq -32(%rbp), %r9 ## 8-byte Reload movq -48(%rbp), %r10 ## 8-byte Reload movq %r10, (%rsp) movb $0, %al callq ___snprintf_chk movl %eax, -52(%rbp) ## 4-byte Spill jmp LBB4_3 LBB4_2: ## %if.else movl $8, %eax movl %eax, %esi xorl %edx, %edx movl $15, %eax movl %eax, %ecx leaq L_.str.4(%rip), %r8 movq -40(%rbp), %rdi ## 8-byte Reload movq -32(%rbp), %r9 ## 8-byte Reload movb $0, %al callq ___snprintf_chk movl %eax, -56(%rbp) ## 4-byte Spill LBB4_3: ## %if.end movl -4(%rbp), %edi ## 4-byte Reload movl -8(%rbp), %esi ## 4-byte Reload movq -40(%rbp), %rdx ## 8-byte Reload movq -24(%rbp), %rcx ## 8-byte Reload movq -16(%rbp), %r8 ## 8-byte Reload addq $64, %rsp popq %rbp jmp _say2 ## TAILCALL .cfi_endproc ## -- End function .globl _say2 ## -- Begin function say2 .p2align 4, 0x90 _say2: ## @say2 .cfi_startproc ## %bb.0: ## %entry pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp subq $64, %rsp movsbl (%rdx), %eax cmpl $0, %eax movl %esi, -4(%rbp) ## 4-byte Spill movq %r8, -16(%rbp) ## 8-byte Spill movq %rcx, -24(%rbp) ## 8-byte Spill movq %rdx, -32(%rbp) ## 8-byte Spill movl %edi, -36(%rbp) ## 4-byte Spill jne LBB5_2 ## %bb.1: ## %if.then leaq L_.str.5(%rip), %rdi movl -36(%rbp), %esi ## 4-byte Reload movl -36(%rbp), %edx ## 4-byte Reload movb $0, %al callq _printf movl %eax, -40(%rbp) ## 4-byte Spill jmp LBB5_3 LBB5_2: ## %if.else leaq L_.str.6(%rip), %rdi movl -36(%rbp), %esi ## 4-byte Reload movq -32(%rbp), %rdx ## 8-byte Reload movb $0, %al callq _printf movl %eax, -44(%rbp) ## 4-byte Spill LBB5_3: ## %if.end movl -36(%rbp), %eax ## 4-byte Reload incl %eax leaq L_.str(%rip), %rdx movl %eax, %edi movl -4(%rbp), %esi ## 4-byte Reload movq -24(%rbp), %rcx ## 8-byte Reload movq -16(%rbp), %r8 ## 8-byte Reload addq $64, %rsp popq %rbp jmp _fizzbuzz ## TAILCALL .cfi_endproc ## -- End function .section __TEXT,__cstring,cstring_literals L_.str: ## @.str .space 1 L_.str.1: ## @.str.1 .asciz "fizz" L_.str.2: ## @.str.2 .asciz "%s%s" L_.str.3: ## @.str.3 .asciz "buzz" L_.str.4: ## @.str.4 .asciz "%s" L_.str.5: ## @.str.5 .asciz "%i : %i\n" L_.str.6: ## @.str.6 .asciz "%i:%s\n" .subsections_via_symbols
実際にCodeSegment同士はjmpで,mallocなどの関数呼び出しのみcallになっている事がわかります
~/w/c/S/cbc-sandbox » grep jmp fizzbuzz.s jmpq *%rsi jmp LBB1_3 jmp LBB1_7 jmp LBB1_10 jmp _fizz ## TAILCALL jmp LBB3_2 jmp _buzz ## TAILCALL jmp LBB4_3 jmp _say2 ## TAILCALL jmp LBB5_3 jmp _fizzbuzz ## TAILCALL
~/w/c/S/cbc-sandbox » grep call fizzbuzz.s
callq _fizzbuzz
callq ___stack_chk_fail
callq *%rdx
callq _malloc
callq ___snprintf_chk
callq ___snprintf_chk
callq _printf
callq _printf
試すには
試すには gccはこちら
clangはこちらを見ていただくと出来ます.
なおclangが容量をすごく取りますが,現状Mac os Mojaveではclangしかビルド出来ません...助けてくれ...