类 Fiddle::Handle

Fiddle::Handle 是访问动态库的方式

示例

设置

libc_so = "/lib64/libc.so.6"
=> "/lib64/libc.so.6"
@handle = Fiddle::Handle.new(libc_so)
=> #<Fiddle::Handle:0x00000000d69ef8>

设置,带标志

libc_so = "/lib64/libc.so.6"
=> "/lib64/libc.so.6"
@handle = Fiddle::Handle.new(libc_so, Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
=> #<Fiddle::Handle:0x00000000d69ef8>

参见 RTLD_LAZYRTLD_GLOBAL

地址到符号

strcpy_addr = @handle['strcpy']
=> 140062278451968

strcpy_addr = @handle.sym('strcpy')
=> 140062278451968

常量

DEFAULT

DEFAULT

RTLD_DEFAULT 的预定义伪句柄

它将使用默认库搜索顺序查找所需符号的第一个出现

NEXT

NEXT

RTLD_NEXT 的预定义伪句柄

它将在当前库之后的搜索顺序中查找函数的下一个出现。

RTLD_GLOBAL

RTLD_GLOBAL

rtld Fiddle::Handle 标志。

此库定义的符号将可用于后续加载的库的符号解析。

RTLD_LAZY

RTLD_LAZY

rtld Fiddle::Handle 标志。

执行延迟绑定。仅在执行引用它们的代码时才解析符号。如果从未引用过符号,则永远不会解析它。(延迟绑定仅对函数引用执行;对变量的引用在加载库时始终立即绑定。)

RTLD_NOW

RTLD_NOW

rtld Fiddle::Handle 标志。

如果指定此值或将环境变量 LD_BIND_NOW 设置为非空字符串,则在 Fiddle.dlopen 返回之前将解析库中的所有未定义符号。如果无法完成此操作,则会返回错误。

公共类方法

sym(name) 单击以切换源

获取名为 name 的函数的地址作为 Integer。该函数通过 dlsym 在 RTLD_NEXT 上进行搜索。

有关更多信息,请参见 man(3) dlsym()。

static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
    return fiddle_handle_sym(RTLD_NEXT, sym);
}
new(library = nil, flags = Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL) 单击以切换源

创建一个新的处理程序,使用 flags 打开 library

如果未指定 library 或给定 nil,则使用 DEFAULT,它等效于 RTLD_DEFAULT。有关详细信息,请参见 man 3 dlopen

lib = Fiddle::Handle.new

默认值取决于操作系统,并为已加载的所有库提供句柄。例如,在大多数情况下,你可以使用它来访问 libc 函数或 rb_str_new 等 Ruby 函数。

static VALUE
rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
{
    void *ptr;
    struct dl_handle *fiddle_handle;
    VALUE lib, flag;
    char  *clib;
    int   cflag;
    const char *err;

    switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
      case 0:
        clib = NULL;
        cflag = RTLD_LAZY | RTLD_GLOBAL;
        break;
      case 1:
        clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
        cflag = RTLD_LAZY | RTLD_GLOBAL;
        break;
      case 2:
        clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
        cflag = NUM2INT(flag);
        break;
      default:
        rb_bug("rb_fiddle_handle_new");
    }

#if defined(_WIN32)
    if( !clib ){
        HANDLE rb_libruby_handle(void);
        ptr = rb_libruby_handle();
    }
    else if( STRCASECMP(clib, "libc") == 0
# ifdef RUBY_COREDLL
             || STRCASECMP(clib, RUBY_COREDLL) == 0
             || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
# endif
        ){
# ifdef _WIN32_WCE
        ptr = dlopen("coredll.dll", cflag);
# else
        (void)cflag;
        ptr = w32_coredll();
# endif
    }
    else
#endif
        ptr = dlopen(clib, cflag);
#if defined(HAVE_DLERROR)
    if( !ptr && (err = dlerror()) ){
        rb_raise(rb_eFiddleDLError, "%s", err);
    }
#else
    if( !ptr ){
        err = dlerror();
        rb_raise(rb_eFiddleDLError, "%s", err);
    }
#endif
    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if( fiddle_handle->ptr && fiddle_handle->open && fiddle_handle->enable_close ){
        dlclose(fiddle_handle->ptr);
    }
    fiddle_handle->ptr = ptr;
    fiddle_handle->open = 1;
    fiddle_handle->enable_close = 0;

    if( rb_block_given_p() ){
        rb_ensure(rb_yield, self, rb_fiddle_handle_close, self);
    }

    return Qnil;
}
sym(name) 单击以切换源

Integer 的形式获取名为 name 的函数的地址。

static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
    return fiddle_handle_sym(RTLD_NEXT, sym);
}
sym_defined?(p1) 单击以切换源
static VALUE
rb_fiddle_handle_s_sym_defined(VALUE self, VALUE sym)
{
    fiddle_void_func func;

    func = fiddle_handle_find_func(RTLD_NEXT, sym);

    if( func ) {
        return PTR2NUM(func);
    }
    else {
        return Qnil;
    }
}

公共实例方法

[]
别名:sym
close 单击以切换源

关闭此句柄。

多次调用 close 将引发 Fiddle::DLError 异常。

static VALUE
rb_fiddle_handle_close(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if(fiddle_handle->open) {
        int ret = dlclose(fiddle_handle->ptr);
        fiddle_handle->open = 0;

        /* Check dlclose for successful return value */
        if(ret) {
#if defined(HAVE_DLERROR)
            rb_raise(rb_eFiddleDLError, "%s", dlerror());
#else
            rb_raise(rb_eFiddleDLError, "could not close handle");
#endif
        }
        return INT2NUM(ret);
    }
    rb_raise(rb_eFiddleDLError, "dlclose() called too many times");

    UNREACHABLE;
}
close_enabled? 单击以切换源

如果在垃圾回收此句柄时将调用 dlclose(),则返回 true

有关详细信息,请参见 man(3) dlclose()。

static VALUE
rb_fiddle_handle_close_enabled_p(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);

    if(fiddle_handle->enable_close) return Qtrue;
    return Qfalse;
}
disable_close 单击以切换源

在垃圾回收此句柄时禁用对 dlclose() 的调用。

static VALUE
rb_fiddle_handle_disable_close(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    fiddle_handle->enable_close = 0;
    return Qnil;
}
enable_close 单击以切换源

在垃圾回收此句柄时启用对 dlclose() 的调用。

static VALUE
rb_fiddle_handle_enable_close(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    fiddle_handle->enable_close = 1;
    return Qnil;
}
file_name 单击以切换源

返回此句柄的文件名。

static VALUE
rb_fiddle_handle_file_name(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);

#if defined(HAVE_DLINFO) && defined(HAVE_CONST_RTLD_DI_LINKMAP)
    {
        struct link_map *lm = NULL;
        int res = dlinfo(fiddle_handle->ptr, RTLD_DI_LINKMAP, &lm);
        if (res == 0 && lm != NULL) {
            return rb_str_new_cstr(lm->l_name);
        }
        else {
#if defined(HAVE_DLERROR)
            rb_raise(rb_eFiddleDLError, "could not get handle file name: %s", dlerror());
#else
            rb_raise(rb_eFiddleDLError, "could not get handle file name");
#endif
        }
    }
#elif defined(HAVE_GETMODULEFILENAME)
    {
        char filename[MAX_PATH];
        DWORD res = GetModuleFileName(fiddle_handle->ptr, filename, MAX_PATH);
        if (res == 0) {
            rb_raise(rb_eFiddleDLError, "could not get handle file name: %s", dlerror());
        }
        return rb_str_new_cstr(filename);
    }
#else
    (void)fiddle_handle;
    return Qnil;
#endif
}
sym(name) 单击以切换源

Integer 的形式获取名为 name 的函数的地址。

static VALUE
rb_fiddle_handle_sym(VALUE self, VALUE sym)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if( ! fiddle_handle->open ){
        rb_raise(rb_eFiddleDLError, "closed handle");
    }

    return fiddle_handle_sym(fiddle_handle->ptr, sym);
}
别名:[]、[]
sym_defined?(p1) 单击以切换源
static VALUE
rb_fiddle_handle_sym_defined(VALUE self, VALUE sym)
{
    struct dl_handle *fiddle_handle;
    fiddle_void_func func;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if( ! fiddle_handle->open ){
        rb_raise(rb_eFiddleDLError, "closed handle");
    }

    func = fiddle_handle_find_func(fiddle_handle->ptr, sym);

    if( func ) {
        return PTR2NUM(func);
    }
    else {
        return Qnil;
    }
}
to_i 单击以切换源

返回此句柄的内存地址。

static VALUE
rb_fiddle_handle_to_i(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    return PTR2NUM(fiddle_handle->ptr);
}
to_ptr 单击以切换源

返回此句柄的 Fiddle::Pointer

static VALUE
rb_fiddle_handle_to_ptr(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    return rb_fiddle_ptr_new_wrap(fiddle_handle->ptr, 0, 0, self, 0);
}