1/* 2 * ext/dl/dl.c 3 * 4 * doumentation: 5 * - Vincent Batts (vbatts@hashbangbash.com) 6 * 7 */ 8#include <ruby/ruby.h> 9#include <ruby/io.h> 10#include <ctype.h> 11#include "dl.h" 12 13VALUE rb_mDL; 14VALUE rb_eDLError; 15VALUE rb_eDLTypeError; 16 17ID rbdl_id_cdecl; 18ID rbdl_id_stdcall; 19 20#ifndef DLTYPE_SSIZE_T 21# if SIZEOF_SIZE_T == SIZEOF_INT 22# define DLTYPE_SSIZE_T DLTYPE_INT 23# elif SIZEOF_SIZE_T == SIZEOF_LONG 24# define DLTYPE_SSIZE_T DLTYPE_LONG 25# elif defined HAVE_LONG_LONG && SIZEOF_SIZE_T == SIZEOF_LONG_LONG 26# define DLTYPE_SSIZE_T DLTYPE_LONG_LONG 27# endif 28#endif 29#define DLTYPE_SIZE_T (-1*SIGNEDNESS_OF_SIZE_T*DLTYPE_SSIZE_T) 30 31#ifndef DLTYPE_PTRDIFF_T 32# if SIZEOF_PTRDIFF_T == SIZEOF_INT 33# define DLTYPE_PTRDIFF_T DLTYPE_INT 34# elif SIZEOF_PTRDIFF_T == SIZEOF_LONG 35# define DLTYPE_PTRDIFF_T DLTYPE_LONG 36# elif defined HAVE_LONG_LONG && SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG 37# define DLTYPE_PTRDIFF_T DLTYPE_LONG_LONG 38# endif 39#endif 40 41#ifndef DLTYPE_INTPTR_T 42# if SIZEOF_INTPTR_T == SIZEOF_INT 43# define DLTYPE_INTPTR_T DLTYPE_INT 44# elif SIZEOF_INTPTR_T == SIZEOF_LONG 45# define DLTYPE_INTPTR_T DLTYPE_LONG 46# elif defined HAVE_LONG_LONG && SIZEOF_INTPTR_T == SIZEOF_LONG_LONG 47# define DLTYPE_INTPTR_T DLTYPE_LONG_LONG 48# endif 49#endif 50#define DLTYPE_UINTPTR_T (-DLTYPE_INTPTR_T) 51 52/* 53 * call-seq: DL.dlopen(so_lib) 54 * 55 * An interface to the dynamic linking loader 56 * 57 * This is a shortcut to DL::Handle.new and takes the same arguments. 58 * 59 * Example: 60 * 61 * libc_so = "/lib64/libc.so.6" 62 * => "/lib64/libc.so.6" 63 * 64 * libc = DL.dlopen(libc_so) 65 * => #<DL::Handle:0x00000000e05b00> 66 */ 67VALUE 68rb_dl_dlopen(int argc, VALUE argv[], VALUE self) 69{ 70 return rb_class_new_instance(argc, argv, rb_cDLHandle); 71} 72 73/* 74 * call-seq: DL.malloc(size) 75 * 76 * Allocate +size+ bytes of memory and return the integer memory address 77 * for the allocated memory. 78 */ 79VALUE 80rb_dl_malloc(VALUE self, VALUE size) 81{ 82 void *ptr; 83 84 rb_secure(4); 85 ptr = (void*)ruby_xmalloc(NUM2INT(size)); 86 return PTR2NUM(ptr); 87} 88 89/* 90 * call-seq: DL.realloc(addr, size) 91 * 92 * Change the size of the memory allocated at the memory location +addr+ to 93 * +size+ bytes. Returns the memory address of the reallocated memory, which 94 * may be different than the address passed in. 95 */ 96VALUE 97rb_dl_realloc(VALUE self, VALUE addr, VALUE size) 98{ 99 void *ptr = NUM2PTR(addr); 100 101 rb_secure(4); 102 ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size)); 103 return PTR2NUM(ptr); 104} 105 106/* 107 * call-seq: DL.free(addr) 108 * 109 * Free the memory at address +addr+ 110 */ 111VALUE 112rb_dl_free(VALUE self, VALUE addr) 113{ 114 void *ptr = NUM2PTR(addr); 115 116 rb_secure(4); 117 ruby_xfree(ptr); 118 return Qnil; 119} 120 121/* 122 * call-seq: DL.dlunwrap(addr) 123 * 124 * Returns the hexadecimal representation of a memory pointer address +addr+ 125 * 126 * Example: 127 * 128 * lib = DL.dlopen('/lib64/libc-2.15.so') 129 * => #<DL::Handle:0x00000001342460> 130 * 131 * lib['strcpy'].to_s(16) 132 * => "7f59de6dd240" 133 * 134 * DL.dlunwrap(DL.dlwrap(lib['strcpy'].to_s(16))) 135 * => "7f59de6dd240" 136 */ 137VALUE 138rb_dl_ptr2value(VALUE self, VALUE addr) 139{ 140 rb_secure(4); 141 return (VALUE)NUM2PTR(addr); 142} 143 144/* 145 * call-seq: DL.dlwrap(val) 146 * 147 * Returns a memory pointer of a function's hexadecimal address location +val+ 148 * 149 * Example: 150 * 151 * lib = DL.dlopen('/lib64/libc-2.15.so') 152 * => #<DL::Handle:0x00000001342460> 153 * 154 * DL.dlwrap(lib['strcpy'].to_s(16)) 155 * => 25522520 156 */ 157VALUE 158rb_dl_value2ptr(VALUE self, VALUE val) 159{ 160 return PTR2NUM((void*)val); 161} 162 163static void 164rb_dl_init_callbacks(VALUE dl) 165{ 166 static const char cb[] = "dl/callback.so"; 167 168 rb_autoload(dl, rb_intern_const("CdeclCallbackAddrs"), cb); 169 rb_autoload(dl, rb_intern_const("CdeclCallbackProcs"), cb); 170#ifdef FUNC_STDCALL 171 rb_autoload(dl, rb_intern_const("StdcallCallbackAddrs"), cb); 172 rb_autoload(dl, rb_intern_const("StdcallCallbackProcs"), cb); 173#endif 174} 175 176void 177Init_dl(void) 178{ 179 void Init_dlhandle(void); 180 void Init_dlcfunc(void); 181 void Init_dlptr(void); 182 183 rbdl_id_cdecl = rb_intern_const("cdecl"); 184 rbdl_id_stdcall = rb_intern_const("stdcall"); 185 186 /* Document-module: DL 187 * 188 * A bridge to the dlopen() or dynamic library linker function. 189 * 190 * == Example 191 * 192 * bash $> cat > sum.c <<EOF 193 * double sum(double *arry, int len) 194 * { 195 * double ret = 0; 196 * int i; 197 * for(i = 0; i < len; i++){ 198 * ret = ret + arry[i]; 199 * } 200 * return ret; 201 * } 202 * 203 * double split(double num) 204 * { 205 * double ret = 0; 206 * ret = num / 2; 207 * return ret; 208 * } 209 * EOF 210 * bash $> gcc -o libsum.so -shared sum.c 211 * bash $> cat > sum.rb <<EOF 212 * require 'dl' 213 * require 'dl/import' 214 * 215 * module LibSum 216 * extend DL::Importer 217 * dlload './libsum.so' 218 * extern 'double sum(double*, int)' 219 * extern 'double split(double)' 220 * end 221 * 222 * a = [2.0, 3.0, 4.0] 223 * 224 * sum = LibSum.sum(a.pack("d*"), a.count) 225 * p LibSum.split(sum) 226 * EOF 227 * bash $> ruby sum.rb 228 * 4.5 229 * 230 * WIN! :-) 231 */ 232 rb_mDL = rb_define_module("DL"); 233 234 /* 235 * Document-class: DL::DLError 236 * 237 * standard dynamic load exception 238 */ 239 rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError); 240 241 /* 242 * Document-class: DL::DLTypeError 243 * 244 * dynamic load incorrect type exception 245 */ 246 rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError); 247 248 /* Document-const: MAX_CALLBACK 249 * 250 * Maximum number of callbacks 251 */ 252 rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK)); 253 254 /* Document-const: DLSTACK_SIZE 255 * 256 * Dynamic linker stack size 257 */ 258 rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE)); 259 260 rb_dl_init_callbacks(rb_mDL); 261 262 /* Document-const: RTLD_GLOBAL 263 * 264 * rtld DL::Handle flag. 265 * 266 * The symbols defined by this library will be made available for symbol 267 * resolution of subsequently loaded libraries. 268 */ 269 rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL)); 270 271 /* Document-const: RTLD_LAZY 272 * 273 * rtld DL::Handle flag. 274 * 275 * Perform lazy binding. Only resolve symbols as the code that references 276 * them is executed. If the symbol is never referenced, then it is never 277 * resolved. (Lazy binding is only performed for function references; 278 * references to variables are always immediately bound when the library 279 * is loaded.) 280 */ 281 rb_define_const(rb_mDL, "RTLD_LAZY", INT2NUM(RTLD_LAZY)); 282 283 /* Document-const: RTLD_NOW 284 * 285 * rtld DL::Handle flag. 286 * 287 * If this value is specified or the environment variable LD_BIND_NOW is 288 * set to a nonempty string, all undefined symbols in the library are 289 * resolved before dlopen() returns. If this cannot be done an error is 290 * returned. 291 */ 292 rb_define_const(rb_mDL, "RTLD_NOW", INT2NUM(RTLD_NOW)); 293 294 /* Document-const: TYPE_VOID 295 * 296 * DL::CFunc type - void 297 */ 298 rb_define_const(rb_mDL, "TYPE_VOID", INT2NUM(DLTYPE_VOID)); 299 300 /* Document-const: TYPE_VOIDP 301 * 302 * DL::CFunc type - void* 303 */ 304 rb_define_const(rb_mDL, "TYPE_VOIDP", INT2NUM(DLTYPE_VOIDP)); 305 306 /* Document-const: TYPE_CHAR 307 * 308 * DL::CFunc type - char 309 */ 310 rb_define_const(rb_mDL, "TYPE_CHAR", INT2NUM(DLTYPE_CHAR)); 311 312 /* Document-const: TYPE_SHORT 313 * 314 * DL::CFunc type - short 315 */ 316 rb_define_const(rb_mDL, "TYPE_SHORT", INT2NUM(DLTYPE_SHORT)); 317 318 /* Document-const: TYPE_INT 319 * 320 * DL::CFunc type - int 321 */ 322 rb_define_const(rb_mDL, "TYPE_INT", INT2NUM(DLTYPE_INT)); 323 324 /* Document-const: TYPE_LONG 325 * 326 * DL::CFunc type - long 327 */ 328 rb_define_const(rb_mDL, "TYPE_LONG", INT2NUM(DLTYPE_LONG)); 329 330#if HAVE_LONG_LONG 331 /* Document-const: TYPE_LONG_LONG 332 * 333 * DL::CFunc type - long long 334 */ 335 rb_define_const(rb_mDL, "TYPE_LONG_LONG", INT2NUM(DLTYPE_LONG_LONG)); 336#endif 337 338 /* Document-const: TYPE_FLOAT 339 * 340 * DL::CFunc type - float 341 */ 342 rb_define_const(rb_mDL, "TYPE_FLOAT", INT2NUM(DLTYPE_FLOAT)); 343 344 /* Document-const: TYPE_DOUBLE 345 * 346 * DL::CFunc type - double 347 */ 348 rb_define_const(rb_mDL, "TYPE_DOUBLE", INT2NUM(DLTYPE_DOUBLE)); 349 350 /* Document-const: TYPE_SIZE_T 351 * 352 * DL::CFunc type - size_t 353 */ 354 rb_define_const(rb_mDL, "TYPE_SIZE_T", INT2NUM(DLTYPE_SIZE_T)); 355 356 /* Document-const: TYPE_SSIZE_T 357 * 358 * DL::CFunc type - ssize_t 359 */ 360 rb_define_const(rb_mDL, "TYPE_SSIZE_T", INT2NUM(DLTYPE_SSIZE_T)); 361 362 /* Document-const: TYPE_PTRDIFF_T 363 * 364 * DL::CFunc type - ptrdiff_t 365 */ 366 rb_define_const(rb_mDL, "TYPE_PTRDIFF_T", INT2NUM(DLTYPE_PTRDIFF_T)); 367 368 /* Document-const: TYPE_INTPTR_T 369 * 370 * DL::CFunc type - intptr_t 371 */ 372 rb_define_const(rb_mDL, "TYPE_INTPTR_T", INT2NUM(DLTYPE_INTPTR_T)); 373 374 /* Document-const: TYPE_UINTPTR_T 375 * 376 * DL::CFunc type - uintptr_t 377 */ 378 rb_define_const(rb_mDL, "TYPE_UINTPTR_T", INT2NUM(DLTYPE_UINTPTR_T)); 379 380 /* Document-const: ALIGN_VOIDP 381 * 382 * The alignment size of a void* 383 */ 384 rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP)); 385 386 /* Document-const: ALIGN_CHAR 387 * 388 * The alignment size of a char 389 */ 390 rb_define_const(rb_mDL, "ALIGN_CHAR", INT2NUM(ALIGN_CHAR)); 391 392 /* Document-const: ALIGN_SHORT 393 * 394 * The alignment size of a short 395 */ 396 rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT)); 397 398 /* Document-const: ALIGN_INT 399 * 400 * The alignment size of an int 401 */ 402 rb_define_const(rb_mDL, "ALIGN_INT", INT2NUM(ALIGN_INT)); 403 404 /* Document-const: ALIGN_LONG 405 * 406 * The alignment size of a long 407 */ 408 rb_define_const(rb_mDL, "ALIGN_LONG", INT2NUM(ALIGN_LONG)); 409 410#if HAVE_LONG_LONG 411 /* Document-const: ALIGN_LONG_LONG 412 * 413 * The alignment size of a long long 414 */ 415 rb_define_const(rb_mDL, "ALIGN_LONG_LONG", INT2NUM(ALIGN_LONG_LONG)); 416#endif 417 418 /* Document-const: ALIGN_FLOAT 419 * 420 * The alignment size of a float 421 */ 422 rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT)); 423 424 /* Document-const: ALIGN_DOUBLE 425 * 426 * The alignment size of a double 427 */ 428 rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE)); 429 430 /* Document-const: ALIGN_SIZE_T 431 * 432 * The alignment size of a size_t 433 */ 434 rb_define_const(rb_mDL, "ALIGN_SIZE_T", INT2NUM(ALIGN_OF(size_t))); 435 436 /* Document-const: ALIGN_SSIZE_T 437 * 438 * The alignment size of a ssize_t 439 */ 440 rb_define_const(rb_mDL, "ALIGN_SSIZE_T", INT2NUM(ALIGN_OF(size_t))); /* same as size_t */ 441 442 /* Document-const: ALIGN_PTRDIFF_T 443 * 444 * The alignment size of a ptrdiff_t 445 */ 446 rb_define_const(rb_mDL, "ALIGN_PTRDIFF_T", INT2NUM(ALIGN_OF(ptrdiff_t))); 447 448 /* Document-const: ALIGN_INTPTR_T 449 * 450 * The alignment size of a intptr_t 451 */ 452 rb_define_const(rb_mDL, "ALIGN_INTPTR_T", INT2NUM(ALIGN_OF(intptr_t))); 453 454 /* Document-const: ALIGN_UINTPTR_T 455 * 456 * The alignment size of a uintptr_t 457 */ 458 rb_define_const(rb_mDL, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t))); 459 460 /* Document-const: SIZEOF_VOIDP 461 * 462 * size of a void* 463 */ 464 rb_define_const(rb_mDL, "SIZEOF_VOIDP", INT2NUM(sizeof(void*))); 465 466 /* Document-const: SIZEOF_CHAR 467 * 468 * size of a char 469 */ 470 rb_define_const(rb_mDL, "SIZEOF_CHAR", INT2NUM(sizeof(char))); 471 472 /* Document-const: SIZEOF_SHORT 473 * 474 * size of a short 475 */ 476 rb_define_const(rb_mDL, "SIZEOF_SHORT", INT2NUM(sizeof(short))); 477 478 /* Document-const: SIZEOF_INT 479 * 480 * size of an int 481 */ 482 rb_define_const(rb_mDL, "SIZEOF_INT", INT2NUM(sizeof(int))); 483 484 /* Document-const: SIZEOF_LONG 485 * 486 * size of a long 487 */ 488 rb_define_const(rb_mDL, "SIZEOF_LONG", INT2NUM(sizeof(long))); 489 490#if HAVE_LONG_LONG 491 /* Document-const: SIZEOF_LONG_LONG 492 * 493 * size of a long long 494 */ 495 rb_define_const(rb_mDL, "SIZEOF_LONG_LONG", INT2NUM(sizeof(LONG_LONG))); 496#endif 497 498 /* Document-const: SIZEOF_FLOAT 499 * 500 * size of a float 501 */ 502 rb_define_const(rb_mDL, "SIZEOF_FLOAT", INT2NUM(sizeof(float))); 503 504 /* Document-const: SIZEOF_DOUBLE 505 * 506 * size of a double 507 */ 508 rb_define_const(rb_mDL, "SIZEOF_DOUBLE",INT2NUM(sizeof(double))); 509 510 /* Document-const: SIZEOF_SIZE_T 511 * 512 * size of a size_t 513 */ 514 rb_define_const(rb_mDL, "SIZEOF_SIZE_T", INT2NUM(sizeof(size_t))); 515 516 /* Document-const: SIZEOF_SSIZE_T 517 * 518 * size of a ssize_t 519 */ 520 rb_define_const(rb_mDL, "SIZEOF_SSIZE_T", INT2NUM(sizeof(size_t))); /* same as size_t */ 521 522 /* Document-const: SIZEOF_PTRDIFF_T 523 * 524 * size of a ptrdiff_t 525 */ 526 rb_define_const(rb_mDL, "SIZEOF_PTRDIFF_T", INT2NUM(sizeof(ptrdiff_t))); 527 528 /* Document-const: SIZEOF_INTPTR_T 529 * 530 * size of a intptr_t 531 */ 532 rb_define_const(rb_mDL, "SIZEOF_INTPTR_T", INT2NUM(sizeof(intptr_t))); 533 534 /* Document-const: SIZEOF_UINTPTR_T 535 * 536 * size of a uintptr_t 537 */ 538 rb_define_const(rb_mDL, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t))); 539 540 rb_define_module_function(rb_mDL, "dlwrap", rb_dl_value2ptr, 1); 541 rb_define_module_function(rb_mDL, "dlunwrap", rb_dl_ptr2value, 1); 542 543 rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1); 544 rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1); 545 rb_define_module_function(rb_mDL, "realloc", rb_dl_realloc, 2); 546 rb_define_module_function(rb_mDL, "free", rb_dl_free, 1); 547 548 /* Document-const: RUBY_FREE 549 * 550 * Address of the ruby_xfree() function 551 */ 552 rb_define_const(rb_mDL, "RUBY_FREE", PTR2NUM(ruby_xfree)); 553 554 /* Document-const: BUILD_RUBY_PLATFORM 555 * 556 * Platform built against (i.e. "x86_64-linux", etc.) 557 * 558 * See also RUBY_PLATFORM 559 */ 560 rb_define_const(rb_mDL, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM)); 561 562 /* Document-const: BUILD_RUBY_VERSION 563 * 564 * Ruby Version built. (i.e. "1.9.3") 565 * 566 * See also RUBY_VERSION 567 */ 568 rb_define_const(rb_mDL, "BUILD_RUBY_VERSION", rb_str_new2(RUBY_VERSION)); 569 570 Init_dlhandle(); 571 Init_dlcfunc(); 572 Init_dlptr(); 573} 574