libdcompile(印刷に優しい版)
Upcoming SlideShare
Loading in...5
×
 

libdcompile(印刷に優しい版)

on

  • 762 views

 

Statistics

Views

Total Views
762
Views on SlideShare
761
Embed Views
1

Actions

Likes
1
Downloads
1
Comments
0

1 Embed 1

http://s.deeeki.com 1

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

libdcompile(印刷に優しい版) libdcompile(印刷に優しい版) Presentation Transcript

  • libdcompileNaomasa Matsubayashi
  • 好きなもの C++ @fadis_ Vim Gentoohttp://www.slideshare.net/fadis
  • C++ C言語との高い相互運用性を維持しつつ 近代的な開発の出来る言語 RAIIを徹底し、例外安全なコードを書き、CppCMS STLがどのように機能しているのか理解していれば、全てはシンプルになる マルチパラダイム言語 手続き型 静的型付け 継承型 実行時 関数型 動的型付け メッセージ型 コンパイル時 コンセプト型 ライブラリで殆ど何でも出来るようになっている ライブラリでえげつないことしてる例 それでも、 他の言語にあってC++に無くて悲しい物もある
  • eval eval "print "Hello, World!n"" 文字列 文字列で与えられたコードを実行する eval $_ ここがコンパイル時に不定でもOK 実行時にコンパイルする手段が必要 これ Haskell Python これも C Perl D Java C# Ruby C++ JavaScriptライブラリにコンパイラが丸ごと含まれている
  • LLVMをバックエンドとして使うclang 新しいC++、ObjectiveC、C言語用コンパイラ コンパイラの個々の機能がライブラリになっていて BSDライクなライセンスLLVM イリノイ大学で開発されたコンパイラ基盤 LLVM中間コードを食べさせると 最適化してターゲットアーキテクチャのバイナリを吐く LLVMとclangを使えば 実行時にコンパイルが出来るのでは clangのライブラリを使ってlibdcompile 実行時にコンパイルするライブラリ https://github.com/Fadis/libdcompile C++にevalを!
  • #include <iostream>#include <string> $ ./foo#include <dcompile/dcompile.hpp> Hello, World!int main() { std::string source_code = $ "#include <iostream>n" "extern "C" void foo() {" " std::cout << "Hello, World!" << std::endl;" "}"; dcompile::dynamic_compiler dc; dc.getHeaderPath().enableSystemPath(); dcompile::module lib = dc( source_code, dcompile::CXX ); boost::optional< dcompile::function > foo = lib.getFunction( "foo" ); if( foo ) (*foo)();}
  • 実行時にコンパイルするコード中で実行の流れ 外部ライブラリの関数を 使いたくなったらどうしよう libdcompileで実行時にコンパイルしたコードは ホストのコードと同じメモリ空間で動くメリット1 このライブラリの実行にbinutilsが必要ない 実行時にコンパイルしたコードからメリット2 ホストのリソースにアクセス出来る LLVMのJIT実行を使えばこれができる LLVMはJIT実行を行う際、与えられたソースコード中で解決できないシンボルを dlsymを使って解決しようとする
  • #include <iostream>#include <string>#include <dcompile/dcompile.hpp>void bar() { std::cout << "Hello, World!" << std::endl; }int main() { std::string source_code = $ ./foo "void bar(); Hello, World! "extern "C" void foo() { bar(); }"; dcompile::dynamic_compiler dc; $ dc.getHeaderPath().enableSystemPath(); dcompile::module lib = dc( source_code, dcompile::CXX ); boost::optional< dcompile::function > foo = lib.getFunction( "foo" ); if( foo ) (*foo)();}
  • 実行時にコンパイルするコード中で実行の流れ 外部ライブラリの関数を 使いたくなったらどうしよう dlsymでa.outのシンボルを漁った時に見えるもの a.outの中にあるシンボル RTDL_GLOBALでdlopenされたライブラリのシンボル LLVMがシンボルを解決しようとする前に 必要なライブラリをdlopenしておけば良い dlfcnは LLVMの中を漁ったら システムのダイナミックロードをPOSIX固有 ラップしてるっぽい関数があった llvm::sys::DynamicLibrary::LoadLibraryPermanently ただし、ロードだけ…
  • #include <iostream>#include <string>#include <dcompile/dcompile.hpp>int main() { std::string source_code = "#include <jpeglib.h>n" "extern "C" void foo() {" " struct jpeg_compress_struct cinfo;" " jpeg_create_compress( &cinfo );" "}"; dcompile::dynamic_compiler dc; dc.getLoader().enableSystemPath(); dc.getHeaderPath().enableSystemPath(); if( !dc.getLoader().load( "jpeg" ) ) std::cout << "unable to load libjpeg." << std::endl; else { boost::optional< dcompile::module > lib = dc( source_code, dcompile::CXX ); if( lib ) { boost::optional< dcompile::function > foo = lib->getFunction( "foo" ); if( foo ) (*foo)(); } }}
  • ライブラリとヘッダのサーチパスを設定するパス dcompile::dynamic_compiler dc; dc.getLoader().enableSystemPath(); システムのライブラリパスをサーチパスに含める それ以外のパスを含めたい場合 dc.getLoader().addPath( "/opt/hoge/lib" ); dc.getHeaderPath().enableSystemPath(); システムのヘッダパスをサーチパスに含める それ以外のパスを含めたい場合dc.getHeaderPath().addPath( "/opt/hoge/include" ); ところでシステムのパスって何 $(CLANG_DIR)/lib/Frontend/InitHeaderSearch.cpp $(LLVM_DIR)/lib/Support/(Unix¦Windows)/Path.inc スーパー手抜き実装
  • #include <iostream>#include <string>#include <dcompile/dcompile.hpp>int main() { std::string source_code = "#include <jpeglib.h>n" "extern "C" void foo() {" " struct jpeg_compress_struct cinfo;" " jpeg_create_compress( &cinfo );" "}"; dcompile::dynamic_compiler dc; dc.getLoader().addPath( "/usr/lib" ); dc.getHeaderPath().addPath( "/usr/include" ); if( !dc.getLoader().load( "jpeg" ) ) std::cout << "unable to load libjpeg." << std::endl; else { boost::optional< dcompile::module > lib = dc( source_code, dcompile::CXX ); if( lib ) { boost::optional< dcompile::function > foo = lib->getFunction( "foo" ); if( foo ) (*foo)(); } }}
  • incompatible libpng14 libpng15危険 -lpng dc.getLoader().load( "png" ); dlsymがどっちをロードしてくるかわからない incompatible libstdc++ libc++危険 ホスト側と実行時コンパイル側で 想定している型が異なる incompatible MSVC Clang無理 マングリング規則が異なるため シンボルを見つけられない Requirement: ライブラリABI互換ライブラリABI = ライブラリAPI + コンパイラABI http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
  • typedef float float4 __attribute( ( vector_size( sizeof( float ) * 4 ) ) ); float4 foo( float4 b ) { b = b * b + b * b; return b; } i486 Athlon64 Corei7 ARMv5fsts -40(%ebp) mulps %xmm0, %xmm0 vmulps %xmm0, %xmm0, %xmm0 mov r0, r3fxch addps %xmm0, %xmm0 vaddps %xmm0, %xmm0, %xmm0 str r1, [sp, #56]fsts -36(%ebp) mov r1, r3fxch %st(2) str r3, [sp, #52]fsts -32(%ebp) str r2, [sp, #48]fxchfsts %st(3) -28(%ebp) ARMv7a ARMv6 bl __mulsf3 str r0, [sp, #44]fxch %st(3) vmul.f32 q9, q8, q8 vmul.f32 s3, s3, s3 ldr r1, [sp, #44]fmul %st(0), %st(0) vadd.f32 q9, q9, q9 vadd.f32 s3, s3, s3 bl __addsf3fadd %st(0), %st(0) str r0, [sp, #76]fsts -32(%ebp) vstr s3, [sp, #12] ldr r1, [sp, #48]fxch %st(2) vmul.f32 s2, s2, s2 str r0, [sp, #40]fmul %st(0), %st(0) vadd.f32 s2, s2, s2 mov r0, r1fadd %st(0), %st(0)fsts -36(%ebp) PPC64 vstr s2, [sp, #8] vmul.f32 s1, s1, s1 bl __mulsf3 str r0, [sp, #36]fxch ldr r1, [sp, #36]fmul %st(0), %st(0) vmaddfp v3, v2, v2, v3 vadd.f32 s1, s1, s1 bl __addsf3fadd %st(0), %st(0) vaddfp v3, v3, v3 vstr s1, [sp, #4] str r0, [sp, #72]fsts -40(%ebp) ldr r1, [sp, #56]fxch %st(3) vmul.f32 s0, s0, s0 str r0, [sp, #32]fmul %st(0), %st(0) vadd.f32 s0, s0, s0 mov r0, r1fadd %st(0), %st(0) bl __mulsf3
  • #include <iostream>#include <string>#include <dcompile/dcompile.hpp>void eval( int *count, const char *str ) { dcompile::dynamic_compiler dc; boost::optional< dcompile::module > lib = dc( str, dcompile::CXX ); if( lib ) { boost::optional< dcompile::function > foo = lib->getFunction( "foo" ); if( foo ) (*foo)( count, str ); }}int main() { int count = 5; std::string source_code = 再帰 "void eval( int *, const char * );" "extern "C" void foo( int *count, const char *str ) {"$ ./foo " if( *count-- ) eval( count, str );" "}"; 0 eval( &count, source_code.c_str() ); $ std::cout << count << std::endl;}
  • 複数の 2つ以上の翻訳単位からなる コードを実行時にコンパイルする翻訳単位 実行時にコンパイルしたコードで使う 実行時にコンパイルしたライブラリが作れる#include <dcompile/dcompile.hpp>int main() { dcompile::dynamic_compiler dc; LLVM3.0以降の新機能 dc.getLoader().enableSystemPath(); dc.getHeaderPath().enableSystemPath(); LLVM Linkerを使用 std::vector< dcompile::object > objs; objs.push_back( dc.getObject( "hoge.cpp" ) ); objs.push_back( dc.getObject( "fuga.cpp" ) ); gcc -cに相当 dcompile::module mod = dcompile::load( dcompile::link( objs.begin(), objs.end() ) ); boost::optional< dcompile::function > foo = mod.getFunction( "foo" ); if( foo ) (*foo)( &a );} ldに相当
  • dcompile::dynamic_compilersetOptimizeLevel 最適化レベルを設定getOptimizeLevel 最適化レベルを取得 getLoader ライブラリパスリストを取得getHeaderPath ヘッダパスリストを取得 ソースコードを渡して operator() リンク済みモジュールを得る ソースコードを渡して getObject リンク前のオブジェクトを得る ソースコードを渡して dumpLLVM LLVM中間コードを得る ソースコードを渡して dumpAsm ネイティブアセンブリを得る
  • 内部 clangのソースに関する最低限のドキュメント doxygen clangのソースに関する詳細なドキュメント ソース clangのライブラリを使う何かを作りたい時 既にclangのライブラリを使って動いている clangコマンドのソースを見れば良い main@/tools/clang/tools/driver/driver.cppExecuteCompilation@/tools/clang/lib/Driver/Driver.cppExuecuteJob@/tools/clang/lib/Driver/Compilation.cppllvm::sys::Program::ExecuteAndWait(Prog, Argv, /*env*/0, Redirects, /*secondsToWait*/0, /*memoryLimit*/0, ふりだしに戻る &Error);
  • main@/tools/clang/tools/driver/driver.cpp cc1_main@/tools/clang/tools/driver/cc1_main.cppclang::ExecuteCompilerInvocation@/tools/clang/tools/ driver/cc1_main.cppbool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { TargetOption CompilerInstance Action EmitBCActionで Diagnostics SourceManager 中間コードを生成 FileManager CompilerInstanceから漁っていけば 必要な情報に大抵辿り着ける
  • LLVM 複数の中間コードを1つにまとめる doxygen見れば大体使い方がわかるLinker LinkInModuleでくっつける中間コードを突っ込んで getModuleすると1つのカタマリになって出てくる LLVM Linkerは ExecuteEngineは与えられた中間コードと 与えられた中間コードを 生成した中間コードを 自分で破棄する 自分で破棄する LLVM LinkerからgetModuleした中間コードを ExecuteEngineで実行すると、プロセスは死ぬgetModuleではなくreleaseModuleを使えば良い
  • 実行 LLVM中間コードを実行する手順が知りたい時 lliコマンドのソースを見れば良い main@/tools/lli/lli.cppInitializeNativeTarget(); ネイティブターゲットのInitializeNativeTargetAsmPrinter(); 初期化EngineBuilder builder(Mod);builder.setMArch(MArch); 中間コードを渡してbuilder.setMCPU(MCPU); ターゲットを設定builder.setMAttrs(MAttrs);builder.setUseMCJIT(true); JITコンパイルを有効にEE = builder.create(); ExecuteEngineを生成EE->runStaticConstructorsDestructors(false);GenericValue Result = EE->runFunction( EntryFn, Args );EE->runStaticConstructorsDestructors(true); get_result_as< T >とか作った方が良いかも
  • LLVMとclangを使えば C++で実行時にコンパイル出来る! Haskell Python CPerl C++ D Java C# Ruby JavaScript
  • LDC D言語のコードを食べて LLVM中間コードを吐く http://www.dsource.org/projects/ldc/ これを使えばC++のコード中に実行時にコンパイルされるD言語のコードを埋め込めるのではちょっとソースコード読んでみたけどよーわからんかった… とりあえず開発が止まってることだけはわかった
  • ご清聴ありがとうございました