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. Если это невозможно, возвращается ошибка.
Открытые методы класса
static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
return fiddle_handle_sym(RTLD_NEXT, sym);
} Получает адрес в виде Integer функции с именем name. Поиск функции выполняется с помощью dlsym в RTLD_NEXT.
Дополнительные сведения см. в man(3) dlsym().
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;
} Создаёт новый дескриптор, открывающий library с помощью flags.
Если library не указан или задано nil, используется DEFAULT, что эквивалентно RTLD_DEFAULT. Подробнее см. man 3 dlopen.
lib = Fiddle::Handle.new
Значение по умолчанию зависит от ОС и предоставляет дескриптор для всех уже загруженных библиотек. Например, в большинстве случаев с его помощью можно получить доступ к функциям libc или функциям Ruby, таким как rb_str_new.
# File ext/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 static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
return fiddle_handle_sym(RTLD_NEXT, sym);
} Получает адрес в виде Integer функции с именем name.
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;
}
} Открытые методы экземпляра
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 вызовет исключение Fiddle::DLError.
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;
} Возвращает true, если при сборке мусора для этого дескриптора будет вызвана dlclose().
Дополнительные сведения см. в man(3) 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;
} Включает вызов dlclose() при сборке мусора для этого дескриптора.
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
} Возвращает имя файла этого дескриптора.
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);
} Получает адрес в виде Integer функции с именем name.
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);
} Возвращает адрес памяти этого дескриптора.
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);
} Возвращает Fiddle::Pointer этого дескриптора.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.