AxWin3 - More RichText work
[tpg/acess2.git] / AcessNative / ld-acess_src / binary.c
1 /*
2  * AcessNative Dynamic Linker
3  * - By John Hodge (thePowersGang)
4  * 
5  * binary.c
6  * - Provides binary loading and type abstraction
7  */
8 #define DEBUG   0
9 #include "common.h"
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <string.h>
13
14 #define LIBRARY_PATH    "$$$$../Usermode/Output/x86_64/Libs"
15
16 // === TYPES ===
17 typedef struct sBinary {
18         struct sBinary  *Next;
19         void    *Base;
20          int    Ready;
21         tBinFmt *Format;
22         char    Path[];
23 }       tBinary;
24
25 // === IMPORTS ===
26 extern void     *Elf_Load(int fd);
27 extern uintptr_t        ElfRelocate(void *Base);
28 extern int      ElfGetSymbol(void *Base, char *Name, uintptr_t *ret, size_t *size);
29 extern int      ciNumBuiltinSymbols;
30 extern tSym     caBuiltinSymbols[];
31 extern char     **gEnvP;
32
33 // === PROTOTYPES ===
34 void    Binary_AddToList(const char *Filename, void *Base, tBinFmt *Format);
35
36 // === GLOBALS ===
37 tBinFmt gElf_FormatDef = {
38 //      .Mask = 0xFFFFFFFF,
39 //      .Magic = "\x7F""ELF",
40         .Name = "ELF32",
41         .Load = Elf_Load,
42         .Relocate = ElfRelocate,
43         .GetSymbol = ElfGetSymbol
44         };
45 tBinary *gLoadedBinaries;
46
47 // === CODE ===
48 char *Binary_LocateLibrary(const char *Name)
49 {
50         char    *envPath = getenv("ACESS_LIBRARY_PATH");
51          int    nameLen = strlen(Name);
52          int    fd;
53         
54         if( strcmp(Name, "libld-acess.so") == 0 ) {
55                 return strdup("libld-acess.so");
56         }
57         
58         // Try the environment ACESS_LIBRARY_PATH
59         if( envPath && envPath[0] != '\0' )
60         {
61                  int    len = strlen(envPath)+1+nameLen+1;
62                 char    tmp[len];
63
64                 strcpy(tmp, envPath);
65                 strcat(tmp, "/");
66                 strcat(tmp, Name);
67                 
68                 fd = acess_open(tmp, 4);        // OPENFLAG_EXEC
69                 if(fd != -1) {
70                         acess_close(fd);
71                         return strdup(tmp);
72                 }
73         }               
74
75         {
76                  int    len = strlen(LIBRARY_PATH)+1+nameLen+1;
77                 char    tmp[len];
78
79                 strcpy(tmp, LIBRARY_PATH);
80                 strcat(tmp, "/");
81                 strcat(tmp, Name);
82                 
83                 #if DEBUG
84                 printf("Binary_LocateLibrary: tmp = '%s'\n", tmp);
85                 #endif
86
87                 fd = acess_open(tmp, 4);        // OPENFLAG_EXEC
88                 if(fd != -1) {
89                         acess_close(fd);
90                         return strdup(tmp);
91                 }
92         }               
93
94         #if DEBUG
95         fprintf(stderr, "Unable to locate library '%s'\n", Name);
96         #endif
97
98         return NULL;
99 }
100
101 void *Binary_LoadLibrary(const char *Name)
102 {
103         char    *path;
104         void    *ret;
105          int    (*entry)(void *,int,char*[],char**) = NULL;
106
107         // Find File
108         path = Binary_LocateLibrary(Name);
109         #if DEBUG
110         printf("Binary_LoadLibrary: path = '%s'\n", path);
111         #endif
112         if( !path ) {
113                 return NULL;
114         }
115
116         ret = Binary_Load(path, (uintptr_t*)&entry);
117         if( ret != (void*)-1 )
118                 Debug("LOADED '%s' to %p (Entry=%p)", path, ret, entry);
119         free(path);
120         
121         #if DEBUG
122         printf("Binary_LoadLibrary: ret = %p, entry = %p\n", ret, entry);
123         #endif
124         if( entry ) {
125                 char    *argv[] = {NULL};
126                 #if DEBUG
127                 printf("Calling '%s' entry point %p\n", Name, entry);
128                 #endif
129                 entry(ret, 0, argv, gEnvP);
130         }
131
132         return ret;
133 }
134
135 void *Binary_Load(const char *Filename, uintptr_t *EntryPoint)
136 {
137          int    fd;
138         uint32_t        dword = 0xFA17FA17;
139         void    *ret;
140         uintptr_t       entry = 0;
141         tBinFmt *fmt;
142
143         // Ignore loading ld-acess
144         if( strcmp(Filename, "libld-acess.so") == 0 ) {
145                 *EntryPoint = 0;
146                 return (void*)-1;
147         }
148
149         {
150                 tBinary *bin;
151                 for(bin = gLoadedBinaries; bin; bin = bin->Next)
152                 {
153                         if( strcmp(Filename, bin->Path) == 0 ) {
154                                 return bin->Base;
155                         }
156                 }
157         }
158
159         fd = acess_open(Filename, 2|1); // Execute and Read
160         if( fd == -1 ) {
161                 // TODO: Handle libary directories
162                 perror("Opening binary");
163                 return NULL;
164         }
165
166         acess_read(fd, &dword, 4);
167         acess_seek(fd, 0, ACESS_SEEK_SET);
168         
169         if( memcmp(&dword, "\x7F""ELF", 4) == 0 ) {
170                 fmt = &gElf_FormatDef;
171         }
172         else {
173                 fprintf(stderr, "Unknown executable format (0x%08x)\n", dword);
174                 acess_close(fd);
175                 return NULL;
176         }
177         
178         #if DEBUG
179         printf("fmt->Load(0x%x)...\n", fd);
180         #endif
181         ret = fmt->Load(fd);
182         acess_close(fd);
183         #if DEBUG
184         printf("fmt->Load(0x%x): %p\n", fd, ret);
185         #endif
186         if( !ret ) {
187                 return NULL;
188         }
189         
190         Binary_AddToList(Filename, ret, fmt);
191
192         entry = fmt->Relocate(ret);
193         #if DEBUG
194         printf("fmt->Relocate(%p): %p\n", ret, (void*)entry);
195         #endif
196         if( !entry ) {
197                 // TODO: Clean up
198                 return NULL;
199         }
200         
201         if( EntryPoint )
202                 *EntryPoint = entry;
203
204         Binary_SetReadyToUse(ret);
205
206         return ret;
207 }
208
209 void Binary_AddToList(const char *Filename, void *Base, tBinFmt *Format)
210 {
211         tBinary *bin = malloc(sizeof(tBinary) + strlen(Filename) + 1);
212         bin->Base = Base;
213         bin->Format = Format;
214         strcpy(bin->Path, Filename);
215         bin->Ready = 0;
216         
217         bin->Next = gLoadedBinaries;
218         gLoadedBinaries = bin;
219 }
220
221 void Binary_SetReadyToUse(void *Base)
222 {
223         tBinary *bin;
224         for(bin = gLoadedBinaries; bin; bin = bin->Next)
225         {
226                 if( bin->Base != Base ) continue ;
227                 bin->Ready = 1;
228         }
229 }
230
231 int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value, size_t *Size)
232 {
233          int    i;
234         tBinary *bin;
235         
236         //printf("Binary_GetSymbol: (SymbolName='%s', Value=%p)\n",
237         //      SymbolName, Value);
238
239         // Search builtins
240         // - Placed first to override smartarses that define their own versions
241         //   of system calls
242         for( i = 0; i < ciNumBuiltinSymbols; i ++ )
243         {
244                 if( strcmp(caBuiltinSymbols[i].Name, SymbolName) == 0 ) {
245                         *Value = (uintptr_t)caBuiltinSymbols[i].Value;
246                         if(Size)        *Size = 0;
247                         return 1;
248                 }
249         }
250         
251         // Search list of loaded binaries
252         for(bin = gLoadedBinaries; bin; bin = bin->Next)
253         {
254                 if( !bin->Ready )       continue;
255                 //printf(" Binary_GetSymbol: bin = %p{%p, %s}\n", bin, bin->Base, bin->Path);
256                 if( bin->Format->GetSymbol(bin->Base, (char*)SymbolName, Value, Size) )
257                         return 1;
258         }
259
260         //printf("Binary_GetSymbol: RETURN 0, not found\n");
261         printf("--- ERROR: Unable to find symbol '%s'\n", SymbolName);
262
263         exit( -1 );
264         return 0;
265 }

UCC git Repository :: git.ucc.asn.au