みずぴー日記

人間の再起動ボタンはハワイのビーチにある

SML# 2.0 のLLVM出力機能を使って、Hello worldをx86_64環境で動かしてみる

f:id:mzp:20140519143223p:plain

注意事項

とりあえずHello,worldが動く程度です。過度な期待をしないでください。

必要なもの

  • SML# 2.0がインストール済みマシン
  • SML# 2.0のソースコード(ビルドする必要はない)
  • x86で動くOSとx86_64で動くOS*1

x86マシンでの作業

とりあえず最低限のhello worldを作りたいので、basisを使わずにHello,worldを書きます。

val puts = _import "puts" : string -> ()
val () = puts "hello from 64bit”;

これをSML#コンパイラLLVM IRにコンパイルします。

$ ls
hello.sml

$ smlsharp   -nostdpath -emit-llvm  -S hello.sml
hello.ll  hello.sml

あとはこのhello.llからx86_64用のオブジェクトファイルを生成するだけなのですが、そのためにはSML#用のGCプラグインをビルドする必要があります。 これはSML#のソースツリーに含まれているので、以下のコマンドでビルドできます。

$ cd /path/to/smlsharp-2.0.0
$ cd src/llvm/main
$ gcc $(llvm-config --cxxflags) -shared -o smlsharpgc.so SMLSharpGC.cpp 

IRをこのプラグインを用いてオブジェクトファイルへとコンパイルします。

$ llc -march=x86-64 -filetype=obj -o hello.o -load=/path/to/smlsharp-2.0.0/src/llvm/main/smlsharpgc.so hello.ll
$ file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (GNU/Linux), not stripped

x86_64マシンでの作業

さきほどのhello.oをx86_64のマシンに転送して、ビルドをします。 ただ、hello.oだけではエントリポイント等が不足しているので適当に補います。

runtime.c:

/* 最低限のランタイムを定義する。とりあえずなので実装はさぼる。 */
void sml_alloc() {}
void sml_control_resume() {}
void sml_control_suspend() {}

entry.c:

/* SML#のエントリポイントを呼びだす。
   エンポイント名はnm hlello.o | grep SMLmainで確認できる */
int main(){
  _SMLmainZ();
  return 0;
}

で、これらをつかってビルドします。

$ gcc -o hello runtime.c hello.o entry.c

実行する。

$ ./hello
hello from 64bit

ヤッターデキター。

今後やるべきことについて

動いて満足できたので、あまり継続してやるつもりはないです。

とりあえず、ちゃんとした対応するためにはSML#のランタイム(/usr/lib/smlsharp/runtime/libsmlsharp.a)のx86_64対応が必須だなぁ、という感じです。

*1:がんばればクロスコンパイルできそうだけど、面倒なのでやってない