]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-load.m
objc4-208.tar.gz
[apple/objc4.git] / runtime / objc-load.m
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 /*
26 * objc-load.m
27 * Copyright 1988-1996, NeXT Software, Inc.
28 * Author: s. naroff
29 *
30 */
31
32 #import "objc-private.h"
33 #import <objc/objc-runtime.h>
34 #import <objc/hashtable2.h>
35 #import <objc/Object.h>
36 #import <objc/Protocol.h>
37
38 #if defined(__MACH__) || defined(WIN32)
39 #import <streams/streams.h>
40 #endif
41
42
43 #if !defined(NeXT_PDO)
44 // MACH
45 #include <mach-o/dyld.h>
46 #endif
47
48 #if defined(WIN32)
49 #import <winnt-pdo.h>
50 #import <windows.h>
51 #endif
52
53 #if defined(__svr4__)
54 #import <dlfcn.h>
55 #endif
56
57 #if defined(__hpux__) || defined(hpux)
58 #import "objc_hpux_register_shlib.c"
59 #endif
60
61 extern char * getsectdatafromheader (const headerType * mhp, const char * segname, const char * sectname, int * size);
62
63 /* Private extern */
64 OBJC_EXPORT void (*callbackFunction)( Class, const char * );
65
66
67 struct objc_method_list **get_base_method_list(Class cls) {
68 struct objc_method_list **ptr = ((struct objc_class * )cls)->methodLists;
69 if (!*ptr) return NULL;
70 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }
71 --ptr;
72 return ptr;
73 }
74
75
76 #if defined(NeXT_PDO) // GENERIC_OBJ_FILE
77 void send_load_message_to_class(Class cls, void *header_addr)
78 {
79 struct objc_method_list **mlistp = get_base_method_list(cls->isa);
80 struct objc_method_list *mlist = mlistp ? *mlistp : NULL;
81 IMP load_method;
82
83 if (mlist) {
84 load_method =
85 class_lookupNamedMethodInMethodList(mlist, "finishLoading:");
86
87 /* go directly there, we do not want to accidentally send
88 the finishLoading: message to one of its categories...
89 */
90 if (load_method)
91 (*load_method)((id)cls, @selector(finishLoading:),
92 header_addr);
93 }
94 }
95
96 void send_load_message_to_category(Category cat, void *header_addr)
97 {
98 struct objc_method_list *mlist = cat->class_methods;
99 IMP load_method;
100 Class cls;
101
102 if (mlist) {
103 load_method =
104 class_lookupNamedMethodInMethodList(mlist, "finishLoading:");
105
106 cls = objc_getClass (cat->class_name);
107
108 /* go directly there, we do not want to accidentally send
109 the finishLoading: message to one of its categories...
110 */
111 if (load_method)
112 (*load_method)(cls, @selector(finishLoading:),
113 header_addr);
114 }
115 }
116 #endif // GENERIC_OBJ_FILE
117
118 /**********************************************************************************
119 * objc_loadModule.
120 *
121 * NOTE: Loading isn't really thread safe. If a load message recursively calls
122 * objc_loadModules() both sets will be loaded correctly, but if the original
123 * caller calls objc_unloadModules() it will probably unload the wrong modules.
124 * If a load message calls objc_unloadModules(), then it will unload
125 * the modules currently being loaded, which will probably cause a crash.
126 *
127 * Error handling is still somewhat crude. If we encounter errors while
128 * linking up classes or categories, we will not recover correctly.
129 *
130 * I removed attempts to lock the class hashtable, since this introduced
131 * deadlock which was hard to remove. The only way you can get into trouble
132 * is if one thread loads a module while another thread tries to access the
133 * loaded classes (using objc_lookUpClass) before the load is complete.
134 **********************************************************************************/
135 int objc_loadModule (const char * moduleName,
136 void (*class_callback) (Class, const char *categoryName),
137 int * errorCode)
138 {
139 int successFlag = 1;
140 int locErrorCode;
141 #if defined(__MACH__)
142 NSObjectFileImage objectFileImage;
143 NSObjectFileImageReturnCode code;
144 #endif
145 #if defined(WIN32) || defined(__svr4__) || defined(__hpux__) || defined(hpux)
146 void * handle;
147 void (*save_class_callback) (Class, const char *) = load_class_callback;
148 #endif
149
150 // So we don't have to check this everywhere
151 if (errorCode == NULL)
152 errorCode = &locErrorCode;
153
154 #if defined(__MACH__)
155 if (moduleName == NULL)
156 {
157 *errorCode = NSObjectFileImageInappropriateFile;
158 return 0;
159 }
160
161 if (_dyld_present () == 0)
162 {
163 *errorCode = NSObjectFileImageFailure;
164 return 0;
165 }
166
167 callbackFunction = class_callback;
168 code = NSCreateObjectFileImageFromFile (moduleName, &objectFileImage);
169 if (code != NSObjectFileImageSuccess)
170 {
171 *errorCode = code;
172 return 0;
173 }
174
175 #if !defined(__OBJC_DONT_USE_NEW_NSLINK_OPTION__)
176 if (NSLinkModule(objectFileImage, moduleName, NSLINKMODULE_OPTION_RETURN_ON_ERROR) == NULL) {
177 NSLinkEditErrors error;
178 int errorNum;
179 char *fileName, *errorString;
180 NSLinkEditError(&error, &errorNum, &fileName, &errorString);
181 // These errors may overlap with other errors that objc_loadModule returns in other failure cases.
182 *errorCode = error;
183 return 0;
184 }
185 #else
186 (void)NSLinkModule(objectFileImage, moduleName, NSLINKMODULE_OPTION_NONE);
187 #endif
188 callbackFunction = NULL;
189
190 #else
191 // The PDO cases
192 if (moduleName == NULL)
193 {
194 *errorCode = 0;
195 return 0;
196 }
197
198 OBJC_LOCK(&loadLock);
199
200 #if defined(WIN32) || defined(__svr4__) || defined(__hpux__) || defined(hpux)
201
202 load_class_callback = class_callback;
203
204 #if defined(WIN32)
205 if ((handle = LoadLibrary (moduleName)) == NULL)
206 {
207 FreeLibrary(moduleName);
208 *errorCode = 0;
209 successFlag = 0;
210 }
211
212 #elif defined(__svr4__)
213 handle = dlopen(moduleName, (RTLD_NOW | RTLD_GLOBAL));
214 if (handle == 0)
215 {
216 *errorCode = 0;
217 successFlag = 0;
218 }
219 else
220 {
221 objc_register_header(moduleName);
222 objc_finish_header();
223 }
224
225 #else
226 handle = shl_load(moduleName, BIND_IMMEDIATE | BIND_VERBOSE, 0L);
227 if (handle == 0)
228 {
229 *errorCode = 0;
230 successFlag = 0;
231 }
232 else
233 ; // Don't do anything here: the shlib should have been built
234 // with the +I'objc_hpux_register_shlib' option
235 #endif
236
237 load_class_callback = save_class_callback;
238
239 #elif defined(NeXT_PDO)
240 // NOTHING YET...
241 successFlag = 0;
242 #endif // WIN32
243
244 OBJC_UNLOCK (&loadLock);
245
246 #endif // MACH
247
248 return successFlag;
249 }
250
251 /**********************************************************************************
252 * objc_loadModules.
253 **********************************************************************************/
254 /* Lock for dynamic loading and unloading. */
255 static OBJC_DECLARE_LOCK (loadLock);
256 #if defined(NeXT_PDO) // GENERIC_OBJ_FILE
257 void (*load_class_callback) (Class, const char *);
258 #endif
259
260
261 long objc_loadModules (char * modlist[],
262 void * errStream,
263 void (*class_callback) (Class, const char *),
264 headerType ** hdr_addr,
265 char * debug_file)
266 {
267 char ** modules;
268 int code;
269 int itWorked;
270
271 if (modlist == 0)
272 return 0;
273
274 for (modules = &modlist[0]; *modules != 0; modules++)
275 {
276 itWorked = objc_loadModule (*modules, class_callback, &code);
277 if (itWorked == 0)
278 {
279 #if defined(__MACH__) || defined(WIN32)
280 if (errStream)
281 NXPrintf ((NXStream *) errStream, "objc_loadModules(%s) code = %d\n", *modules, code);
282 #endif
283 return 1;
284 }
285
286 if (hdr_addr)
287 *(hdr_addr++) = 0;
288 }
289
290 return 0;
291 }
292
293 /**********************************************************************************
294 * objc_unloadModules.
295 *
296 * NOTE: Unloading isn't really thread safe. If an unload message calls
297 * objc_loadModules() or objc_unloadModules(), then the current call
298 * to objc_unloadModules() will probably unload the wrong stuff.
299 **********************************************************************************/
300
301 long objc_unloadModules (void * errStream,
302 void (*unload_callback) (Class, Category))
303 {
304 headerType * header_addr = 0;
305 int errflag = 0;
306
307 // TODO: to make unloading work, should get the current header
308
309 if (header_addr)
310 {
311 ; // TODO: unload the current header
312 }
313 else
314 {
315 errflag = 1;
316 }
317
318 return errflag;
319 }
320