2011年1月22日土曜日

cacheflush が undefined reference で dalvik のコンパイルに失敗 (解決)

次の条件が成り立っているとき:

  (1) Android のソースコードツリーから dalvik だけ取りだして利用しようとして,
  (2) bionic libc (これは Android ソースコードツリーに含まれる) を使わず,
  (3) 使用する外部ツールチェーンが cacheflush システムコールへの C 言語インターフェースを提供していない

dalvik を WITH_JIT=true (JIT を有効にする) でコンパイルすると, dalvik/vm/compiler/codegen/arm/Assemble.c が cacheflush() を呼んでいるため, undefined reference エラーでリンクに失敗する.

こういう場合は, cacheflush システムコールへの C 言語インターフェースを自分で実装しなければならないと思われるが, アセンブリ言語で書くのは面倒くさい. ラッキーなことに, syscall() という関数を使用すると, アセンブリ言語を使わずに任意のシステムコールを呼べるようだ. 確信はないが, おそらく次のようなコードで cacheflush() を実装できると思う.

    /* For the prototype of syscall(). */
    #define _GNU_SOURCE
    #include <unistd.h>

    /* For __ARM_NR_cacheflush */
    #include <asm/unistd.h>

    int cacheflush(long start, long end, long flags)
    {
        return syscall(__ARM_NR_cacheflush, start, end, flags);
    }


Fails to compile dalvik due to undefined reference to cacheflush (solved)

When the following conditions meet:

  (1) You are trying to extract only 'dalvik' from the Android source code tree and use it, and
  (2) 'bionic libc' (which is contained in the Android source code tree) is not used, and
  (3) the external toolchain you are using does not provide the C-language interface to the 'cacheflush' system call.

an attempt to compile 'dalvik' with WITH_JIT=true (to enable Just In Time compilation) will fail in the 'link' stage due to 'undefined reference' errors because dalvik/vm/compiler/codegen/arm/Assemble.c calls cacheflush().

In this case, I think we have to implement the C-language interface to the 'cacheflush' system call ourselves, but it is cumbersome to implement it in assembly language. Luckily, it seems that a function named syscall() allows us to call an arbitrary system call without using assembly language. I'm not sure but code like the following will perhaps work as cacheflush().

    /* For the prototype of syscall(). */
    #define _GNU_SOURCE
    #include <unistd.h>

    /* For __ARM_NR_cacheflush */
    #include <asm/unistd.h>

    int cacheflush(long start, long end, long flags)
    {
        return syscall(__ARM_NR_cacheflush, start, end, flags);
    }