rbdc 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/dyncall/CMakeLists.txt +3 -3
  3. data/dyncall/ChangeLog +33 -0
  4. data/dyncall/ChangeLog.orig +274 -0
  5. data/dyncall/LICENSE +1 -1
  6. data/dyncall/README +3 -5
  7. data/dyncall/ToDo +27 -18
  8. data/dyncall/ToDo.orig +201 -0
  9. data/dyncall/autovar/autovar_ARCH.h +1 -1
  10. data/dyncall/buildsys/vs2005/vs2005.sln +0 -9
  11. data/dyncall/cconv.lang +36 -0
  12. data/dyncall/configure +17 -9
  13. data/dyncall/configure.bat +1 -1
  14. data/dyncall/dyncall/dyncall.h +2 -1
  15. data/dyncall/dyncall/dyncall_call.S +9 -1
  16. data/dyncall/dyncall/dyncall_call_mips_n32.S +192 -0
  17. data/dyncall/dyncall/dyncall_call_mips_n64.S +197 -0
  18. data/dyncall/dyncall/dyncall_call_mips_n64.h +2 -0
  19. data/dyncall/dyncall/{dyncall_call_mips_o32_gas.s → dyncall_call_mips_o32.S} +44 -42
  20. data/dyncall/dyncall/dyncall_call_mips_o32.h +8 -3
  21. data/dyncall/dyncall/dyncall_call_ppc32.S +3 -1
  22. data/dyncall/dyncall/dyncall_call_ppc32.h +4 -3
  23. data/dyncall/dyncall/dyncall_call_ppc64.S +1 -1
  24. data/dyncall/dyncall/dyncall_call_ppc64.h +3 -0
  25. data/dyncall/dyncall/dyncall_call_x64.S +27 -2
  26. data/dyncall/dyncall/dyncall_call_x64.h +2 -1
  27. data/dyncall/dyncall/dyncall_call_x64_generic_masm.asm +13 -2
  28. data/dyncall/dyncall/dyncall_call_x86.S +6 -6
  29. data/dyncall/dyncall/dyncall_call_x86.h +7 -7
  30. data/dyncall/dyncall/dyncall_call_x86_generic_masm.asm +6 -7
  31. data/dyncall/dyncall/dyncall_callvm_mips_n64.c +27 -9
  32. data/dyncall/dyncall/dyncall_callvm_mips_o32.c +38 -31
  33. data/dyncall/dyncall/dyncall_callvm_mips_o32.c.orig +247 -0
  34. data/dyncall/dyncall/dyncall_callvm_x64.c +57 -3
  35. data/dyncall/dyncall/dyncall_callvm_x86.c +32 -32
  36. data/dyncall/dyncall/dyncall_macros.h +11 -8
  37. data/dyncall/dyncall/dyncall_struct.c +12 -6
  38. data/dyncall/dyncall/dyncall_struct.h +1 -1
  39. data/dyncall/dyncall/dyncall_vector.c +13 -12
  40. data/dyncall/dyncall/dyncall_vector.c.orig +53 -0
  41. data/dyncall/dyncall/gen-masm.sh +4 -5
  42. data/dyncall/dyncallback/dyncall_args_mips.h +24 -6
  43. data/dyncall/dyncallback/dyncall_args_mips64.c +3 -3
  44. data/dyncall/dyncallback/dyncall_args_mips_o32.c +19 -6
  45. data/dyncall/dyncallback/dyncall_callback_arch.S +11 -1
  46. data/dyncall/dyncallback/{dyncall_callback_mips_n32_gas.s → dyncall_callback_mips_n32.S} +1 -1
  47. data/dyncall/dyncallback/{dyncall_callback_mips_n64_gas.s → dyncall_callback_mips_n64.S} +39 -25
  48. data/dyncall/dyncallback/{dyncall_callback_mips_o32_gas.s → dyncall_callback_mips_o32.S} +29 -13
  49. data/dyncall/dyncallback/dyncall_callback_x86_masm.asm +0 -1
  50. data/dyncall/dyncallback/dyncall_thunk.h +1 -1
  51. data/dyncall/dyncallback/gen-masm.sh +3 -5
  52. data/dyncall/dynload/dynload.3 +16 -4
  53. data/dyncall/dynload/dynload_unix.c +101 -53
  54. data/dyncall/dynload/dynload_windows.c +76 -3
  55. data/dyncall/portasm/README.txt +1 -1
  56. data/dyncall/portasm/gen-masm.sh +5 -1
  57. metadata +14 -13
  58. data/dyncall/buildsys/vs2005/test_plain/test_plain.vcproj +0 -202
  59. data/dyncall/dyncall/dyncall_call_mips_gas.S +0 -37
  60. data/dyncall/dyncall/dyncall_call_mips_n32_gas.s +0 -192
  61. data/dyncall/dyncall/dyncall_call_mips_n64_gas.s +0 -192
  62. 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 < DCARGS_MIPS_NUM_IREGS)
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 < DCARGS_MIPS_NUM_FREGS)
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 < DCARGS_MIPS_NUM_FREGS) {
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
- p->freg_count = 2; /* first int will disable float reg use. */
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
- # include "dyncall_callback_mips_gas.S"
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,7 +2,7 @@
2
2
 
3
3
  Package: dyncall
4
4
  Library: dyncallback
5
- File: dyncallback/dyncall_callback_mips_n32_gas.s
5
+ File: dyncallback/dyncall_callback_mips_n32.S
6
6
  Description: Callback Thunk - Implementation for mips64 n32
7
7
  License:
8
8
 
@@ -2,11 +2,11 @@
2
2
 
3
3
  Package: dyncall
4
4
  Library: dyncallback
5
- File: dyncallback/dyncall_callback_mips_n64_gas.s
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
- /* Frame size of 160b comes from following: */
43
- /* DCargs(fregs:64 + iregs:64 + regcounts:8 + stackptr:8) + retval:8 + ra:8 */
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,160,$31 /* specify our frame: fp,size,lr; creates virt $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, 144($sp)
60
+ sd $zero, SP_RVAL($sp)
51
61
 
52
- /* Store float and int args where our DCargs member arrays are, in local area. */
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 $zero, 128($sp) /* reg_count */
72
- daddiu $4, $sp, 160
73
- sd $4, 136($sp) /* stackptr */
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 /* Param 0 = DCCallback*, $24 ($t8) holds pointer to thunk */
77
- move $5, $sp /* Param 1 = DCArgs*, pointer to where pointer to args is stored */
78
- daddiu $6, $sp, 144 /* Param 2 = results pointer to 8b of local data on stack */
79
- ld $7, 64($24) /* Param 3 = userdata pointer */
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) /* store handler entry in $25 ($t9), required for PIC */
82
- jalr $25 /* jump */
83
- nop /* branch delay 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, 144($sp) /* note: ignoring second possible retval in $3, here */
87
- l.d $f0, 144($sp)
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 $ra, 152($sp) /* restore return address */
91
- daddiu $sp, $sp, 160 /* close frame */
92
- j $ra /* return */
93
- nop /* branch delay 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/dyncall_callback_mips_o32_gas.s
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
- s.d $f12, 40($sp) /* -16($fp) */
64
- s.d $f14, 48($sp) /* -8($fp) */
65
- sw $4, 56($sp) /* 0($fp) */
66
- sw $5, 60($sp) /* 4($fp) */
67
- sw $6, 64($sp) /* 8($fp) */
68
- sw $7, 68($sp) /* 12($fp) */
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 /* non-$fp replacement for: */
73
- sw $4, 28($sp) /* sw $fp, 28($sp) */
74
- sw $zero, 24($sp)
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 in corresponding registers $2-$3 ($v0-$v1) and $f0 */
87
- lw $2, 32($sp)
88
- lw $3, 36($sp)
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 */
@@ -2,7 +2,6 @@
2
2
  .386
3
3
  .MODEL FLAT
4
4
  .CODE
5
-
6
5
  DCThunk_size = 16
7
6
  DCArgs_size = 20
8
7
  DCValue_size = 8
@@ -51,7 +51,7 @@
51
51
  **
52
52
  **/
53
53
 
54
- #include "../dyncall/dyncall_macros.h"
54
+ #include "dyncall_macros.h"
55
55
 
56
56
  typedef struct DCThunk_ DCThunk;
57
57
 
@@ -1,8 +1,6 @@
1
1
  #!/bin/sh
2
+ cd `dirname $0`
2
3
 
3
- # Uses portasm to generates MASM sources for intel platforms.
4
- printf "; auto-generated by `basename $0`\r\n" >dyncall_callback_x86_masm.asm
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
 
@@ -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. Returns a null pointer on error.
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 > 1, a null-terminted string with the path to the library should be in
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__) /* to access dlinfo */
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
- /* that merely checks lib names */
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
- /* code for dlGetLibraryPath is platform specific - if dlinfo() exists use */
82
- /* that: check for RTLD_DI_LINKMAP (#define for dlinfo()), or if GNU C Lib */
83
- /* is used (where RTLD_DI_LINKMAP is an enum), or by OS (dlinfo comes from */
84
- /* Solaris), etc. */
85
- #if defined(RTLD_DI_LINKMAP) || defined(OS_SunOS) || defined(__GLIBC__) /* @@@ dlinfo() was introduced in glibc 2.3.3 (in 2003), somehow check for that, also */
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 = strlen(p->l_name);
95
- if(l < bufSize) /* l+'\0' <= bufSize */
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
- /*if(pLib == RTLD_DEFAULT)
114
- return NULL; @@@ return exec's path */
115
-
116
- /* Darwin's code doesn't come with (non-standard) dlinfo(), so use dyld(1) */
117
- /* code. There doesn't seem to be a direct way to query the library path, */
118
- /* so "double-load" temporarily all already loaded images (just increases */
119
- /* ref count) and compare handles until we found ours. Return the name. */
120
- for(i=_dyld_image_count(); i>0;) /* iterate libs from end, more likely ours */
121
- {
122
- const char* libPath = _dyld_get_image_name(--i);
123
- void* lib = dlopen(libPath, RTLD_LIGHTEST);
124
- if(lib) {
125
- dlclose(lib);
126
- /* compare handle pointers' high bits (in low 2 bits some flags might */
127
- /* be stored - should be safe b/c address needs alignment, anywas) */
128
- if(((intptr_t)pLib ^ (intptr_t)lib) < 4) {
129
- l = strlen(libPath);
130
- if(l < bufSize) /* l+'\0' <= bufSize */
131
- strcpy(sOut, libPath);
132
- break;
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(), use it if not explicitly requesting */
142
- /* to use dladdr()-based guessing (set by configure) -----> */
143
- #elif defined(OS_OpenBSD) && !defined(DL_DLADDR_TO_LIBPATH)
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
- /* unable to relate info->dlpi_addr directly to our dlopen handle, let's */
159
- /* do what we do on macOS above, re-dlopen the already loaded lib (just */
160
- /* increases ref count) and compare handles. */
161
- void* lib = dlopen(info->dlpi_name, RTLD_LIGHTEST);
162
- if(lib) {
163
- dlclose(lib);
164
- if(lib == (void*)d->pLib) {
165
- l = strlen(info->dlpi_name);
166
- if(l < d->bufSize) /* l+'\0' <= bufSize */
167
- strcpy(d->sOut, info->dlpi_name);
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 = strlen(i.dli_fname);
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
  }