17

ライブラリ自体の中から共有ライブラリのパスを取得するにはどうすればよいですか?

言い換えると、ライブラリXがをdlopen()使用してロードされているとしましょう。ライブラリ自体の内部からライブラリをロードするために使用されたパスにアクセスするにはどうすればよいですか?

そもそもライブラリをロードしたエージェントにこのパラメータを渡してもらうことはできないことに注意してください。

更新:静的変数を操作する方法は次のとおりです。

std::string wdir;

namespace {
    class dynamic_library_load_unload_handler {
         public:
              dynamic_library_load_unload_handler(){
                    Dl_info dl_info;
                    dladdr((void *) NP_Initialize, &dl_info);

                    std::string path(dl_info.dli_fname);
                    wdir = path.substr( 0, path.find_last_of( '/' ) +1 );
              }
              ~dynamic_library_load_unload_handler(){
                    // Code to execute when the library is unloaded
              }
    } dynamic_library_load_unload_handler_hook;
}
4

2 に答える 2

21

ダイナミックリンカは実際にいくつかの場所を検索して、各ダイナミックライブラリを見つけます。これらには(man ld.soから)が含まれます:

  • 環境変数によって与えられるパスLD_LIBRARY_PATH
  • バイナリにベイクされたパスは、DT_RUNPATHエントリの下のライブラリをロードします
  • キャッシュファイル/etc/ld.so.cache
  • /libおよび/usr/ lib

特定の共有ライブラリのパスを取得したい場合は、このdladdr関数をお勧めします。マニュアルページから:

関数dladdr()は関数ポインターを受け取り、それが配置されている名前とファイルを解決しようとします。情報は次の Dl_info構造に格納されます。

typedef struct {
    const char *dli_fname;  /* Pathname of shared object that
                               contains address */
    void       *dli_fbase;  /* Address at which shared object
                               is loaded */
    const char *dli_sname;  /* Name of nearest symbol with address
                               lower than addr */
    void       *dli_saddr;  /* Exact address of symbol named
                               in dli_sname */
} Dl_info;

addrに一致するシンボルが見つからなかった場合、dli_snameおよび dli_saddrはに設定されNULLます。

dladdr()エラーの場合は0を返し、成功の場合はゼロ以外を返します。

したがって、関数ポインタを指定するだけで、それを提供するファイルの名前とその他の情報が提供されます。したがって、たとえば、ライブラリ内のコンストラクターでこれを呼び出して、ライブラリのフルパスを見つけることができます。

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

__attribute__((constructor))
void on_load(void) {
    Dl_info dl_info;
    dladdr((void *)on_load, &dl_info);
    fprintf(stderr, "module %s loaded\n", dl_info.dli_fname);
}

この関数は、同じセマンティクスを持つOSXでも機能します。

于 2009-11-05T15:24:44.893 に答える
0

dl_info.dli_fnameにはAndroidのフルパスが常に含まれているとは限らないため(ここを参照)、フルパスを取得するには/ proc / self/mapsを解析する必要があります。

string GetSelfPath()
{
    string selfPath;
    Dl_info di;
    dladdr((void*)GetSelfPath, &di);
    LOGC("GetSelfPath:%08X,dli_fbase:%08X,dli_saddr:%08X,dli_fname:%s,dli_sname:%s", GetSelfPath, di.dli_fbase, di.dli_saddr, di.dli_fname, di.dli_sname);
    //dl_info.dli_fname not always contain full path in android,see android.googlesource.com/platform/bionic/+/… line 141
    if (strrchr(di.dli_fname, '/') != NULL)
    {
        selfPath=di.dli_fname;
    }
    else selfPath= GetPathByFileName(di.dli_fname);
    LOGC("self path:%s", selfPath.c_str());
    return selfPath;
}

string GetPathByFileName(string targetFilename)
{
    FILE *fp = fopen("/proc/self/maps", "r");
    if (NULL == fp) {
        return "";
    }
    const size_t BUFFER_SIZE = 256;
    char buffer[BUFFER_SIZE] = "";
    char path[BUFFER_SIZE] = "";

    while (fgets(buffer, BUFFER_SIZE, fp)) {
        if (sscanf(buffer, "%*llx-%*llx %*s %*s %*s %*s %s", path) == 1) {
            char *bname = basename(path);
            LOGC("check basename[%s]", bname);
            if (strcasecmp(bname, targetFilename.c_str()) == 0) {
                fclose(fp);
                return path;
            }
        }
    }
    fclose(fp);
    return "";
}
于 2019-02-19T10:29:13.927 に答える