0.8.14.5: Join the foreign legion!
[sbcl.git] / src / runtime / ppc-darwin-dlshim.c
1 /*
2  * These functions emulate a small subset of the dlopen / dlsym
3  * functionality under Darwin's Mach-O dyld system.
4  */
5
6 /*
7  * This software is part of the SBCL system. See the README file for
8  * more information.
9  *
10  * This software is derived from the CMU CL system, which was
11  * written at Carnegie Mellon University and released into the
12  * public domain. The software is in the public domain and is
13  * provided with absolutely no warranty. See the COPYING and CREDITS
14  * files for more information.
15  */
16
17
18 #include <mach-o/dyld.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 /* Darwin does not define the standard ELF
24  * dlopen/dlclose/dlsym/dlerror interface to shared libraries, so this
25  * is an attempt at a minimal wrapper to allow SBCL to work without
26  * external dependency on pogma's dlcompat library.
27  */
28
29 /* For now, there is no RTLD_GLOBAL emulation either. */
30
31 static char dl_self; /* I'm going to abuse this */
32
33 #define RTLD_LAZY 1
34 #define RTLD_NOW 2
35 #define RTLD_GLOBAL 0x100
36
37 static int callback_count;
38 static struct mach_header* last_header;
39
40 void dlshim_image_callback(struct mach_header* ptr, unsigned long phooey)
41 {
42     callback_count++;
43     last_header = ptr;
44 }
45
46 int lib_path_count(void)
47 {
48     char* libpath;
49     int i;
50     int count;
51     libpath = getenv("DYLD_LIBRARY_PATH");
52     count = 1;
53     if (libpath) {
54         for (i = 0; libpath[i] != '\0'; i++) {
55             if (libpath[i] == ':') count++;
56         }
57     }
58     return count;
59 }
60
61 const char* lib_path_prefixify(int index, const char* filename)
62 {
63     static char* retbuf = NULL;
64     int fi, li, i, count;
65     char* libpath;
66     if (!retbuf) {
67         retbuf = (char*) malloc(1024*sizeof(char));
68     }
69     count = 0;
70     fi = 0;
71     li = -1;
72     libpath = getenv("DYLD_LIBRARY_PATH");
73     if (libpath) {
74         i = 0;
75         while (count != index && libpath[i] != '\0') {
76             if (libpath[i] == ':') count++;
77             i++;
78         }
79         fi = i;
80         while (libpath[i] != '\0' && libpath[i] != ':') {
81             i++;
82         }
83         li = i - 1;
84     }
85     if (li - fi > 0) {
86         if (li - fi + 1 > 1022 - strlen(filename)) {
87             retbuf = (char*) realloc(retbuf, (li - fi + 3 + strlen(filename))*sizeof(char));
88         }
89         memcpy(retbuf, libpath + fi, (li - fi + 1)*sizeof(char));
90         retbuf[li - fi + 1] = '/';
91         memcpy(retbuf + li - fi + 2, filename, strlen(filename) + 1);
92         return retbuf;
93     } else {
94         return filename;
95     }
96 }
97
98 void* dlopen(const char* filename, int flags)
99 {
100     static char has_callback = 0;
101     if (!has_callback) {
102         _dyld_register_func_for_add_image(dlshim_image_callback);
103     }
104     if (!filename) {
105         return &dl_self;
106     } else {
107         struct mach_header* img = NULL;
108         if (!img) img = NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
109         if (!img) img = NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING);
110         if (!img) {
111             NSObjectFileImage fileImage;
112             callback_count = 0;
113             last_header = NULL;
114             if (NSCreateObjectFileImageFromFile(filename, &fileImage) == NSObjectFileImageSuccess) {
115                 NSLinkModule(fileImage, filename, NSLINKMODULE_OPTION_BINDNOW | ((flags & RTLD_GLOBAL)?NSLINKMODULE_OPTION_PRIVATE:0) | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
116                 if (callback_count && last_header) img = last_header;
117             }
118         }
119         if (!img) {
120             NSObjectFileImage fileImage;
121             int i, maxi;
122             char* prefixfilename;
123             maxi = lib_path_count();
124             for (i = 0; i < maxi && !img; i++) {
125                 prefixfilename = lib_path_prefixify(i, filename);
126                 callback_count = 0;
127                 last_header = NULL;
128                 if (NSCreateObjectFileImageFromFile(prefixfilename, &fileImage) == NSObjectFileImageSuccess) {
129                     NSLinkModule(fileImage, filename, NSLINKMODULE_OPTION_BINDNOW | ((flags & RTLD_GLOBAL)?NSLINKMODULE_OPTION_PRIVATE:0) | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
130                     if (callback_count && last_header) img = last_header;
131                 }
132             }
133         }
134         if (img) {
135             if (flags & RTLD_NOW) {
136                 NSLookupSymbolInImage(img, "", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
137             }
138             if (NSIsSymbolNameDefinedInImage(img, "__init")) {
139                 NSSymbol* initsymbol;
140                 void (*initfunc) (void);
141                 initsymbol = NSLookupSymbolInImage(img, "__init", 0);
142                 initfunc = NSAddressOfSymbol(initsymbol);
143                 initfunc();
144             }
145         }
146         return img;
147     }
148 }
149
150 const char* dlerror()
151 {
152     static char* errbuf = NULL;
153     NSLinkEditErrors a;
154     int b;
155     char *c, *d;
156     NSLinkEditError(&a, &b, &c, &d);
157     if (!errbuf) {
158         errbuf = (char*) malloc(256*sizeof(char));
159     }
160     snprintf(errbuf, 255, "%s in %s: %d %d", c, d, a, b);
161     return errbuf;
162 }
163
164 void* dlsym(void* handle, char* symbol)
165 {
166     if (handle == &dl_self) {
167         if (NSIsSymbolNameDefined(symbol)) {
168             NSSymbol* retsym;
169             retsym = NSLookupAndBindSymbol(symbol);
170             return NSAddressOfSymbol(retsym);
171         } else {
172             return NULL;
173         }
174     } else {
175         if (NSIsSymbolNameDefinedInImage(handle, symbol)) {
176             NSSymbol* retsym;
177             retsym = NSLookupSymbolInImage(handle, symbol, 0);
178             return NSAddressOfSymbol(retsym);
179         } else {
180             return NULL;
181         }
182     }
183 }
184
185 int dlclose(void *handle)
186 {
187     /* dlclose is not implemented, and never will be for dylibs.
188      * return -1 to signal an error; it's not used by SBCL anyhow */
189     return -1;
190 }