emscripten であそぶ

hello

int main() {
  puts("hello");
}

生成されたコード

// EMSCRIPTEN_START_FUNCS
function _main() {
 var label = 0;
 var $1=_puts(((8)|0));
 return 0;
}
Module["_main"] = _main;
// EMSCRIPTEN_END_FUNCS

8がだだっぴろいメモリへのインデックスなのはわかるけど、それはどこで定義されてるのかな…と hello で検索しても見つからない。 104 で検索すると見つかった。

STATIC_BASE = 8;
STATICTOP = STATIC_BASE + 8;
/* memory initializer */ allocate([104,101,108,108,111,0,0,0], "i8", ALLOC_NONE, Rubyntime.GLOBAL_BASE)

sleep

CPS 変換ってやつかなんかしないときつくねー、って気になるものの代表格

#include <unistd.h>
int main() {
  sleep(1);
}

えっと…

      while (Date.now() - start < msec) {
        // Do nothing.
      }

まさかの busy loop! 男らしい!

pthread

 <pthread.h>
void* thread(void* data) {}
int main() {
  pthread_t th;
  pthread_create(&th, NULL, &thread, NULL);
  pthread_join(th, NULL);
}

ReferenceError: _pthread_create is not defined

read

#include <unistd.h>
int main() {
  read(0, "foo", 1);
  perror("read");
}

STDIN は EBADF 。

setjmp

ほとんどイヤガラセみたいな要求ですが

#include <setjmp.h>
#include <stdio.h>
jmp_buf env;
void func() {
  longjmp(env, 1);
}
int main() {
  int ok = 0;
  if (setjmp(env)) {
    if (ok)
      puts("PASS");
  } else {
    ok = 1;
    func();
  }
}

意外にも? 動いた! 実装は例外にて。なるほどー。

  function _longjmp(env, value) {
      throw { longjmp: true, id: HEAP32[((env)>>2)], value: value || 1 };
    }

メモリ保護

int main() {
  --*"";
  char* msg = "hello";
  ++*msg;
  puts(msg);
  char* p = &main;
  *p = 42;
}

iello 。無し!

mmap

#include <sys/mman.h>
int main() {
  char* p = mmap(0x4000000, 0x1000,
                 PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, -1, 0);
  if (p == MAP_FAILED)
    perror("mmap");
  *p = 'h';
  printf("%p %s\n", p, p);
}

結果は 0x5000a8 h とかで MAP_FIXED は無視されました。ちなみに

      /* FIXME: Since mmap is normally implemented at the kernel level,
       * this implementation simply uses malloc underneath the call to
       * mmap.
       */

とのことで、 mmapmalloc 呼んでて通常と真逆。ちなみにメモリ空間はデフォルトでは 16MB らしい。まあそんなもんですかねえ。

pipe

#include <unistd.h>
int main() {
  int fds[2];
  pipe(fds);
  perror("pipe");
}

pipe は ENOSYS か。ネットワークでも使わない限り blocking call がどうなるかわからない感じか…

connect

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
int main() {
  int sock = socket(AF_INET, SOCK_STREAM, 0);
  struct sockaddr_in addr;
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(80);
  addr.sin_addr.s_addr = 0x0100007f;
  connect(sock, &addr, sizeof(addr));
}

結果は

opening ws://127.0.0.1:80
Error in connect(): ReferenceError: WebSocket is not defined

WebScoket 必須らしい。 sleep 以外の synchronous な関数を呼んでみたいんですけど、どうしたら良いかな。

fork

ENOSYS かなと思ったら EAGAIN

#include <errno.h>
#include <unistd.h>
int main() {
  fork();
  perror("fork");
  printf("%d %d\n", errno, EAGAIN);
}

EAGAIN が "No more processes" とかいう見覚えの全く無いメッセージを出したので確認してみました…

qsort

普通に const な領域を sort するのもどうかと思うけど…

#include <stdlib.h>
int cmp(const void* a, const void* b) {
  return *(char*)a-*(char*)b;
}
int main() {
  const char* msg = "hoge";
  qsort(msg, 4, 1, cmp);
  puts(msg);
}

関数ポインタは FUNCTION_TABLE ってのに入ってて、別の空間にある感じぽい。

var FUNCTION_TABLE = [0,0,_cmp];
// EMSCRIPTEN_START_FUNCS
function _cmp($a, $b) {

まとめ

InteliOS => HTML5 converter with LLVM 書いた人は今どんな気持ちなんだろうか

http://software.intel.com/en-us/articles/technical-reference-intel-html5-app-porter-tool-beta

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h