rbdc 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/dyncall/CMakeLists.txt +3 -3
- data/dyncall/ChangeLog +33 -0
- data/dyncall/ChangeLog.orig +274 -0
- data/dyncall/LICENSE +1 -1
- data/dyncall/README +3 -5
- data/dyncall/ToDo +27 -18
- data/dyncall/ToDo.orig +201 -0
- data/dyncall/autovar/autovar_ARCH.h +1 -1
- data/dyncall/buildsys/vs2005/vs2005.sln +0 -9
- data/dyncall/cconv.lang +36 -0
- data/dyncall/configure +17 -9
- data/dyncall/configure.bat +1 -1
- data/dyncall/dyncall/dyncall.h +2 -1
- data/dyncall/dyncall/dyncall_call.S +9 -1
- data/dyncall/dyncall/dyncall_call_mips_n32.S +192 -0
- data/dyncall/dyncall/dyncall_call_mips_n64.S +197 -0
- data/dyncall/dyncall/dyncall_call_mips_n64.h +2 -0
- data/dyncall/dyncall/{dyncall_call_mips_o32_gas.s → dyncall_call_mips_o32.S} +44 -42
- data/dyncall/dyncall/dyncall_call_mips_o32.h +8 -3
- data/dyncall/dyncall/dyncall_call_ppc32.S +3 -1
- data/dyncall/dyncall/dyncall_call_ppc32.h +4 -3
- data/dyncall/dyncall/dyncall_call_ppc64.S +1 -1
- data/dyncall/dyncall/dyncall_call_ppc64.h +3 -0
- data/dyncall/dyncall/dyncall_call_x64.S +27 -2
- data/dyncall/dyncall/dyncall_call_x64.h +2 -1
- data/dyncall/dyncall/dyncall_call_x64_generic_masm.asm +13 -2
- data/dyncall/dyncall/dyncall_call_x86.S +6 -6
- data/dyncall/dyncall/dyncall_call_x86.h +7 -7
- data/dyncall/dyncall/dyncall_call_x86_generic_masm.asm +6 -7
- data/dyncall/dyncall/dyncall_callvm_mips_n64.c +27 -9
- data/dyncall/dyncall/dyncall_callvm_mips_o32.c +38 -31
- data/dyncall/dyncall/dyncall_callvm_mips_o32.c.orig +247 -0
- data/dyncall/dyncall/dyncall_callvm_x64.c +57 -3
- data/dyncall/dyncall/dyncall_callvm_x86.c +32 -32
- data/dyncall/dyncall/dyncall_macros.h +11 -8
- data/dyncall/dyncall/dyncall_struct.c +12 -6
- data/dyncall/dyncall/dyncall_struct.h +1 -1
- data/dyncall/dyncall/dyncall_vector.c +13 -12
- data/dyncall/dyncall/dyncall_vector.c.orig +53 -0
- data/dyncall/dyncall/gen-masm.sh +4 -5
- data/dyncall/dyncallback/dyncall_args_mips.h +24 -6
- data/dyncall/dyncallback/dyncall_args_mips64.c +3 -3
- data/dyncall/dyncallback/dyncall_args_mips_o32.c +19 -6
- data/dyncall/dyncallback/dyncall_callback_arch.S +11 -1
- data/dyncall/dyncallback/{dyncall_callback_mips_n32_gas.s → dyncall_callback_mips_n32.S} +1 -1
- data/dyncall/dyncallback/{dyncall_callback_mips_n64_gas.s → dyncall_callback_mips_n64.S} +39 -25
- data/dyncall/dyncallback/{dyncall_callback_mips_o32_gas.s → dyncall_callback_mips_o32.S} +29 -13
- data/dyncall/dyncallback/dyncall_callback_x86_masm.asm +0 -1
- data/dyncall/dyncallback/dyncall_thunk.h +1 -1
- data/dyncall/dyncallback/gen-masm.sh +3 -5
- data/dyncall/dynload/dynload.3 +16 -4
- data/dyncall/dynload/dynload_unix.c +101 -53
- data/dyncall/dynload/dynload_windows.c +76 -3
- data/dyncall/portasm/README.txt +1 -1
- data/dyncall/portasm/gen-masm.sh +5 -1
- metadata +14 -13
- data/dyncall/buildsys/vs2005/test_plain/test_plain.vcproj +0 -202
- data/dyncall/dyncall/dyncall_call_mips_gas.S +0 -37
- data/dyncall/dyncall/dyncall_call_mips_n32_gas.s +0 -192
- data/dyncall/dyncall/dyncall_call_mips_n64_gas.s +0 -192
- data/dyncall/dyncallback/dyncall_callback_mips_gas.S +0 -38
@@ -30,7 +30,7 @@
|
|
30
30
|
DClonglong dcbArgLongLong(DCArgs* p)
|
31
31
|
{
|
32
32
|
DClonglong value;
|
33
|
-
if(p->reg_count <
|
33
|
+
if(p->reg_count < DCARGS_MIPS_NUM_REGS)
|
34
34
|
value = p->ireg_data[p->reg_count++];
|
35
35
|
else {
|
36
36
|
value = *((DClonglong*)p->stackptr);
|
@@ -54,7 +54,7 @@ DCpointer dcbArgPointer(DCArgs* p) { return (DCpointer)dcbArgLongLong(p); }
|
|
54
54
|
DCdouble dcbArgDouble(DCArgs* p)
|
55
55
|
{
|
56
56
|
DCdouble result;
|
57
|
-
if(p->reg_count <
|
57
|
+
if(p->reg_count < DCARGS_MIPS_NUM_REGS)
|
58
58
|
result = p->freg_data[p->reg_count++];
|
59
59
|
else {
|
60
60
|
result = *((DCdouble*)p->stackptr);
|
@@ -65,7 +65,7 @@ DCdouble dcbArgDouble(DCArgs* p)
|
|
65
65
|
DCfloat dcbArgFloat(DCArgs* p)
|
66
66
|
{
|
67
67
|
DCfloat result;
|
68
|
-
if(p->reg_count <
|
68
|
+
if(p->reg_count < DCARGS_MIPS_NUM_REGS) {
|
69
69
|
result = ((DCfloat*)&p->freg_data[p->reg_count++])
|
70
70
|
#if defined(DC__Endian_LITTLE)
|
71
71
|
[0];
|
@@ -29,7 +29,12 @@
|
|
29
29
|
DCint dcbArgInt(DCArgs* p)
|
30
30
|
{
|
31
31
|
DCint value;
|
32
|
-
|
32
|
+
|
33
|
+
#if defined(DC__ABI_HARDFLOAT)
|
34
|
+
/* first int will disable float reg use. */
|
35
|
+
p->freg_count = 2;
|
36
|
+
#endif /* DC__ABI_HARDFLOAT */
|
37
|
+
|
33
38
|
value = *((int*)p->stackptr);
|
34
39
|
p->stackptr += sizeof(int);
|
35
40
|
return value;
|
@@ -63,19 +68,23 @@ DCpointer dcbArgPointer(DCArgs* p) { return (DCpointer)dcbArgUInt(p); }
|
|
63
68
|
DCfloat dcbArgFloat(DCArgs* p)
|
64
69
|
{
|
65
70
|
DCfloat result;
|
71
|
+
|
72
|
+
#if defined(DC__ABI_HARDFLOAT)
|
66
73
|
if(p->freg_count < 2) {
|
67
74
|
/* Stored float regs (max 2) are always 8b aligned. The way we look them up, */
|
68
75
|
/* relative to a diverging p->stackptr, we need consider this. Only works */
|
69
76
|
/* with up to two float args, which is all we need. Hacky, but saves us */
|
70
77
|
/* from one more variable and more bookkeeping in DCArgs. */
|
71
78
|
result = ((DCfloat*)(p->stackptr + ((int)p->stackptr & 4)) - 4) /* '-4' b/c those regs are stored right before the args */
|
72
|
-
#if defined(DC__Endian_LITTLE)
|
79
|
+
# if defined(DC__Endian_LITTLE)
|
73
80
|
[0];
|
74
|
-
#else
|
81
|
+
# else
|
75
82
|
[1];
|
76
|
-
#endif
|
83
|
+
# endif
|
77
84
|
++p->freg_count;
|
78
|
-
} else
|
85
|
+
} else
|
86
|
+
#endif /* DC__ABI_HARDFLOAT */
|
87
|
+
{
|
79
88
|
result = *((DCfloat*)p->stackptr);
|
80
89
|
}
|
81
90
|
p->stackptr += sizeof(DCfloat);
|
@@ -88,12 +97,16 @@ DCdouble dcbArgDouble(DCArgs* p)
|
|
88
97
|
DCfloat f[2];
|
89
98
|
} d;
|
90
99
|
p->stackptr += ((int)p->stackptr & 4); /* Skip one slot if not aligned. */
|
100
|
+
|
101
|
+
#if defined(DC__ABI_HARDFLOAT)
|
91
102
|
if(p->freg_count < 2) {
|
92
103
|
/*result = *((DCdouble*)p->stackptr-2); this changes the value, slightly*/
|
93
104
|
d.f[0] = ((DCfloat*)p->stackptr-4)[0]; /* '-4' b/c those regs are stored right before the args */
|
94
105
|
d.f[1] = ((DCfloat*)p->stackptr-4)[1];
|
95
106
|
++p->freg_count;
|
96
|
-
} else
|
107
|
+
} else
|
108
|
+
#endif /* DC__ABI_HARDFLOAT */
|
109
|
+
{
|
97
110
|
/*result = *((DCdouble*)p->stackptr); this changes the value, slightly*/
|
98
111
|
d.f[0] = ((DCfloat*)p->stackptr)[0];
|
99
112
|
d.f[1] = ((DCfloat*)p->stackptr)[1];
|
@@ -65,7 +65,17 @@
|
|
65
65
|
# elif defined(DC__Arch_PPC64)
|
66
66
|
# include "dyncall_callback_ppc64.S"
|
67
67
|
# elif defined(DC__Arch_MIPS) || defined(DC__Arch_MIPS64)
|
68
|
-
#
|
68
|
+
# if defined(DC__ABI_MIPS_O32)
|
69
|
+
# include "dyncall_callback_mips_o32.S"
|
70
|
+
# elif defined(DC__ABI_MIPS_N64)
|
71
|
+
# include "dyncall_callback_mips_n64.S"
|
72
|
+
# elif defined(DC__ABI_MIPS_N32)
|
73
|
+
# include "dyncall_callback_mips_n32.S"
|
74
|
+
# elif defined(DC__ABI_MIPS_EABI)
|
75
|
+
# include "dyncall_callback_mips_eabi_gas.s"
|
76
|
+
# else
|
77
|
+
# error Unknown MIPS ABI.
|
78
|
+
# endif
|
69
79
|
# elif defined(DC__Arch_ARM_ARM)
|
70
80
|
# include "dyncall_callback_arm32_arm_gas.S"
|
71
81
|
# elif defined(DC__Arch_ARM_THUMB)
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Package: dyncall
|
4
4
|
Library: dyncallback
|
5
|
-
File: dyncallback/
|
5
|
+
File: dyncallback/dyncall_callback_mips_n64.S
|
6
6
|
Description: Callback Thunk - Implementation for mips64 n64
|
7
7
|
License:
|
8
8
|
|
9
|
-
Copyright (c) 2016 Tassilo Philipp <tphilipp@potion-studios.com>
|
9
|
+
Copyright (c) 2016-2018 Tassilo Philipp <tphilipp@potion-studios.com>
|
10
10
|
|
11
11
|
Permission to use, copy, modify, and distribute this software for any
|
12
12
|
purpose with or without fee is hereby granted, provided that the above
|
@@ -28,6 +28,18 @@
|
|
28
28
|
$t8+64 -> userdata
|
29
29
|
*/
|
30
30
|
|
31
|
+
/* Frame size is 160b for hard- and 128b for soft-float, as follows: */
|
32
|
+
/* DCargs(fregs:64? + iregs:64 + regcnts:8 + sp:8) + rval:8 + ra:8 */
|
33
|
+
#if defined(DC__ABI_HARDFLOAT)
|
34
|
+
SP_SP = 160
|
35
|
+
#else
|
36
|
+
SP_SP = 96
|
37
|
+
#endif
|
38
|
+
SP_LR = SP_SP-8
|
39
|
+
SP_RVAL = SP_SP-16
|
40
|
+
SP_ARG_SP = SP_SP-24
|
41
|
+
SP_ARG_RC = SP_SP-32
|
42
|
+
|
31
43
|
.section .mdebug.abi64
|
32
44
|
.previous
|
33
45
|
.abicalls
|
@@ -39,17 +51,15 @@ dcCallbackThunkEntry:
|
|
39
51
|
.set noreorder
|
40
52
|
|
41
53
|
/* Prolog. */
|
42
|
-
|
43
|
-
|
44
|
-
daddiu $sp, $sp, -160 /* open frame */
|
45
|
-
sd $ra, 152($sp) /* save link register */
|
54
|
+
daddiu $sp, $sp, -SP_SP /* open frame */
|
55
|
+
sd $ra, SP_LR($sp) /* save link register */
|
46
56
|
|
47
|
-
.frame $fp,
|
57
|
+
.frame $fp,SP_SP,$31 /* specify our frame: fp,size,lr; creates virt $fp */
|
48
58
|
/* code below doesn't use $fp though, as n/a with -O1 */
|
49
59
|
/* Init return value */
|
50
|
-
sd $zero,
|
60
|
+
sd $zero, SP_RVAL($sp)
|
51
61
|
|
52
|
-
/* Store
|
62
|
+
/* Store reg args where our DCargs member arrays are, in local stack area */
|
53
63
|
sd $4, 0($sp)
|
54
64
|
sd $5, 8($sp)
|
55
65
|
sd $6, 16($sp)
|
@@ -58,6 +68,7 @@ dcCallbackThunkEntry:
|
|
58
68
|
sd $9, 40($sp)
|
59
69
|
sd $10, 48($sp)
|
60
70
|
sd $11, 56($sp)
|
71
|
+
#if defined(DC__ABI_HARDFLOAT)
|
61
72
|
s.d $f12, 64($sp)
|
62
73
|
s.d $f13, 72($sp)
|
63
74
|
s.d $f14, 80($sp)
|
@@ -66,31 +77,34 @@ dcCallbackThunkEntry:
|
|
66
77
|
s.d $f17, 104($sp)
|
67
78
|
s.d $f18, 112($sp)
|
68
79
|
s.d $f19, 120($sp)
|
80
|
+
#endif
|
69
81
|
|
70
82
|
/* Init DCarg's reg_counts and stackptr. */
|
71
|
-
sd
|
72
|
-
daddiu $4, $sp,
|
73
|
-
sd $4,
|
83
|
+
sd $zero, SP_ARG_RC($sp) /* reg_count */
|
84
|
+
daddiu $4, $sp, SP_SP
|
85
|
+
sd $4, SP_ARG_SP($sp) /* stackptr */
|
74
86
|
|
75
87
|
/* Prepare callback handler call. */
|
76
|
-
move $4, $24
|
77
|
-
move $5, $sp
|
78
|
-
daddiu $6, $sp,
|
79
|
-
ld $7, 64($24)
|
88
|
+
move $4, $24 /* Param 0 = DCCallback*, $24/$t8 holds DCThunk* */
|
89
|
+
move $5, $sp /* Param 1 = ptr to where DCArgs* is stored */
|
90
|
+
daddiu $6, $sp, SP_RVAL /* Param 2 = results ptr to 8b of local stack data */
|
91
|
+
ld $7, 64($24) /* Param 3 = userdata pointer */
|
80
92
|
|
81
|
-
ld $25, 56($24)
|
82
|
-
jalr $25
|
83
|
-
nop
|
93
|
+
ld $25, 56($24) /* store handler entry in $25/$t9, required for PIC */
|
94
|
+
jalr $25 /* jump */
|
95
|
+
nop /* branch delay nop */
|
84
96
|
|
85
97
|
/* Copy result in corresponding registers $2-$3 ($v0-$v1) and $f0 */
|
86
|
-
ld $2,
|
87
|
-
|
98
|
+
ld $2, SP_RVAL($sp) /* note: ignoring 2nd possible retval in $3, here */
|
99
|
+
#if defined(DC__ABI_HARDFLOAT)
|
100
|
+
l.d $f0, SP_RVAL($sp)
|
101
|
+
#endif
|
88
102
|
|
89
103
|
/* Epilog. Tear down frame and return. */
|
90
|
-
ld
|
91
|
-
daddiu $sp, $sp,
|
92
|
-
j
|
93
|
-
nop
|
104
|
+
ld $ra, SP_LR($sp) /* restore return address */
|
105
|
+
daddiu $sp, $sp, SP_SP /* close frame */
|
106
|
+
j $ra /* return */
|
107
|
+
nop /* branch delay nop */
|
94
108
|
|
95
109
|
.set reorder
|
96
110
|
.end dcCallbackThunkEntry
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Package: dyncall
|
4
4
|
Library: dyncallback
|
5
|
-
File: dyncallback/
|
5
|
+
File: dyncallback/dyncall_callback_mips_o32.S
|
6
6
|
Description: Callback Thunk - Implementation mips32 o32
|
7
7
|
License:
|
8
8
|
|
@@ -60,18 +60,22 @@ dcCallbackThunkEntry:
|
|
60
60
|
/* For $4-$7 ($a0-$a3), use dedicated spill area (caller doesn't spill, but */
|
61
61
|
/* provides it at end of _caller's_ frame, so $fp points right to it). */
|
62
62
|
/* For $f12 and $f14 use our space (in local data), which is adjacent. */
|
63
|
-
|
64
|
-
s.d $
|
65
|
-
|
66
|
-
|
67
|
-
sw $
|
68
|
-
sw $
|
63
|
+
#if defined(DC__ABI_HARDFLOAT)
|
64
|
+
s.d $f12, 40($sp) /* -16($fp) */
|
65
|
+
s.d $f14, 48($sp) /* -8($fp) */
|
66
|
+
#endif /* DC__ABI_HARDFLOAT */
|
67
|
+
sw $4, 56($sp) /* 0($fp) */
|
68
|
+
sw $5, 60($sp) /* 4($fp) */
|
69
|
+
sw $6, 64($sp) /* 8($fp) */
|
70
|
+
sw $7, 68($sp) /* 12($fp) */
|
69
71
|
|
70
72
|
/* Init DCArg, which contains reg_count and stackptr* to the args. Point */
|
71
73
|
/* stackptr to the area where the non-float args start (which is at $fp). */
|
72
|
-
addiu $4, $sp, 56
|
73
|
-
sw $4, 28($sp)
|
74
|
-
|
74
|
+
addiu $4, $sp, 56 /* <- non-$fp replacement for: */
|
75
|
+
sw $4, 28($sp) /* <- sw $fp, 28($sp) */
|
76
|
+
#if defined(DC__ABI_HARDFLOAT)
|
77
|
+
sw $zero, 24($sp) /* init num float-regs (unused for soft-float) */
|
78
|
+
#endif /* DC__ABI_HARDFLOAT */
|
75
79
|
|
76
80
|
/* Prepare callback handler call. */
|
77
81
|
move $4, $12 /* Param 0 = DCCallback*, $12 ($t4) holds pointer to thunk */
|
@@ -83,10 +87,22 @@ dcCallbackThunkEntry:
|
|
83
87
|
jalr $25 /* jump */
|
84
88
|
nop /* branch delay nop */
|
85
89
|
|
86
|
-
/* Copy result
|
87
|
-
|
88
|
-
|
90
|
+
/* Copy result to corresponding registers */
|
91
|
+
/* Handle single precision soft-float retvals differently on big-endian */
|
92
|
+
/* targets as they are right-justified in their 8b stack lots */
|
93
|
+
#if !defined(DC__ABI_HARDFLOAT) && defined(DC__Endian_BIG)
|
94
|
+
xori $4, $2, 'f' /* $4 = 0 if cb-handler returned 'f' in $2 */
|
95
|
+
#endif
|
96
|
+
lw $2, 32($sp)
|
97
|
+
lw $3, 36($sp)
|
98
|
+
#if defined(DC__ABI_HARDFLOAT)
|
89
99
|
l.d $f0, 32($sp)
|
100
|
+
#elif defined(DC__Endian_BIG)
|
101
|
+
bgtz $4, .nonf32r /* if no 'f' returned, $2 and $3 are good */
|
102
|
+
nop /* branch delay nop */
|
103
|
+
move $2, $3
|
104
|
+
.nonf32r:
|
105
|
+
#endif /* DC__ABI_HARDFLOAT */
|
90
106
|
|
91
107
|
/* Epilog. Tear down frame and return. */
|
92
108
|
lw $ra, 20($sp) /* restore return address */
|
@@ -1,8 +1,6 @@
|
|
1
1
|
#!/bin/sh
|
2
|
+
cd `dirname $0`
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
printf "; auto-generated by `basename $0`\r\n" >dyncall_callback_x64_masm.asm
|
6
|
-
gcc -E -P -DGEN_MASM dyncall_callback_x86.S | awk '{printf "%s\r\n", $0}' >> dyncall_callback_x86_masm.asm
|
7
|
-
gcc -E -P -DGEN_MASM dyncall_callback_x64.S | awk '{printf "%s\r\n", $0}' >> dyncall_callback_x64_masm.asm
|
4
|
+
../portasm/gen-masm.sh dyncall_callback_x86 _masm
|
5
|
+
../portasm/gen-masm.sh dyncall_callback_x64 _masm
|
8
6
|
|
data/dyncall/dynload/dynload.3
CHANGED
@@ -54,7 +54,9 @@ and
|
|
54
54
|
.Fn dlFindSymbol
|
55
55
|
calls. Passing a null pointer for the
|
56
56
|
.Ar libpath
|
57
|
-
argument is valid, and returns a handle to the main executable of the calling code. Also, searching libraries in library paths (e.g. by just passing the library's leaf name) should work, however, they are OS specific.
|
57
|
+
argument is valid, and returns a handle to the main executable of the calling code. Also, searching libraries in library paths (e.g. by just passing the library's leaf name) should work, however, they are OS specific. The
|
58
|
+
.Ar libPath
|
59
|
+
argument is expected to be UTF-8 encoded. Returns a null pointer on error.
|
58
60
|
.Pp
|
59
61
|
.Fn dlFreeLibrary
|
60
62
|
frees the loaded library with handle
|
@@ -74,11 +76,13 @@ The parameter
|
|
74
76
|
.Ar sOut
|
75
77
|
is a pointer to a buffer of size
|
76
78
|
.Ar bufSize
|
77
|
-
(in bytes), to hold the output string. The return value is the size of the buffer (in bytes) needed to hold the null-terminated string, or 0 if it can't be looked up. If
|
79
|
+
(in bytes), to hold the output string (UTF-8 encoded). The return value is the size of the buffer (in bytes) needed to hold the null-terminated string, or 0 if it can't be looked up. If
|
78
80
|
.Ar bufSize
|
79
|
-
>= return value
|
81
|
+
>= return value >= 1, a null-terminted string with the path to the library should be in
|
80
82
|
.Ar sOut .
|
81
|
-
If it returns 0, the library name wasn't able to be found. Please note that this might happen in some rare cases, so make sure to always check.
|
83
|
+
If it returns 0, the library name wasn't able to be found. Please note that this might happen in some rare cases, so make sure to always check. Passing a null pointer as
|
84
|
+
.Ar pLib
|
85
|
+
returns the path to the executable (not guaranteed to be absolute - if it isn't it's relative to the working directory the process was started in, not the current one).
|
82
86
|
.Pp
|
83
87
|
The dlSyms* functions can be used to iterate over symbols. Since they can be used on libraries that are not linked, they are made
|
84
88
|
for symbol name lookups, not to get symbols' addresses. For that refer to
|
@@ -99,14 +103,22 @@ must point to a loaded symbol.
|
|
99
103
|
.Sh BUGS
|
100
104
|
.Fn dlGetLibraryPath
|
101
105
|
is not thread-safe on Darwin (macOS, iOS, ...) and OpenBSD.
|
106
|
+
.Pp
|
102
107
|
.Fn dlSymsInit
|
103
108
|
is not thread-safe on Darwin.
|
109
|
+
.Pp
|
104
110
|
.Fn dlGetLibraryPath
|
105
111
|
will not work on the following platforms when the library in question doesn't have the (default)
|
106
112
|
.Fn _init
|
107
113
|
and
|
108
114
|
.Fn _fini
|
109
115
|
symbols exported (rare, but possible): Haiku (all versions), OpenBSD < 3.7, NetBSD < 5.1, FreeBSD < 4.8
|
116
|
+
.Pp
|
117
|
+
Getting the executable's path by passing NULL in
|
118
|
+
.Ar pLib
|
119
|
+
to
|
120
|
+
.Fn dlGetLibraryPath
|
121
|
+
fails on the following platforms: Haiku (all versions), OpenBSD < 3.7, NetBSD < 5.1, FreeBSD < 4.8
|
110
122
|
.Sh CONFORMING TO
|
111
123
|
The dynload library conforms to c99.
|
112
124
|
.Ed
|
@@ -38,7 +38,12 @@
|
|
38
38
|
|
39
39
|
#include <string.h>
|
40
40
|
|
41
|
-
#if defined(__GLIBC__)
|
41
|
+
#if defined(__GLIBC__)
|
42
|
+
/* @@@ version check glibc more precisely... dl_iterate_phdr(): glibc ver >= 2.2.4*/
|
43
|
+
#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 3)
|
44
|
+
# define DL_USE_GLIBC_ITER_PHDR
|
45
|
+
#endif
|
46
|
+
/* to access dl_iterate_phdr(), and related w/ glibc */
|
42
47
|
# define _GNU_SOURCE
|
43
48
|
# define __USE_GNU
|
44
49
|
#endif
|
@@ -69,32 +74,42 @@ void dlFreeLibrary(DLLib* pLib)
|
|
69
74
|
|
70
75
|
|
71
76
|
|
72
|
-
/* for dlopen-based dlGetLibraryPath impls below, prefer RTLD_NOLOAD
|
73
|
-
|
77
|
+
/* for dlopen-based dlGetLibraryPath impls below, prefer RTLD_NOLOAD that
|
78
|
+
* merely checks lib names */
|
74
79
|
#if defined(RTLD_NOLOAD)
|
75
|
-
# define RTLD_LIGHTEST RTLD_NOLOAD
|
80
|
+
# define RTLD_LIGHTEST RTLD_LAZY|RTLD_NOLOAD
|
76
81
|
#else
|
77
82
|
# define RTLD_LIGHTEST RTLD_LAZY
|
78
83
|
#endif
|
79
84
|
|
80
85
|
|
81
|
-
/*
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
+
/* helper copying string if buffer big enough, returning length (without \0) */
|
87
|
+
static int dl_strlen_strcpy(char* dst, const char* src, int dstSize)
|
88
|
+
{
|
89
|
+
int l = strlen(src);
|
90
|
+
if(l < dstSize) /* l+'\0' <= bufSize */
|
91
|
+
strcpy(dst, src);
|
92
|
+
return l;
|
93
|
+
}
|
94
|
+
|
95
|
+
/* code for dlGetLibraryPath() is platform specific */
|
96
|
+
|
97
|
+
/* if dlinfo() exists use it (except on glibc, where it exists since version
|
98
|
+
* 2.3.3, but its implementation is dangerous, as no checks are done whether
|
99
|
+
* the handle is valid, thus rendering the returned values useless) check for
|
100
|
+
* RTLD_DI_LINKMAP which is a #define for dlinfo() on most supported targets,
|
101
|
+
* or specifically check the OS (e.g. dlinfo() is originally from Solaris) */
|
102
|
+
#if (defined(RTLD_DI_LINKMAP) || defined(OS_SunOS)) && !defined(DL_USE_GLIBC_ITER_PHDR)
|
86
103
|
|
87
104
|
#include <link.h>
|
88
105
|
|
89
106
|
int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
90
107
|
{
|
91
|
-
struct link_map* p;
|
108
|
+
struct link_map* p = NULL;
|
92
109
|
int l = -1;
|
93
|
-
if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0)
|
94
|
-
l =
|
95
|
-
|
96
|
-
strcpy(sOut, p->l_name);
|
97
|
-
}
|
110
|
+
if(dlinfo(pLib ? pLib : RTLD_SELF, RTLD_DI_LINKMAP, &p) == 0)
|
111
|
+
l = dl_strlen_strcpy(sOut, p->l_name, bufSize);
|
112
|
+
|
98
113
|
return l+1; /* strlen + '\0' */
|
99
114
|
}
|
100
115
|
|
@@ -110,26 +125,30 @@ int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
|
110
125
|
uint32_t i;
|
111
126
|
int l = -1;
|
112
127
|
|
113
|
-
/*
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
if(
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
128
|
+
/* request info about own process? lookup first loaded image */
|
129
|
+
if(pLib == NULL) {
|
130
|
+
const char* libPath = _dyld_get_image_name(0); //@@@ consider using _NSGetExecutablePath()
|
131
|
+
if(libPath)
|
132
|
+
l = dl_strlen_strcpy(sOut, libPath, bufSize);
|
133
|
+
}
|
134
|
+
else {
|
135
|
+
/* Darwin's code doesn't come with (non-standard) dlinfo(), so use dyld(1)
|
136
|
+
* code. There doesn't seem to be a direct way to query the library path,
|
137
|
+
* so "double-load" temporarily all already loaded images (just increases
|
138
|
+
* ref count) and compare handles until we found ours. Return the name. */
|
139
|
+
for(i=_dyld_image_count(); i>0;) /* backwards, ours is more likely at end */
|
140
|
+
{
|
141
|
+
const char* libPath = _dyld_get_image_name(--i);
|
142
|
+
void* lib = dlopen(libPath, RTLD_LIGHTEST);
|
143
|
+
if(lib) {
|
144
|
+
dlclose(lib);
|
145
|
+
|
146
|
+
/* compare handle pointers' high bits (in low 2 bits some flags might */
|
147
|
+
/* be stored - should be safe b/c address needs alignment, anyways) */
|
148
|
+
if(((uintptr_t)pLib ^ (uintptr_t)lib) < 4) {
|
149
|
+
l = dl_strlen_strcpy(sOut, libPath, bufSize);
|
150
|
+
break;
|
151
|
+
}
|
133
152
|
}
|
134
153
|
}
|
135
154
|
}
|
@@ -138,9 +157,10 @@ int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
|
138
157
|
}
|
139
158
|
|
140
159
|
|
141
|
-
/* OpenBSD >= 3.7 has dl_iterate_phdr(),
|
142
|
-
|
143
|
-
|
160
|
+
/* OpenBSD >= 3.7 has dl_iterate_phdr(), as well as glibc >= 2.2.4, however
|
161
|
+
* skip and use on dladdr()-based guessing if if explicitly requested, e.g. by
|
162
|
+
* ./configure */
|
163
|
+
#elif !defined(DL_DLADDR_TO_LIBPATH) && (defined(OS_OpenBSD) || defined(DL_USE_GLIBC_ITER_PHDR))
|
144
164
|
|
145
165
|
#include <sys/types.h>
|
146
166
|
#include <link.h>
|
@@ -155,18 +175,41 @@ static int iter_phdr_cb(struct dl_phdr_info* info, size_t size, void* data)
|
|
155
175
|
{
|
156
176
|
int l = -1;
|
157
177
|
iter_phdr_data* d = (iter_phdr_data*)data;
|
158
|
-
|
159
|
-
|
160
|
-
/*
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
178
|
+
void* lib = NULL;
|
179
|
+
|
180
|
+
/* get loaded object's handle if not requesting info about process itself */
|
181
|
+
if(d->pLib != NULL) {
|
182
|
+
/* unable to relate info->dlpi_addr directly to our dlopen handle, let's
|
183
|
+
* do what we do on macOS above, re-dlopen the already loaded lib (just
|
184
|
+
* increases ref count) and compare handles */
|
185
|
+
/* @@@ might be b/c it's the reloc addr... see below */
|
186
|
+
lib = dlopen(info->dlpi_name, RTLD_LIGHTEST);
|
187
|
+
if(lib)
|
188
|
+
dlclose(lib);
|
189
|
+
}
|
190
|
+
|
191
|
+
/* compare handles and get name if found; if d->pLib == NULL this will
|
192
|
+
enter info on first iterated object, which is the process itself */
|
193
|
+
if(lib == (void*)d->pLib) {
|
194
|
+
l = dl_strlen_strcpy(d->sOut, info->dlpi_name, d->bufSize);
|
195
|
+
|
196
|
+
/* if dlpi_name is empty, lookup name via dladdr(proc_load_addr, ...) */
|
197
|
+
if(l == 0 && d->pLib == NULL) {
|
198
|
+
/* dlpi_addr is the reloc base (0 if PIE), find real virtual load addr */
|
199
|
+
void* vladdr = (void*)info->dlpi_addr;
|
200
|
+
int i = 0;
|
201
|
+
for(; i < info->dlpi_phnum; ++i) {
|
202
|
+
if(info->dlpi_phdr[i].p_type == PT_LOAD) {
|
203
|
+
vladdr = (void*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
|
204
|
+
break;
|
205
|
+
}
|
206
|
+
}
|
207
|
+
Dl_info di;
|
208
|
+
if(dladdr(vladdr, &di) != 0)
|
209
|
+
l = dl_strlen_strcpy(d->sOut, di.dli_fname, d->bufSize);
|
168
210
|
}
|
169
211
|
}
|
212
|
+
|
170
213
|
return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */
|
171
214
|
}
|
172
215
|
|
@@ -177,9 +220,16 @@ int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
|
177
220
|
}
|
178
221
|
|
179
222
|
|
223
|
+
/* glibc with neither dl_iterate_phdr() nor dlinfo() (latter introduced after former) @@@
|
224
|
+
#elif defined(__GLIBC__) && !defined(DL_USE_GLIBC_ITER_PHDR)
|
225
|
+
|
226
|
+
@@@impl */
|
227
|
+
|
180
228
|
/* fallback to dladdr() hack */
|
181
229
|
#else
|
182
230
|
|
231
|
+
#warning "Using non-optimal code for dlGetLibraryPath() b/c of platform limitations."
|
232
|
+
|
183
233
|
/* if nothing else is available, fall back to guessing using dladdr() - this */
|
184
234
|
/* might not always work, as it's trying to getit via the _fini() symbol, */
|
185
235
|
/* which is usually defined in ELF files, but not guaranteed */
|
@@ -190,16 +240,14 @@ int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
|
190
240
|
|
191
241
|
int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
192
242
|
{
|
243
|
+
/*@@@ missing handler for pLib == NULL*/
|
193
244
|
/* cross fingers that shared object is standard ELF and look for _fini */
|
194
245
|
int l = -1;
|
195
246
|
void* s = dlsym((void*)pLib, "_fini");
|
196
247
|
if(s) {
|
197
248
|
Dl_info i;
|
198
|
-
if(dladdr(s, &i) != 0)
|
199
|
-
l =
|
200
|
-
if(l < bufSize) /* l+'\0' <= bufSize */
|
201
|
-
strcpy(sOut, i.dli_fname);
|
202
|
-
}
|
249
|
+
if(dladdr(s, &i) != 0)
|
250
|
+
l = dl_strlen_strcpy(sOut, i.dli_fname, bufSize);
|
203
251
|
}
|
204
252
|
return l+1; /* strlen + '\0' */
|
205
253
|
}
|