mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
2e87e2150e
[ruby-trunk - Bug #6496] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35846 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
573 lines
14 KiB
C
573 lines
14 KiB
C
/*
|
|
* ext/dl/dl.c
|
|
*
|
|
* doumentation:
|
|
* - Vincent Batts (vbatts@hashbangbash.com)
|
|
*
|
|
*/
|
|
#include <ruby/ruby.h>
|
|
#include <ruby/io.h>
|
|
#include <ctype.h>
|
|
#include "dl.h"
|
|
|
|
VALUE rb_mDL;
|
|
VALUE rb_eDLError;
|
|
VALUE rb_eDLTypeError;
|
|
|
|
ID rbdl_id_cdecl;
|
|
ID rbdl_id_stdcall;
|
|
|
|
#ifndef DLTYPE_SSIZE_T
|
|
# if SIZEOF_SIZE_T == SIZEOF_INT
|
|
# define DLTYPE_SSIZE_T DLTYPE_INT
|
|
# elif SIZEOF_SIZE_T == SIZEOF_LONG
|
|
# define DLTYPE_SSIZE_T DLTYPE_LONG
|
|
# elif defined HAVE_LONG_LONG && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
|
|
# define DLTYPE_SSIZE_T DLTYPE_LONG_LONG
|
|
# endif
|
|
#endif
|
|
#define DLTYPE_SIZE_T (-1*SIGNEDNESS_OF_SIZE_T*DLTYPE_SSIZE_T)
|
|
|
|
#ifndef DLTYPE_PTRDIFF_T
|
|
# if SIZEOF_PTRDIFF_T == SIZEOF_INT
|
|
# define DLTYPE_PTRDIFF_T DLTYPE_INT
|
|
# elif SIZEOF_PTRDIFF_T == SIZEOF_LONG
|
|
# define DLTYPE_PTRDIFF_T DLTYPE_LONG
|
|
# elif defined HAVE_LONG_LONG && SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
|
|
# define DLTYPE_PTRDIFF_T DLTYPE_LONG_LONG
|
|
# endif
|
|
#endif
|
|
|
|
#ifndef DLTYPE_INTPTR_T
|
|
# if SIZEOF_INTPTR_T == SIZEOF_INT
|
|
# define DLTYPE_INTPTR_T DLTYPE_INT
|
|
# elif SIZEOF_INTPTR_T == SIZEOF_LONG
|
|
# define DLTYPE_INTPTR_T DLTYPE_LONG
|
|
# elif defined HAVE_LONG_LONG && SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
|
|
# define DLTYPE_INTPTR_T DLTYPE_LONG_LONG
|
|
# endif
|
|
#endif
|
|
#define DLTYPE_UINTPTR_T (-DLTYPE_INTPTR_T)
|
|
|
|
/*
|
|
* call-seq: DL.dlopen(so_lib)
|
|
*
|
|
* 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>
|
|
*/
|
|
VALUE
|
|
rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
|
|
{
|
|
return rb_class_new_instance(argc, argv, rb_cDLHandle);
|
|
}
|
|
|
|
/*
|
|
* call-seq: DL.malloc(size)
|
|
*
|
|
* Allocate +size+ bytes of memory and return the integer memory address
|
|
* for the allocated memory.
|
|
*/
|
|
VALUE
|
|
rb_dl_malloc(VALUE self, VALUE size)
|
|
{
|
|
void *ptr;
|
|
|
|
rb_secure(4);
|
|
ptr = (void*)ruby_xmalloc(NUM2INT(size));
|
|
return PTR2NUM(ptr);
|
|
}
|
|
|
|
/*
|
|
* call-seq: DL.realloc(addr, size)
|
|
*
|
|
* 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.
|
|
*/
|
|
VALUE
|
|
rb_dl_realloc(VALUE self, VALUE addr, VALUE size)
|
|
{
|
|
void *ptr = NUM2PTR(addr);
|
|
|
|
rb_secure(4);
|
|
ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size));
|
|
return PTR2NUM(ptr);
|
|
}
|
|
|
|
/*
|
|
* call-seq: DL.free(addr)
|
|
*
|
|
* Free the memory at address +addr+
|
|
*/
|
|
VALUE
|
|
rb_dl_free(VALUE self, VALUE addr)
|
|
{
|
|
void *ptr = NUM2PTR(addr);
|
|
|
|
rb_secure(4);
|
|
ruby_xfree(ptr);
|
|
return Qnil;
|
|
}
|
|
|
|
/*
|
|
* call-seq: DL.dlunwrap(addr)
|
|
*
|
|
* 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"
|
|
*/
|
|
VALUE
|
|
rb_dl_ptr2value(VALUE self, VALUE addr)
|
|
{
|
|
rb_secure(4);
|
|
return (VALUE)NUM2PTR(addr);
|
|
}
|
|
|
|
/*
|
|
* call-seq: DL.dlwrap(val)
|
|
*
|
|
* 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
|
|
*/
|
|
VALUE
|
|
rb_dl_value2ptr(VALUE self, VALUE val)
|
|
{
|
|
return PTR2NUM((void*)val);
|
|
}
|
|
|
|
static void
|
|
rb_dl_init_callbacks(VALUE dl)
|
|
{
|
|
static const char cb[] = "dl/callback.so";
|
|
|
|
rb_autoload(dl, rb_intern_const("CdeclCallbackAddrs"), cb);
|
|
rb_autoload(dl, rb_intern_const("CdeclCallbackProcs"), cb);
|
|
#ifdef FUNC_STDCALL
|
|
rb_autoload(dl, rb_intern_const("StdcallCallbackAddrs"), cb);
|
|
rb_autoload(dl, rb_intern_const("StdcallCallbackProcs"), cb);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
Init_dl(void)
|
|
{
|
|
void Init_dlhandle(void);
|
|
void Init_dlcfunc(void);
|
|
void Init_dlptr(void);
|
|
|
|
rbdl_id_cdecl = rb_intern_const("cdecl");
|
|
rbdl_id_stdcall = rb_intern_const("stdcall");
|
|
|
|
/* Document-module: DL
|
|
*
|
|
* 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! :-)
|
|
*/
|
|
rb_mDL = rb_define_module("DL");
|
|
|
|
/*
|
|
* Document-class: DL::DLError
|
|
*
|
|
* standard dynamic load exception
|
|
*/
|
|
rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError);
|
|
|
|
/*
|
|
* Document-class: DL::DLTypeError
|
|
*
|
|
* dynamic load incorrect type exception
|
|
*/
|
|
rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError);
|
|
|
|
/* Document-const: MAX_CALLBACK
|
|
*
|
|
* Maximum number of callbacks
|
|
*/
|
|
rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK));
|
|
|
|
/* Document-const: DLSTACK_SIZE
|
|
*
|
|
* Dynamic linker stack size
|
|
*/
|
|
rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE));
|
|
|
|
rb_dl_init_callbacks(rb_mDL);
|
|
|
|
/* Document-const: RTLD_GLOBAL
|
|
*
|
|
* rtld DL::Handle flag.
|
|
*
|
|
* The symbols defined by this library will be made available for symbol
|
|
* resolution of subsequently loaded libraries.
|
|
*/
|
|
rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
|
|
|
|
/* Document-const: RTLD_LAZY
|
|
*
|
|
* rtld DL::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.)
|
|
*/
|
|
rb_define_const(rb_mDL, "RTLD_LAZY", INT2NUM(RTLD_LAZY));
|
|
|
|
/* Document-const: RTLD_NOW
|
|
*
|
|
* rtld DL::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.
|
|
*/
|
|
rb_define_const(rb_mDL, "RTLD_NOW", INT2NUM(RTLD_NOW));
|
|
|
|
/* Document-const: TYPE_VOID
|
|
*
|
|
* DL::CFunc type - void
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_VOID", INT2NUM(DLTYPE_VOID));
|
|
|
|
/* Document-const: TYPE_VOIDP
|
|
*
|
|
* DL::CFunc type - void*
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_VOIDP", INT2NUM(DLTYPE_VOIDP));
|
|
|
|
/* Document-const: TYPE_CHAR
|
|
*
|
|
* DL::CFunc type - char
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_CHAR", INT2NUM(DLTYPE_CHAR));
|
|
|
|
/* Document-const: TYPE_SHORT
|
|
*
|
|
* DL::CFunc type - short
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_SHORT", INT2NUM(DLTYPE_SHORT));
|
|
|
|
/* Document-const: TYPE_INT
|
|
*
|
|
* DL::CFunc type - int
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_INT", INT2NUM(DLTYPE_INT));
|
|
|
|
/* Document-const: TYPE_LONG
|
|
*
|
|
* DL::CFunc type - long
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_LONG", INT2NUM(DLTYPE_LONG));
|
|
|
|
#if HAVE_LONG_LONG
|
|
/* Document-const: TYPE_LONG_LONG
|
|
*
|
|
* DL::CFunc type - long long
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_LONG_LONG", INT2NUM(DLTYPE_LONG_LONG));
|
|
#endif
|
|
|
|
/* Document-const: TYPE_FLOAT
|
|
*
|
|
* DL::CFunc type - float
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_FLOAT", INT2NUM(DLTYPE_FLOAT));
|
|
|
|
/* Document-const: TYPE_DOUBLE
|
|
*
|
|
* DL::CFunc type - double
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_DOUBLE", INT2NUM(DLTYPE_DOUBLE));
|
|
|
|
/* Document-const: TYPE_SIZE_T
|
|
*
|
|
* DL::CFunc type - size_t
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_SIZE_T", INT2NUM(DLTYPE_SIZE_T));
|
|
|
|
/* Document-const: TYPE_SSIZE_T
|
|
*
|
|
* DL::CFunc type - ssize_t
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_SSIZE_T", INT2NUM(DLTYPE_SSIZE_T));
|
|
|
|
/* Document-const: TYPE_PTRDIFF_T
|
|
*
|
|
* DL::CFunc type - ptrdiff_t
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_PTRDIFF_T", INT2NUM(DLTYPE_PTRDIFF_T));
|
|
|
|
/* Document-const: TYPE_INTPTR_T
|
|
*
|
|
* DL::CFunc type - intptr_t
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_INTPTR_T", INT2NUM(DLTYPE_INTPTR_T));
|
|
|
|
/* Document-const: TYPE_UINTPTR_T
|
|
*
|
|
* DL::CFunc type - uintptr_t
|
|
*/
|
|
rb_define_const(rb_mDL, "TYPE_UINTPTR_T", INT2NUM(DLTYPE_UINTPTR_T));
|
|
|
|
/* Document-const: ALIGN_VOIDP
|
|
*
|
|
* The alignment size of a void*
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP));
|
|
|
|
/* Document-const: ALIGN_CHAR
|
|
*
|
|
* The alignment size of a char
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_CHAR", INT2NUM(ALIGN_CHAR));
|
|
|
|
/* Document-const: ALIGN_SHORT
|
|
*
|
|
* The alignment size of a short
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT));
|
|
|
|
/* Document-const: ALIGN_INT
|
|
*
|
|
* The alignment size of an int
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_INT", INT2NUM(ALIGN_INT));
|
|
|
|
/* Document-const: ALIGN_LONG
|
|
*
|
|
* The alignment size of a long
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_LONG", INT2NUM(ALIGN_LONG));
|
|
|
|
#if HAVE_LONG_LONG
|
|
/* Document-const: ALIGN_LONG_LONG
|
|
*
|
|
* The alignment size of a long long
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_LONG_LONG", INT2NUM(ALIGN_LONG_LONG));
|
|
#endif
|
|
|
|
/* Document-const: ALIGN_FLOAT
|
|
*
|
|
* The alignment size of a float
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT));
|
|
|
|
/* Document-const: ALIGN_DOUBLE
|
|
*
|
|
* The alignment size of a double
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE));
|
|
|
|
/* Document-const: ALIGN_SIZE_T
|
|
*
|
|
* The alignment size of a size_t
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_SIZE_T", INT2NUM(ALIGN_OF(size_t)));
|
|
|
|
/* Document-const: ALIGN_SSIZE_T
|
|
*
|
|
* The alignment size of a ssize_t
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_SSIZE_T", INT2NUM(ALIGN_OF(size_t))); /* same as size_t */
|
|
|
|
/* Document-const: ALIGN_PTRDIFF_T
|
|
*
|
|
* The alignment size of a ptrdiff_t
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_PTRDIFF_T", INT2NUM(ALIGN_OF(ptrdiff_t)));
|
|
|
|
/* Document-const: ALIGN_INTPTR_T
|
|
*
|
|
* The alignment size of a intptr_t
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_INTPTR_T", INT2NUM(ALIGN_OF(intptr_t)));
|
|
|
|
/* Document-const: ALIGN_UINTPTR_T
|
|
*
|
|
* The alignment size of a uintptr_t
|
|
*/
|
|
rb_define_const(rb_mDL, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t)));
|
|
|
|
/* Document-const: SIZEOF_VOIDP
|
|
*
|
|
* size of a void*
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_VOIDP", INT2NUM(sizeof(void*)));
|
|
|
|
/* Document-const: SIZEOF_CHAR
|
|
*
|
|
* size of a char
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_CHAR", INT2NUM(sizeof(char)));
|
|
|
|
/* Document-const: SIZEOF_SHORT
|
|
*
|
|
* size of a short
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_SHORT", INT2NUM(sizeof(short)));
|
|
|
|
/* Document-const: SIZEOF_INT
|
|
*
|
|
* size of an int
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_INT", INT2NUM(sizeof(int)));
|
|
|
|
/* Document-const: SIZEOF_LONG
|
|
*
|
|
* size of a long
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_LONG", INT2NUM(sizeof(long)));
|
|
|
|
#if HAVE_LONG_LONG
|
|
/* Document-const: SIZEOF_LONG_LONG
|
|
*
|
|
* size of a long long
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_LONG_LONG", INT2NUM(sizeof(LONG_LONG)));
|
|
#endif
|
|
|
|
/* Document-const: SIZEOF_FLOAT
|
|
*
|
|
* size of a float
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_FLOAT", INT2NUM(sizeof(float)));
|
|
|
|
/* Document-const: SIZEOF_DOUBLE
|
|
*
|
|
* size of a double
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_DOUBLE",INT2NUM(sizeof(double)));
|
|
|
|
/* Document-const: SIZEOF_SIZE_T
|
|
*
|
|
* size of a size_t
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_SIZE_T", INT2NUM(sizeof(size_t)));
|
|
|
|
/* Document-const: SIZEOF_SSIZE_T
|
|
*
|
|
* size of a ssize_t
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_SSIZE_T", INT2NUM(sizeof(size_t))); /* same as size_t */
|
|
|
|
/* Document-const: SIZEOF_PTRDIFF_T
|
|
*
|
|
* size of a ptrdiff_t
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_PTRDIFF_T", INT2NUM(sizeof(ptrdiff_t)));
|
|
|
|
/* Document-const: SIZEOF_INTPTR_T
|
|
*
|
|
* size of a intptr_t
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_INTPTR_T", INT2NUM(sizeof(intptr_t)));
|
|
|
|
/* Document-const: SIZEOF_UINTPTR_T
|
|
*
|
|
* size of a uintptr_t
|
|
*/
|
|
rb_define_const(rb_mDL, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t)));
|
|
|
|
rb_define_module_function(rb_mDL, "dlwrap", rb_dl_value2ptr, 1);
|
|
rb_define_module_function(rb_mDL, "dlunwrap", rb_dl_ptr2value, 1);
|
|
|
|
rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1);
|
|
rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1);
|
|
rb_define_module_function(rb_mDL, "realloc", rb_dl_realloc, 2);
|
|
rb_define_module_function(rb_mDL, "free", rb_dl_free, 1);
|
|
|
|
/* Document-const: RUBY_FREE
|
|
*
|
|
* Address of the ruby_xfree() function
|
|
*/
|
|
rb_define_const(rb_mDL, "RUBY_FREE", PTR2NUM(ruby_xfree));
|
|
|
|
/* Document-const: BUILD_RUBY_PLATFORM
|
|
*
|
|
* Platform built against (i.e. "x86_64-linux", etc.)
|
|
*
|
|
* See also RUBY_PLATFORM
|
|
*/
|
|
rb_define_const(rb_mDL, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM));
|
|
|
|
/* Document-const: BUILD_RUBY_VERSION
|
|
*
|
|
* Ruby Version built. (i.e. "1.9.3")
|
|
*
|
|
* See also RUBY_VERSION
|
|
*/
|
|
rb_define_const(rb_mDL, "BUILD_RUBY_VERSION", rb_str_new2(RUBY_VERSION));
|
|
|
|
Init_dlhandle();
|
|
Init_dlcfunc();
|
|
Init_dlptr();
|
|
}
|