Module: DL

Included in:
Function, Importer
Defined in:
dl.c,
lib/dl.rb,
lib/dl/func.rb,
lib/dl/pack.rb,
lib/dl/stack.rb,
lib/dl/value.rb,
lib/dl/types.rb,
lib/dl/struct.rb,
lib/dl/import.rb,
lib/dl/cparser.rb,
lib/dl/callback.rb,
dl.c

Overview

A bridge to the dlopen() or dynamic library linker function.

Example

bash $> cat > sum.c <<EOF
double sum(double *arry, int len)
{
        double ret = 0;
        int i;
        for(i = 0; i < len; i++){
                ret = ret + arry[i];
        }
        return ret;
}

double split(double num)
{
        double ret = 0;
        ret = num / 2;
        return ret;
}
EOF
bash $> gcc -o libsum.so -shared sum.c
bash $> cat > sum.rb <<EOF
require 'dl'
require 'dl/import'

module LibSum
        extend DL::Importer
        dlload './libsum.so'
        extern 'double sum(double*, int)'
        extern 'double split(double)'
end

a = [2.0, 3.0, 4.0]

sum = LibSum.sum(a.pack("d*"), a.count)
p LibSum.split(sum)
EOF
bash $> ruby sum.rb
4.5

WIN! :-)

Defined Under Namespace

Modules: BasicTypes, CParser, CStructBuilder, Importer, PackInfo, ValueUtil, Win32Types Classes: CFunc, CPtr, CStruct, CStructEntity, CUnion, CUnionEntity, CarriedFunction, CompositeHandler, DLError, DLTypeError, Function, Handle, Packer, Stack, TempFunction

Constant Summary collapse

SEM =

The mutual exclusion (Mutex) semaphore for the DL module

Mutex.new
CdeclCallbackProcs =

A Hash of callback Procs

Uses Fiddle

tmp
CdeclCallbackAddrs =

A Hash of the addresses of callback Proc

Uses Fiddle

tmp
StdcallCallbackProcs =

A Hash of Stdcall callback Procs

Uses Fiddle on win32

tmp
StdcallCallbackAddrs =

A Hash of the addresses of Stdcall callback Procs

Uses Fiddle on win32

tmp
MAX_CALLBACK =

Maximum number of callbacks

INT2NUM(MAX_CALLBACK)
DLSTACK_SIZE =

Dynamic linker stack size

INT2NUM(DLSTACK_SIZE)
RTLD_GLOBAL =

:Handle flag.

The symbols defined by this library will be made available for symbol resolution of subsequently loaded libraries.

rtld DL
RTLD_LAZY =

:Handle flag.

Perform lazy binding. Only resolve symbols as the code that references them is executed. If the symbol is never referenced, then it is never resolved. (Lazy binding is only performed for function references; references to variables are always immediately bound when the library is loaded.)

rtld DL
RTLD_NOW =

:Handle flag.

If this value is specified or the environment variable LD_BIND_NOW is set to a nonempty string, all undefined symbols in the library are resolved before dlopen() returns. If this cannot be done an error is returned.

rtld DL
TYPE_VOID =

:CFunc type - void

DL
TYPE_VOIDP =

:CFunc type - void*

DL
TYPE_CHAR =

:CFunc type - char

DL
TYPE_SHORT =

:CFunc type - short

DL
TYPE_INT =

:CFunc type - int

DL
TYPE_LONG =

:CFunc type - long

DL
TYPE_LONG_LONG =

:CFunc type - long long

DL
TYPE_FLOAT =

:CFunc type - float

DL
TYPE_DOUBLE =

:CFunc type - double

DL
TYPE_SIZE_T =

:CFunc type - size_t

DL
TYPE_SSIZE_T =

:CFunc type - ssize_t

DL
TYPE_PTRDIFF_T =

:CFunc type - ptrdiff_t

DL
TYPE_INTPTR_T =

:CFunc type - intptr_t

DL
TYPE_UINTPTR_T =

:CFunc type - uintptr_t

DL
ALIGN_VOIDP =

The alignment size of a void*

INT2NUM(ALIGN_VOIDP)
ALIGN_CHAR =

The alignment size of a char

INT2NUM(ALIGN_CHAR)
ALIGN_SHORT =

The alignment size of a short

INT2NUM(ALIGN_SHORT)
ALIGN_INT =

The alignment size of an int

INT2NUM(ALIGN_INT)
ALIGN_LONG =

The alignment size of a long

INT2NUM(ALIGN_LONG)
ALIGN_LONG_LONG =

The alignment size of a long long

INT2NUM(ALIGN_LONG_LONG)
ALIGN_FLOAT =

The alignment size of a float

INT2NUM(ALIGN_FLOAT)
ALIGN_DOUBLE =

The alignment size of a double

INT2NUM(ALIGN_DOUBLE)
ALIGN_SIZE_T =

The alignment size of a size_t

INT2NUM(ALIGN_OF(size_t))
ALIGN_SSIZE_T =

same as size_t

INT2NUM(ALIGN_OF(size_t))
ALIGN_PTRDIFF_T =

The alignment size of a ptrdiff_t

INT2NUM(ALIGN_OF(ptrdiff_t))
ALIGN_INTPTR_T =

The alignment size of a intptr_t

INT2NUM(ALIGN_OF(intptr_t))
ALIGN_UINTPTR_T =

The alignment size of a uintptr_t

INT2NUM(ALIGN_OF(uintptr_t))
SIZEOF_VOIDP =

size of a void*

INT2NUM(sizeof(void*))
SIZEOF_CHAR =

size of a char

INT2NUM(sizeof(char))
SIZEOF_SHORT =

size of a short

INT2NUM(sizeof(short))
SIZEOF_INT =

size of an int

INT2NUM(sizeof(int))
SIZEOF_LONG =

size of a long

INT2NUM(sizeof(long))
SIZEOF_LONG_LONG =

size of a long long

INT2NUM(sizeof(LONG_LONG))
SIZEOF_FLOAT =

size of a float

INT2NUM(sizeof(float))
SIZEOF_DOUBLE =

size of a double

INT2NUM(sizeof(double))
SIZEOF_SIZE_T =

size of a size_t

INT2NUM(sizeof(size_t))
SIZEOF_SSIZE_T =

same as size_t

INT2NUM(sizeof(size_t))
SIZEOF_PTRDIFF_T =

size of a ptrdiff_t

INT2NUM(sizeof(ptrdiff_t))
SIZEOF_INTPTR_T =

size of a intptr_t

INT2NUM(sizeof(intptr_t))
SIZEOF_UINTPTR_T =

size of a uintptr_t

INT2NUM(sizeof(uintptr_t))
RUBY_FREE =

Address of the ruby_xfree() function

PTR2NUM(ruby_xfree)
BUILD_RUBY_PLATFORM =

Platform built against (i.e. “x86_64-linux”, etc.)

See also RUBY_PLATFORM

rb_str_new2(RUBY_PLATFORM)
BUILD_RUBY_VERSION =

Ruby Version built. (i.e. “1.9.3”)

See also RUBY_VERSION

rb_str_new2(RUBY_VERSION)
NULL =

A NULL pointer

rb_dlptr_new(0, 0, 0)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.dlopen(so_lib) ⇒ Object

An interface to the dynamic linking loader

This is a shortcut to DL::Handle.new and takes the same arguments.

Example:

libc_so = "/lib64/libc.so.6"
=> "/lib64/libc.so.6"

libc = DL.dlopen(libc_so)
=> #<DL::Handle:0x00000000e05b00>


67
68
69
70
71
# File 'dl.c', line 67

VALUE
rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
{
    return rb_class_new_instance(argc, argv, rb_cDLHandle);
}

.dlunwrap(addr) ⇒ Object

Returns the hexadecimal representation of a memory pointer address addr

Example:

lib = DL.dlopen('/lib64/libc-2.15.so')
=> #<DL::Handle:0x00000001342460>

lib['strcpy'].to_s(16)
=> "7f59de6dd240"

DL.dlunwrap(DL.dlwrap(lib['strcpy'].to_s(16)))
=> "7f59de6dd240"


134
135
136
137
138
# File 'dl.c', line 134

VALUE
rb_dl_ptr2value(VALUE self, VALUE addr)
{
    return (VALUE)NUM2PTR(addr);
}

.dlwrap(val) ⇒ Object

Returns a memory pointer of a function's hexadecimal address location val

Example:

lib = DL.dlopen('/lib64/libc-2.15.so')
=> #<DL::Handle:0x00000001342460>

DL.dlwrap(lib['strcpy'].to_s(16))
=> 25522520


153
154
155
156
157
# File 'dl.c', line 153

VALUE
rb_dl_value2ptr(VALUE self, VALUE val)
{
    return PTR2NUM((void*)val);
}

.fiddle?Boolean

Returns true if DL is using Fiddle, the libffi wrapper.

Returns:

  • (Boolean)


12
13
14
# File 'lib/dl.rb', line 12

def self.fiddle?
  Object.const_defined?(:Fiddle)
end

.free(addr) ⇒ Object

Free the memory at address addr



109
110
111
112
113
114
115
116
# File 'dl.c', line 109

VALUE
rb_dl_free(VALUE self, VALUE addr)
{
    void *ptr = NUM2PTR(addr);

    ruby_xfree(ptr);
    return Qnil;
}

.malloc(size) ⇒ Object

Allocate size bytes of memory and return the integer memory address for the allocated memory.



79
80
81
82
83
84
85
86
# File 'dl.c', line 79

VALUE
rb_dl_malloc(VALUE self, VALUE size)
{
    void *ptr;

    ptr = (void*)ruby_xmalloc(NUM2INT(size));
    return PTR2NUM(ptr);
}

.realloc(addr, size) ⇒ Object

Change the size of the memory allocated at the memory location addr to size bytes. Returns the memory address of the reallocated memory, which may be different than the address passed in.



95
96
97
98
99
100
101
102
# File 'dl.c', line 95

VALUE
rb_dl_realloc(VALUE self, VALUE addr, VALUE size)
{
    void *ptr = NUM2PTR(addr);

    ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size));
    return PTR2NUM(ptr);
}

Instance Method Details

#remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/dl/callback.rb', line 70

def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
  if DL.fiddle?
    addr = addr.to_i
    return false unless proc_entry.key?(addr)
    proc_entry.delete(addr)
    true
  else
    index = nil
    if( ctype )
      addr_entry[ctype].each_with_index{|xaddr, idx|
        if( xaddr == addr )
          index = idx
        end
      }
    else
      addr_entry.each{|ty,entry|
        entry.each_with_index{|xaddr, idx|
          if( xaddr == addr )
            index = idx
          end
        }
      }
    end
    if( index and proc_entry[ctype][index] )
      proc_entry[ctype][index] = nil
      return true
    else
      return false
    end
  end
end

#remove_cdecl_callback(addr, ctype = nil) ⇒ Object Also known as: remove_callback



102
103
104
# File 'lib/dl/callback.rb', line 102

def remove_cdecl_callback(addr, ctype = nil)
  remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype)
end

#remove_stdcall_callback(addr, ctype = nil) ⇒ Object



106
107
108
# File 'lib/dl/callback.rb', line 106

def remove_stdcall_callback(addr, ctype = nil)
  remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype)
end

#set_callback_internal(proc_entry, addr_entry, argc, ty, abi = nil, &cbp) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/dl/callback.rb', line 30

def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = nil, &cbp)
  if( argc < 0 )
    raise(ArgumentError, "arity should not be less than 0.")
  end
  addr = nil

  if DL.fiddle?
    abi ||= Fiddle::Function::DEFAULT
    closure = Fiddle::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp)
    proc_entry[closure.to_i] = closure
    addr = closure.to_i
  else
    SEM.synchronize{
      ary = proc_entry[ty]
      (0...MAX_CALLBACK).each{|n|
        idx = (n * DLSTACK_SIZE) + argc
        if( ary[idx].nil? )
          ary[idx] = cbp
          addr = addr_entry[ty][idx]
          break
        end
      }
    }
  end

  addr
end

#set_cdecl_callback(ty, argc, &cbp) ⇒ Object Also known as: set_callback



58
59
60
# File 'lib/dl/callback.rb', line 58

def set_cdecl_callback(ty, argc, &cbp)
  set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp)
end

#set_stdcall_callback(ty, argc, &cbp) ⇒ Object



62
63
64
65
66
67
68
# File 'lib/dl/callback.rb', line 62

def set_stdcall_callback(ty, argc, &cbp)
  if DL.fiddle?
    set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, Fiddle::Function::STDCALL, &cbp)
  else
    set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
  end
end