class 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_LAZY 和 RTLD_GLOBAL
符号的地址¶ ↑
strcpy_addr = @handle['strcpy'] => 140062278451968
或
strcpy_addr = @handle.sym('strcpy')
=> 140062278451968
常量
- DEFAULT
-
一个预定义的 RTLD_DEFAULT 伪句柄
它将使用默认的库搜索顺序查找所需符号的第一次出现
- NEXT
-
一个预定义的 RTLD_NEXT 伪句柄
它将在当前库之后,按搜索顺序查找函数的下一次出现。
- RTLD_GLOBAL
-
rtld
Fiddle::Handle标志。此库定义的符号将可用于后续加载的库的符号解析。
- RTLD_LAZY
-
rtld
Fiddle::Handle标志。执行延迟绑定。仅当执行引用符号的代码时才解析符号。如果从不引用该符号,则永远不会解析它。(延迟绑定仅对函数引用执行;对变量的引用总是在加载库时立即绑定。)
- RTLD_NOW
-
rtld
Fiddle::Handle标志。如果指定此值或环境变量 LD_BIND_NOW 设置为非空字符串,则在
Fiddle.dlopen返回之前,将解析库中所有未定义的符号。如果无法完成,则会返回错误。
公共类方法
获取名为 name 的函数的地址,作为整数。该函数通过 RTLD_NEXT 上的 dlsym 搜索。
有关更多信息,请参阅 man(3) dlsym()。
static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
return fiddle_handle_sym(RTLD_NEXT, sym);
}
创建一个新的处理程序,该处理程序使用 flags 打开 library。
如果未指定 library 或给定 nil,则使用 DEFAULT,它等效于 RTLD_DEFAULT。有关更多信息,请参阅 man 3 dlopen。
lib = Fiddle::Handle.new
默认值取决于操作系统,并为已加载的所有库提供句柄。例如,在大多数情况下,您可以使用它来访问 libc 函数,或 ruby 函数,如 rb_str_new。
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;
}
# File fiddle/lib/fiddle/ffi_backend.rb, line 488 def initialize(libname = nil, flags = RTLD_LAZY | RTLD_GLOBAL) begin @lib = FFI::DynamicLibrary.open(libname, flags) rescue LoadError, RuntimeError # LoadError for JRuby, RuntimeError for TruffleRuby raise DLError, "Could not open #{libname}" end @open = true begin yield(self) ensure self.close end if block_given? end
获取名为 name 的函数的地址,作为整数。
static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
return fiddle_handle_sym(RTLD_NEXT, sym);
}
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;
}
}
公共实例方法
关闭此句柄。
多次调用 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;
}
如果在此句柄被垃圾回收时将调用 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;
}
禁用在此句柄被垃圾回收时调用 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;
}
启用在此句柄被垃圾回收时调用 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;
}
返回此句柄的文件名。
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
}
获取名为 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);
}
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;
}
}
返回此句柄的内存地址。
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);
}
返回此句柄的 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);
}