From c8f02d5d170c5373eeef98d6f6354ae7c726e29b Mon Sep 17 00:00:00 2001 From: jj Date: Mon, 11 Dec 2023 19:22:30 +0100 Subject: [PATCH] dynldr: ruby3.3 compat --- metasm/dynldr.rb | 64 ++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/metasm/dynldr.rb b/metasm/dynldr.rb index 74bf786f2..a7b807703 100644 --- a/metasm/dynldr.rb +++ b/metasm/dynldr.rb @@ -9,7 +9,7 @@ module Metasm class DynLdr - # basic C defs for ruby internals - 1.8 and 1.9 compat - x86/x64 + # basic C defs for ruby internals - 1.8, 1.9, 3.3 compat - x86/x64 RUBY_H = <= '1.9' ? 1 : 0} -#endif - #if #{RUBY_VERSION >= '2.0' ? 1 : 0} // flonums. WHY? // also breaks Qtrue/Qnil #define rb_float_new rb_float_new_in_heap #endif -#if DYNLDR_RUBY_19 +#if #{RUBY_VERSION >= '1.9' ? 0 : 1} + #define T_STRING 0x07 + #define T_ARRAY 0x09 + #define T_FIXNUM 0x0a + #define T_MASK 0x3f + #define STR_PTR(o) (RString(o)->ptr) + #define STR_LEN(o) (RString(o)->len) + #define ARY_PTR(o) (RArray(o)->ptr) + #define ARY_LEN(o) (RArray(o)->len) +#else #define T_STRING 0x05 #define T_ARRAY 0x07 #define T_FIXNUM 0x15 #define T_MASK 0x1f #define RSTRING_NOEMBED (1<<13) +#if #{RUBY_VERSION >= '3.2' ? 0 : 1} + // ruby1.9 .. 3.2 #define STR_PTR(o) ((RString(o)->flags & RSTRING_NOEMBED) ? RString(o)->ptr : (char*)&RString(o)->len) #define STR_LEN(o) ((RString(o)->flags & RSTRING_NOEMBED) ? RString(o)->len : (RString(o)->flags >> 14) & 0x1f) +#else + // ruby3.2+: len is used for NOEMBED strings, and the str buffer starts right after len (off 8+8+4 on win64) + // TODO find a better way to test, not depending on the compiling interpreter ? + #define STR_PTR(o) ((RString(o)->flags & RSTRING_NOEMBED) ? RString(o)->ptr : (((char*)&RString(o)->len) + sizeof(long))) + #define STR_LEN(o) RString(o)->len +#endif #define RARRAY_EMBED (1<<13) #define ARY_PTR(o) ((RArray(o)->flags & RARRAY_EMBED) ? (VALUE*)&RArray(o)->len : RArray(o)->ptr) - #define ARY_LEN(o) ((RArray(o)->flags & RARRAY_EMBED) ? ((RArray(o)->flags >> 15) & 3) : RArray(o)->len) -#else - #define T_STRING 0x07 - #define T_ARRAY 0x09 - #define T_FIXNUM 0x0a - #define T_MASK 0x3f - #define STR_PTR(o) (RString(o)->ptr) - #define STR_LEN(o) (RString(o)->len) - #define ARY_PTR(o) (RArray(o)->ptr) - #define ARY_LEN(o) (RArray(o)->len) + // RVARGC uses more bits, should be 0/unused in earlier ruby versions + #define ARY_LEN(o) ((RArray(o)->flags & RARRAY_EMBED) ? ((RArray(o)->flags >> 15) & 0xff) : RArray(o)->len) #endif -#if #{nil.object_id == 4 ? 1 : 0} -// ruby1.8 +#if #{(RUBY_VERSION < '3.0' and nil.object_id == 4) ? 1 : 0} +// ruby1.8 (Qnil changed in 1.9 and back in 3.3 #define TYPE(x) (((VALUE)(x) & 1) ? T_FIXNUM : (((VALUE)(x) < 0x07) || (((VALUE)(x) & 0xf) == 0xe)) ? 0x40 : RString(x)->flags & T_MASK) #else // ruby2.0+, USE_FLONUM, world is hell @@ -138,7 +142,6 @@ class DynLdr #define os_load_sym_ord(l, s) 0U #endif -extern int *cb_ret_table; extern void *callback_handler; extern void *callback_id_0; extern void *callback_id_1; @@ -207,13 +210,12 @@ class DynLdr else rb_raise(*rb_eArgError, "Invalid lib"); - if (TYPE(func) != T_STRING && TYPE(func) != T_FIXNUM) - rb_raise(*rb_eArgError, "Invalid func"); - - if (TYPE(func) == T_FIXNUM) + if (TYPE(func) == T_STRING) + p = os_load_sym(h, STR_PTR(func)); + else if (TYPE(func) == T_FIXNUM) p = os_load_sym_ord(h, VAL2INT(func)); else - p = os_load_sym(h, STR_PTR(func)); + rb_raise(*rb_eArgError, "Invalid func"); return INT2VAL(p); } @@ -354,6 +356,14 @@ class DynLdr } #endif +unsigned long long ruby_abi_version(void) __attribute__((export)) +{ + // mandatory to be loadable in a dev ruby build + // TODO find expected value in current interpreter ? + return 0; + // disable the value check interpreter side: #{ENV['RUBY_ABI_CHECK'] = '0'} +} + int Init_dynldr(void) __attribute__((export_as(Init_))) // to patch before parsing to match the .so name { dynldr = rb_const_get(rb_const_get(*rb_cObject, rb_intern("Metasm")), rb_intern("DynLdr"));