File files/EDLF64.draft changed (mode: 100644) (index ba5ec5f..958379d) |
1 |
|
EDLF64 is the JSON/wayland of the executables and dynamic libraries for 64bits platforms. |
|
|
1 |
|
EDLF64 is the JSON/wayland of the executables and dynamic libraries for 64bits platforms with a |
|
2 |
|
thread lock mechanism. |
2 |
3 |
|
|
3 |
|
EDLF64=Executable and Dynamic Library Format for 64bits platforms. |
|
|
4 |
|
EDLF64=Executable and Dynamic Library Format for 64bits platforms (with a thread lock mechanism). |
4 |
5 |
|
|
5 |
6 |
The excrutiating simplicity of the format is intended while doing a good enough job. |
The excrutiating simplicity of the format is intended while doing a good enough job. |
6 |
7 |
|
|
7 |
|
Endianness is the one from the CPU. Offsets 0->edlf_hdr_bytes_n-1 are obviously invalid. |
|
|
8 |
|
To avoid a circular dependency with a high level threading dynamic library, the hardware |
|
9 |
|
architecture with or without the kernel must provide a pre-inited/ready to use thread lock |
|
10 |
|
mechanism. Usually on many cores systems, this is an atomic compare and exchange hardware |
|
11 |
|
instruction or kernel syscall on memory locations which are already inited with some specific |
|
12 |
|
content. |
8 |
13 |
==================================================================================================== |
==================================================================================================== |
9 |
|
0x00 "EDLF64",0x00[2],version_b,undef_b[7] (version_b will very probably stay 0x00 forever) |
|
|
14 |
|
0x00 "EDLF64",0x00,version_b (version_b will very probably stay 0x00 forever) |
10 |
15 |
0x08 alignment, power of two (then cannot be 0, namely at least 1), from "EDLF64" |
0x08 alignment, power of two (then cannot be 0, namely at least 1), from "EDLF64" |
11 |
16 |
0x10 mem_bytes_n. |
0x10 mem_bytes_n. |
12 |
17 |
0x18 process_entry_file_offset, 0 if this is a dynamic library (register passing, no stack). |
0x18 process_entry_file_offset, 0 if this is a dynamic library (register passing, no stack). |
|
... |
... |
Endianness is the one from the CPU. Offsets 0->edlf_hdr_bytes_n-1 are obviously |
16 |
21 |
==================================================================================================== |
==================================================================================================== |
17 |
22 |
A loader64 instance will keep a registry of what was loaded via reference counting. Usually, there |
A loader64 instance will keep a registry of what was loaded via reference counting. Usually, there |
18 |
23 |
will be only one static instance of loader64 per process inited by the process_entry function. |
will be only one static instance of loader64 per process inited by the process_entry function. |
|
24 |
|
The main loader64 instance code is usually dependent only on the hardware architecture and kernel, |
|
25 |
|
to stay independent of all dynamic libraries. |
19 |
26 |
|
|
20 |
27 |
uint64_t loader64_open( /*INPUT*/ void *pathname, /* we presume the pathname is self-sizing */ |
uint64_t loader64_open( /*INPUT*/ void *pathname, /* we presume the pathname is self-sizing */ |
21 |
28 |
/*OUTPUT*/ uint64_t *handle, void **start); |
/*OUTPUT*/ uint64_t *handle, void **start); |
22 |
29 |
|
|
23 |
|
Must be reentrant/thread safe. |
|
|
30 |
|
Must be re-entrant. Usually, the main loader instance of a process which will be used to |
|
31 |
|
load a high level threading dynamic library does use the same thread lock mechanism than the |
|
32 |
|
resolve function, that to break the circular dependency. |
24 |
33 |
|
|
25 |
|
Return 0 if ok, non-zero if an error did happen, and a loader handle and the pointer |
|
26 |
|
on the start of the loaded dynamic library, namely the first byte of the loaded dynamic |
|
27 |
|
library ELDF64 header. |
|
|
34 |
|
Return values: |
|
35 |
|
0 if ok, and a loader handle and the pointer on the start of the loaded dynamic |
|
36 |
|
library, namely the first byte of the loaded dynamic library ELDF64 header. |
|
37 |
|
11 (-EAGAIN), if the loader is currently busy. |
|
38 |
|
other an error did happen. |
28 |
39 |
|
|
29 |
40 |
Init functions, if any, should be resolved and called right after open. Usually, their C |
Init functions, if any, should be resolved and called right after open. Usually, their C |
30 |
41 |
prototypes do include pathname, see below for a recommended init function prototype. |
prototypes do include pathname, see below for a recommended init function prototype. |
|
... |
... |
uint64_t loader64_open( /*INPUT*/ void *pathname, /* we presume the pathname is |
42 |
53 |
|
|
43 |
54 |
uint64_t loader64_close(/*INPUT*/ uint64_t handle); |
uint64_t loader64_close(/*INPUT*/ uint64_t handle); |
44 |
55 |
|
|
45 |
|
Must be reentrant/thread safe. Return 0 if ok, non-zero if something wrong did happen while |
|
46 |
|
closing the edlf64 file. |
|
|
56 |
|
Must be re-entrant. Usually, the main loader instance of a process which will be used to |
|
57 |
|
load a high level threading dynamic library, does use the same thread lock mechanism than |
|
58 |
|
the resolve function, that to break the circular dependency. |
|
59 |
|
|
|
60 |
|
Return values: |
|
61 |
|
0 if ok, non-zero The handle becomes invalid. |
|
62 |
|
11 (-EAGAIN), if the loader is currently busy. The handle stays valid. |
|
63 |
|
other if something wrong did happen while closing the edlf64 file. The handle becomes |
|
64 |
|
invalid. |
47 |
65 |
|
|
48 |
66 |
Fini functions, if any, should be called (may be resolved if not provided by init functions) |
Fini functions, if any, should be called (may be resolved if not provided by init functions) |
49 |
67 |
right before the close call. |
right before the close call. |
50 |
68 |
|
|
51 |
69 |
Init/fini functions have the responsibility to keep the dynamic library state consistent (for |
Init/fini functions have the responsibility to keep the dynamic library state consistent (for |
52 |
70 |
instance using reference counting like a loader instance). |
instance using reference counting like a loader instance). |
|
71 |
|
Dynamic libraries should try to presume not they are the only instance in a process. The process |
|
72 |
|
could have other instances via other loader instances. Avoiding those races could be expensive, |
|
73 |
|
should be clearly documented in a dynamic library documentation if it is supported or not. |
53 |
74 |
==================================================================================================== |
==================================================================================================== |
54 |
75 |
EDLF64 is about loading only one RWX memory segment. |
EDLF64 is about loading only one RWX memory segment. |
55 |
76 |
==================================================================================================== |
==================================================================================================== |
56 |
|
A EDLF64 executable may honor the following environment variable in order to lookup for dynamic |
|
57 |
|
libraries. Of course, only on platforms where it is possible. Such incompatible platforms should |
|
|
77 |
|
A EDLF64 file may honor the following environment variable in order to lookup for dynamic |
|
78 |
|
libraries. Of course, only on platforms where it is possible. Such incompatible platforms may |
58 |
79 |
defines their own "EDLF64_LIBRARY_PATH way". |
defines their own "EDLF64_LIBRARY_PATH way". |
59 |
80 |
|
|
60 |
81 |
EDLF64_LIBRARY_PATH environment variable to lookup for EDLF64 dynamic libraries: byte string |
EDLF64_LIBRARY_PATH environment variable to lookup for EDLF64 dynamic libraries: byte string |
|
... |
... |
C prototype of resolve function: |
103 |
124 |
/*INPUT*/ uint64_t *symbol_id, |
/*INPUT*/ uint64_t *symbol_id, |
104 |
125 |
/*OUTPUT*/ void **symbol_virtual_address); |
/*OUTPUT*/ void **symbol_virtual_address); |
105 |
126 |
|
|
|
127 |
|
Must be re-entrant/thread-safe without the usage of a high level threading dynamic library. |
|
128 |
|
|
106 |
129 |
symbol_id is a 64bits unique id identifying a symbol (similar to kernel syscalls). Like kernel |
symbol_id is a 64bits unique id identifying a symbol (similar to kernel syscalls). Like kernel |
107 |
|
syscalls, those symbol ids must be _EXTREMELY_ stable in time. You could segment the id space with |
|
108 |
|
categories (init calls, fini calls, etc, 64bits is huge). |
|
109 |
|
Return 0 if ok, with the virtual address of the symbol via the symbol_virtual_address argument. |
|
|
130 |
|
syscalls, those symbol ids must be _EXTREMELY_ stable in time. |
|
131 |
|
|
|
132 |
|
Return values: |
|
133 |
|
0 if ok, with the virtual address of the symbol via the symbol_virtual_address argument. No |
|
134 |
|
assumption must be made about the location of this virtual address. |
|
135 |
|
11 (-EAGAIN), if the resolve function cannot be run right now. |
|
136 |
|
other the symbol was not found. |
110 |
137 |
==================================================================================================== |
==================================================================================================== |
111 |
|
Recommended C prototype of an init function: |
|
|
138 |
|
Recommended C prototype of a basic init function: |
112 |
139 |
uint64_t init( |
uint64_t init( |
113 |
140 |
/*INPUT*/ void *process_info, uint64_t process_info_bytes_n, void *pathname, |
/*INPUT*/ void *process_info, uint64_t process_info_bytes_n, void *pathname, |
114 |
141 |
uint64_t (*loader64_open)(void *pathname, uint64_t *handle, void **start), |
uint64_t (*loader64_open)(void *pathname, uint64_t *handle, void **start), |
|
... |
... |
Pathname is a pointer on the pathname used to load this edlf64 file. If successf |
121 |
148 |
going with more than 6 parameters, just init a transient structure to pass the whole data to work |
going with more than 6 parameters, just init a transient structure to pass the whole data to work |
122 |
149 |
around some ABI kludge. |
around some ABI kludge. |
123 |
150 |
|
|
124 |
|
Alternative C prototype of an init function: |
|
|
151 |
|
Alternative C prototype of a basic init function: |
125 |
152 |
uint64_t init( |
uint64_t init( |
126 |
153 |
/*INPUT*/ void *process_info, uint64_t process_info_bytes_n, int fd, |
/*INPUT*/ void *process_info, uint64_t process_info_bytes_n, int fd, |
127 |
154 |
uint64_t (*loader64_open)(void *pathname, uint64_t *handle, void **start), |
uint64_t (*loader64_open)(void *pathname, uint64_t *handle, void **start), |
|
... |
... |
Alternative C prototype of an init function: |
129 |
156 |
/*OUTPUT*/ void (**fini)(void)); |
/*OUTPUT*/ void (**fini)(void)); |
130 |
157 |
|
|
131 |
158 |
Same thing than the previous one, but with the process file descriptor used to load/mmap the edlf64 |
Same thing than the previous one, but with the process file descriptor used to load/mmap the edlf64 |
132 |
|
file instead of the pathname. You could even add the directory file descriptor. |
|
|
159 |
|
file instead of the pathname. You could even add the directory file descriptor, and since that |
|
160 |
|
would make more than 6 parameters, better use a transient structure to pass the whole data. |
133 |
161 |
|
|
134 |
|
Recommended C prototype of fini function: |
|
|
162 |
|
Recommended C prototype of basic fini function: |
135 |
163 |
void fini(void) |
void fini(void) |
136 |
164 |
---------------------------------------------------------------------------------------------------- |
---------------------------------------------------------------------------------------------------- |
|
165 |
|
Dead-locks/circular dependencies can happen while coarse init-ing/fini-ting inter-dependent dynamic |
|
166 |
|
libraries. Usually, it means you need to break them down, or have fine-grained init/fini functions |
|
167 |
|
specific to a caller/subsystem, and that, probably in several steps. |
|
168 |
|
Or the other way around: fuse them all in one common dynamic library with a big init and use other |
|
169 |
|
dynamic libraries as user level stubs resolving in this very common dynamic library. Of course, |
|
170 |
|
those user level stubs could contain some code "only for the user" to call. |
|
171 |
|
==================================================================================================== |
137 |
172 |
NOTES: |
NOTES: |
138 |
173 |
|
|
139 |
174 |
No static and implicit TLS anymore, explicit initialization is required, for instance via the |
No static and implicit TLS anymore, explicit initialization is required, for instance via the |