読者です 読者をやめる 読者になる 読者になる

#9 iOS で動的にインクリメント関数を実装する

カヤックのAdvent Calendar 9日目は @Gemmbu がお送りします。

iOS でも実行時に確保したメモリ上のコードが動作することはある界隈では有名ですが、
手元で試したことがある方はすくないのではと思います。
そこで実行時に確保したメモリ上に、与えられた数値に 1 加算して返す関数を実装し動作させてみましょう。

流れ

  • 与えられた数値に 1 加算して返すコードを書く
  • アライメントを意識してメモリを確保する
  • 確保したメモリにコードを書き込む
  • 確保したメモリに実行権限を付与する
  • 確保したメモリを関数として実行する

サンプルコード

#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>

// 与えられた数値に 1 加算して返すコード書く
// 以下は armv7s 用のコードであり、armv7 及び arm64 ではそれぞれ別のコードにする必要がある。
uint32_t code[] = {
    0xe2800001,    // add r0, r0, #1
    0xe12fff1e,    // br  lr
};

// アライメントを意識してメモリを確保する
uint32_t *p;
long pagesize = sysconf(_SC_PAGE_SIZE);
NSLog(@"pagesize %@", @(pagesize));
int r = posix_memalign((void **)&p, pagesize, pagesize);
if(r != 0){
    int err = errno;
    NSCAssert(NO, @"posix_memalign failed %s(%d) ", strerror(err), err);
}

// 確保したメモリにコードを書き込む
memcpy(p, code, sizeof(code));

// 確保したメモリに実行権限を付与する
int errcode = mprotect(p, pagesize, PROT_READ | PROT_EXEC);
if (errcode != 0) {
    int err = errno;
    NSCAssert(NO, @"mprotect failed %s(%d) ", strerror(err), err);
}

// 確保したメモリを関数として実行する
NSLog(@"inc(1) = %d", ((int(*)(int))p)(1));    // > inc(1) = 2
...

ここから https://github.com/KAMEDAkyosuke/ios-dynamic-function コードを取得できます

これを応用することでオレオレ言語にオレオレ jit を乗せることもできちゃいますね。
カヤックでオレオレ言語といえばうんこ演算で使用されている Unko Script。
この Unko Script を jit 化して高速化したい情熱のある人はいないでしょうか。

NOTE
Unko Script は Scheme を元にして作られた関数型言語です。

明日は

アドベントカレンダー10日目を担当してくださるのは、組長さんです。
カヤックのサービスを支えてくださりいつもありがとうございます。

カヤックではエンジニアを大募集しています

カヤックでは普通の iOS エンジニアだけでなく、やりたいことを実現するためなら c 言語よりさらに下に潜ってもいいエンジニアを募集しております。

社員と直接話せるイベント、1社だけの合同説明会を、1月17日(土)に渋谷ヒカリエで開催します!!!

ぜひご参加ください