libbfd

あー。

http://shinh.skr.jp/koneta/#shelang

シンボルが消された .so 内のロード、あっさりできた。 readelf とか見てたけどそんなこと以前に bfd_*dynamic_symtab* シリーズを使えばオッケー。これならシンボル情報を dynamic セクションから読むってことで、ローダが読んでる情報と同じになるはず。

先人偉い。 binutils 偉い。

libffi

http://shinh.skr.jp/koneta/#shelang

更新しないと思ってたけど更新しました。

http://d.hatena.ne.jp/shinichiro_h/20051027#1130351251

の続きです。 libffi を紹介していただいたので使ってみました。生成されていた 7400行とかあった dispatch.c が完全にいらなくなってなんかハッピーチックです。

sayさん に指摘いただいたのですが、シンボルテーブルが無い .so ファイルだとダメです。 objdump やら ld やらはシンボルテーブル無くてもシンボル名からアドレス引いてやがるのでそのへん勉強してみようと思います。あと、どうやら libc のような最初っから読まれているシンボルは dlsym(RTLD_DEFAULT, "puts") などで取れるみたいなので見つからない場合はそれを使ってみました。

追記: シンボルテーブルの無い .so ファイルは elf.h とか使って .dynsym テーブルを読めばいい。実際のシンボル名はどう見ても .rodata にある。まぁちょっと調べりゃわかりそう… readelf -r がズバリっぽい。

以下 libffi について。

インストールは gcc-core と gcc-java を散らかして、 gcc-x.x.x/libffi 内で、

$ mkdir obj
$ cd obj
$ ../configure; make; sudo make install

とかすると単体で入っていい感じです。 include/ffitarget.h はインストールされてくれないので手動でコピーします。


……面倒になったのでコードはって終わり。

#include <ffi.h>

ffi_type *get_ffi_type(reflection_type_t type) {
    switch (type) {
    case R_CHAR:
        return &ffi_type_sint8;
    case R_INT:
        return &ffi_type_sint32;
    case R_FLOAT:
        return &ffi_type_float;
    case R_PTR:
        return &ffi_type_pointer;
    default:
        return &ffi_type_void;
    }
}

int reflection_dispatch(
    reflection_t* ref, const char* name, reflection_type_t rtype,
    int arg_num, reflection_value_t* args, reflection_type_t* types,
    reflection_value_t* ret)
{
    reflection_sym_t** asym =
        (reflection_sym_t**)htab_find_slot(ref->syms, name, NO_INSERT);
    void* fp = NULL;

    if (!asym) {
#ifdef __USE_GNU
        fp = (void*)dlsym(RTLD_DEFAULT, name);
#endif
        if (fp == 0) return 1;
    }
    else {
        fp = (void*)((*asym)->fp);
    }

    {
        ffi_cif cif;
        ffi_type* as[32];
        void* vs[32];
        ffi_arg rv;
        ffi_type* rt;
        int i;

        for (i = 0; i < arg_num; i++) {
            as[i] = get_ffi_type(types[i]);
            if (as[i] == &ffi_type_void) return 1;
            vs[i] = &args[i];
        }

        rt = get_ffi_type(rtype);
        if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, arg_num, rt, as) != FFI_OK) {
            return 1;
        }

        ffi_call(&cif, FFI_FN(fp), &rv, vs);

        if (rtype != R_VOID) {
            *ret = *(reflection_value_t*)&rv;
        }

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