|
|
1.1 root 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.0 (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: * objc-load.m
26: * Copyright 1988, NeXT, Inc.
27: * Author: s. naroff
28: *
29: */
30: #ifdef SHLIB
31: #import "shlib.h"
32: #endif SHLIB
33:
34: #import "objc-private.h"
35: #import "objc-load.h"
36: #import "objc-runtime.h"
37: #import "hashtable.h"
38: #import "Object.h"
39: #import "Protocol.h"
40: #include <NXString.h>
41: #include <mach-o/rld.h>
42:
43: #ifdef RUNTIME_DYLD
44: #include <mach-o/dyld.h>
45: #endif
46:
47: #ifdef KERNEL
48: extern char *getsectdatafromheader(
49: const struct mach_header *mhp,
50: const char *segname,
51: const char *sectname,
52: int *size);
53: #endif
54:
55: @interface Protocol(Private)
56: + _fixup: (void *)protos numElements: (int) nentries;
57: @end
58:
59: /* Private extern */
60: extern struct mach_header *rld_get_current_header(void);
61: extern void (*callbackFunction)( Class, Category );
62:
63: static inline void map_selrefs (SEL *sels, unsigned int cnt)
64: {
65: unsigned int i;
66:
67: /* Overwrite the string with a unique identifier. */
68: for (i = 0; i < cnt; i++)
69: {
70: SEL sel = sel_registerName ((const char *) sels[i]);
71:
72: if (sels[i] != sel)
73: sels[i] = sel;
74: }
75: }
76:
77:
78: static inline void map_methods (struct objc_method_list *methods)
79: {
80: unsigned int i;
81:
82: for (i = 0; i < methods->method_count; i++)
83: {
84: Method method = &methods->method_list[i];
85: SEL sel = sel_registerName ((const char *) method->method_name);
86:
87: if (method->method_name != sel)
88: method->method_name = sel;
89: }
90: }
91:
92:
93: static inline void map_method_descs (struct objc_method_description_list *methods)
94: {
95: unsigned int i;
96:
97: for (i = 0; i < methods->count; i++)
98: {
99: struct objc_method_description *method = &methods->list[i];
100: SEL sel = sel_registerName ((const char *) method->name);
101:
102: if (method->name != sel)
103: method->name = sel;
104: }
105: }
106:
107:
108: static struct objc_method_list *get_base_method_list(Class cls)
109: {
110: struct objc_method_list *mlist, *prev = 0;
111:
112: for (mlist = cls->methods; mlist; mlist = mlist->method_next)
113: prev = mlist;
114:
115: return prev;
116: }
117:
118: static void send_load_message_to_class(Class cls, void *header_addr)
119: {
120: struct objc_method_list *mlist = get_base_method_list(cls->isa);
121: IMP load_method;
122:
123: if (mlist) {
124: load_method =
125: class_lookupMethodInMethodList(mlist,
126: @selector(finishLoading:));
127:
128: /* go directly there, we do not want to accidentally send
129: the finishLoading: message to one of its categories...
130: */
131: if (load_method)
132: (*load_method)((id)cls, @selector(finishLoading:),
133: header_addr);
134: }
135: }
136:
137: static void send_load_message_to_category(Category cat, void *header_addr)
138: {
139: struct objc_method_list *mlist = cat->class_methods;
140: IMP load_method;
141: Class cls;
142:
143: if (mlist) {
144: load_method =
145: class_lookupMethodInMethodList(mlist,
146: @selector(finishLoading:));
147:
148: cls = objc_getClass (cat->class_name);
149:
150: /* go directly there, we do not want to accidentally send
151: the finishLoading: message to one of its categories...
152: */
153: if (load_method)
154: (*load_method)(cls, @selector(finishLoading:),
155: header_addr);
156: }
157: }
158:
159: static void send_unload_message_to_class(Class cls)
160: {
161: struct objc_method_list *mlist = get_base_method_list(cls->isa);
162: IMP load_method;
163:
164: if (mlist) {
165: load_method =
166: class_lookupMethodInMethodList(mlist,
167: @selector(startUnloading));
168:
169: /* go directly there, we do not want to accidentally send
170: the finishLoading: message to one of its categories...
171: */
172: if (load_method)
173: (*load_method)((id)cls,
174: @selector(startUnloading));
175: }
176: }
177:
178: static void send_unload_message_to_category(Category cat)
179: {
180: struct objc_method_list *mlist = cat->class_methods;
181: IMP load_method;
182: Class cls;
183:
184: if (mlist) {
185: load_method =
186: class_lookupMethodInMethodList(mlist,
187: @selector(startUnloading));
188:
189: cls = objc_getClass (cat->class_name);
190:
191: /* go directly there, we do not want to accidentally send
192: the finishLoading: message to one of its categories...
193: */
194: if (load_method)
195: (*load_method)((id)cls,
196: @selector(startUnloading));
197: }
198: }
199:
200: static void _objc_fixup_string_objects_from_header(struct mach_header *header)
201: {
202: NXConstantString *section;
203: unsigned int size;
204:
205: section = (NXConstantString *) getsectdatafromheader (header,
206: SEG_OBJC, "__string_object", &size);
207: if (section != 0 && size != 0)
208: {
209: Class constantStringClass = objc_getClass ("NXConstantString");
210: unsigned int i;
211:
212: for (i = 0; i < size / sizeof (NXConstantString); i++)
213: *((Class *) §ion[i]) = constantStringClass;
214: }
215: }
216:
217:
218: int objc_registerModule (struct mach_header *header_addr,
219: void (*class_callback) (Class, Category))
220: {
221: Module mod, modhdr;
222: int size, saveSize, i;
223: SEL *sels;
224: // this isn't very object oriented!...bypass ivar protection.
225: struct proto_template { @defs(Protocol) } *protos;
226: Class *cls_refs;
227: int errflag = 0;
228:
229: #ifdef RUNTIME_DYLD
230: if (_dyld_present ())
231: {
232: fprintf (stderr, "objc_registerModule not supported in dynamic programs\n");
233: return 1;
234: }
235: #endif
236:
237: modhdr = (Module) getsectdatafromheader (header_addr,
238: SEG_OBJC, "__module_info", &saveSize);
239:
240: /* Check for duplicate classes.
241: This should never happen since rld should detect multiple
242: definitions of the .objc_class_name_XXX symbols. */
243: for (mod = modhdr, size = saveSize;
244: mod && size;
245: size -= mod->size, (char *) mod += mod->size)
246: {
247: for (i = 0; i < mod->symtab->cls_def_cnt; i++)
248: {
249: Class cls = mod->symtab->defs[i];
250:
251: if ((cls = objc_lookUpClass (mod->symtab->defs[i])))
252: {
253: #if 0
254: NXPrintf (errStream, "objc_loadModules(): "
255: "Duplicate definition for class `%s'\n",
256: [cls name]);
257: #endif
258: errflag = 1;
259: }
260: }
261: }
262:
263: if (errflag)
264: return 1;
265:
266: _objc_addHeader (header_addr, 0);
267:
268: /* Fixup string objects. */
269: _objc_fixup_string_objects_from_header (header_addr);
270:
271: /* Map selectors. */
272: sels = (SEL *) getsectdatafromheader (header_addr,
273: SEG_OBJC, "__message_refs", &size);
274: if (sels)
275: map_selrefs (sels, size / sizeof (SEL));
276:
277: /* Fixup protocol objects. */
278: protos = (struct proto_template *) getsectdatafromheader (
279: header_addr, SEG_OBJC, "__protocol", &size);
280: if (protos)
281: {
282: unsigned int i;
283:
284: for (i = 0; i < size / sizeof (Protocol); i++) {
285:
286: /* can't use map_methods, the sizes differ. */
287: if (protos[i].instance_methods)
288: map_method_descs (protos[i].instance_methods);
289: if (protos[i].class_methods)
290: map_method_descs (protos[i].class_methods);
291: }
292: [Protocol _fixup: protos numElements: size / sizeof (Protocol)];
293: }
294:
295: /* Insert classes into class hashtable */
296: for (mod = modhdr, size = saveSize;
297: mod && size;
298: size -= mod->size, (char *) mod += mod->size)
299: {
300: for (i = 0; i < mod->symtab->cls_def_cnt; i++)
301: {
302: objc_addClass (mod->symtab->defs[i]);
303: }
304: }
305:
306: /* Process class definitions. */
307: for (mod = modhdr, size = saveSize;
308: mod && size;
309: size -= mod->size, (char *) mod += mod->size)
310: {
311: for (i = 0; i < mod->symtab->cls_def_cnt; i++)
312: {
313: Class cls = mod->symtab->defs[i];
314:
315: if (cls->methods)
316: map_methods (cls->methods);
317: if (cls->isa->methods)
318: map_methods (cls->isa->methods);
319:
320: _class_install_relationships (cls, mod->version);
321:
322: /* Versions 3 and 4 will never ship; internal compatibility only.
323: Compensate for "next" field in struct objc_protocol_list. */
324: if (cls->isa->version >= 3 && cls->isa->version <= 4
325: && cls->protocols)
326: {
327: (char *) cls->protocols -= 4;
328: (char *) cls->isa->protocols -= 4;
329: }
330:
331: /* for internal compatibility...should remove! */
332: if ((cls->isa->version == 3) && cls->protocols)
333: {
334: _objc_inform ("Unable to install protocols by name...\n");
335: _objc_inform ("Class %s must be recompiled.\n",
336: cls->name);
337: cls->protocols = 0;
338: cls->isa->protocols = 0;
339: }
340: }
341: }
342:
343: /* We must process all classes before any categories, or else
344: we might map the selectors for a category method twice. */
345:
346: /* Process category definitions. */
347: for (mod = modhdr, size = saveSize;
348: mod && size;
349: size -= mod->size, (char *) mod += mod->size)
350: {
351: for (i = mod->symtab->cls_def_cnt;
352: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt;
353: i++)
354: {
355: Category cat = mod->symtab->defs[i];
356:
357: if (cat->instance_methods)
358: map_methods (cat->instance_methods);
359: if (cat->class_methods)
360: map_methods (cat->class_methods);
361:
362: _objc_add_category (mod->symtab->defs[i], mod->version);
363: }
364: }
365:
366: /* Handle v1.0 mapping of selector references */
367: for (mod = modhdr, size = saveSize;
368: mod && size;
369: size -= mod->size, (char *) mod += mod->size)
370: {
371: if (mod->version == 1)
372: map_selrefs (mod->symtab->refs, mod->symtab->sel_ref_cnt);
373: }
374:
375: #ifdef OBJC_CLASS_REFS
376: /* Fixup class references. */
377: cls_refs = (Class *) getsectdatafromheader (
378: header_addr, SEG_OBJC, "__cls_refs", &size);
379: if (cls_refs)
380: {
381: unsigned int i;
382:
383: for (i = 0; i < size / sizeof (Class); i++)
384: cls_refs[i] = objc_getClass ((const char *) cls_refs[i]);
385: }
386: #endif /* OBJC_CLASS_REFS */
387:
388: /* Do we guarantee any ordering of load messages?
389: We might send a load message to a subclass before its superclass.
390:
391: Also, a load method might send a message to a class which hasn't
392: received its load message yet by using objc_getClass ().
393:
394: To solve these problems properly, we probably need to add a
395: "loaded" bit to the class structure in addition to the
396: "initialized" bit. */
397:
398: /* Send load messages and activate call backs to classes. */
399: for (mod = modhdr, size = saveSize;
400: mod && size;
401: size -= mod->size, (char *) mod += mod->size)
402: {
403: for (i = 0; i < mod->symtab->cls_def_cnt; i++)
404: {
405: if (class_callback)
406: (*class_callback) (mod->symtab->defs[i], 0);
407:
408: send_load_message_to_class (mod->symtab->defs[i],
409: header_addr);
410: }
411: }
412:
413: /* Send load messages and activate call backs to categories. */
414: for (mod = modhdr, size = saveSize;
415: mod && size;
416: size -= mod->size, (char *) mod += mod->size)
417: {
418: for (i = mod->symtab->cls_def_cnt;
419: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt;
420: i++)
421: {
422: if (class_callback)
423: (*class_callback) (objc_getClass(((Category)mod->symtab->defs[i])->class_name),
424: (Category)mod->symtab->defs[i]);
425:
426: send_load_message_to_category((Category)mod->symtab->defs[i],
427: header_addr);
428: }
429: }
430:
431: return 0;
432: }
433:
434:
435: #ifndef KERNEL
436: static
437: #endif
438: void objc_unregisterModule (struct mach_header *header_addr,
439: void (*unload_callback) (Class, Category))
440: {
441: Module mod, modhdr;
442: int size, i, saveSize, strsize;
443: const char *strs;
444:
445: #ifdef RUNTIME_DYLD
446: if (_dyld_present ())
447: {
448: fprintf (stderr, "objc_unregisterModule not supported in dynamic programs\n");
449: return;
450: }
451: #endif
452:
453:
454: modhdr = (Module) getsectdatafromheader (header_addr,
455: SEG_OBJC, "__module_info", &saveSize);
456:
457: /* Send unload messages and deactivate call backs to categories. */
458: for (mod = modhdr, size = saveSize;
459: mod && size;
460: size -= mod->size, (char *) mod += mod->size)
461: {
462: for (i = mod->symtab->cls_def_cnt;
463: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt;
464: i++)
465: {
466: Category cat = mod->symtab->defs[i];
467:
468: if (unload_callback)
469: (*unload_callback) (objc_getClass (cat->class_name), cat);
470:
471: send_unload_message_to_category (cat);
472: }
473: }
474:
475: /* Send unload messages and deactivate call backs to classes. */
476: for (mod = modhdr, size = saveSize;
477: mod && size;
478: size -= mod->size, (char *) mod += mod->size)
479: {
480: for (i = 0; i < mod->symtab->cls_def_cnt; i++)
481: {
482: Class cls = mod->symtab->defs[i];
483:
484: if (unload_callback)
485: (*unload_callback) (cls, 0);
486:
487: send_unload_message_to_class (cls);
488: }
489: }
490:
491: /* Remove categories. */
492: for (mod = modhdr, size = saveSize;
493: mod && size;
494: size -= mod->size, (char *) mod += mod->size)
495: {
496: for (i = mod->symtab->cls_def_cnt;
497: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt;
498: i++)
499: {
500: Category cat = mod->symtab->defs[i];
501:
502: _objc_remove_category (cat, mod->version);
503: }
504: }
505:
506: /* Remove classes. */
507: for (mod = modhdr, size = saveSize;
508: mod && size;
509: size -= mod->size, (char *) mod += mod->size)
510: {
511: for (i = 0; i < mod->symtab->cls_def_cnt; i++)
512: {
513: Class cls = mod->symtab->defs[i];
514:
515: _objc_removeClass (cls);
516: }
517: }
518:
519: /* Do we really want to do this?
520: What if I load Foo.o which contains a new selector "foo",
521: then I unload Foo.o and load Bar.o which also contains the
522: selector "foo". The value of the selector may change!
523: I think that selector mappings need to be permanent. */
524:
525: /* Unload any selectors that might have been unique to this module. */
526: strs = (const char *) getsectdatafromheader (header_addr,
527: SEG_OBJC, "__meth_var_names", &strsize);
528:
529: if (strs)
530: _sel_unloadSelectors (strs, strs + strsize);
531:
532: /* Unload old-style strings too. */
533: strs = (const char *) getsectdatafromheader (header_addr,
534: SEG_OBJC, "__selector_strs", &strsize);
535:
536: if (strs)
537: _sel_unloadSelectors (strs, strs + strsize);
538:
539: _objc_removeHeader (header_addr);
540: }
541:
542:
543: #ifndef KERNEL
544:
545: /* Lock for dynamic loading and unloading. */
546:
547: static OBJC_DECLARE_LOCK (loadLock);
548:
549: /* Loading isn't really thread safe. If a load message recursively calls
550: objc_loadModules() both sets will be loaded correctly, but if the original
551: caller calls objc_unloadModules() it will probably unload the wrong modules.
552: If a load message calls objc_unloadModules(), then it will unload
553: the modules currently being loaded, which will probably cause a crash. */
554:
555: /* Error handling is still somewhat crude. If we encounter errors while
556: linking up classes or categories, we will not recover correctly.
557: Hopefully rld_load () will detect these problems for us. */
558:
559: /* I removed atempts to lock the class hashtable, since this introduced
560: deadlock which was hard to remove. The only way you can get into trouble
561: is if one thread loads a module while another thread tries to access the
562: loaded classes (using objc_lookUpClass) before the load is complete. */
563:
564: long objc_loadModules (
565: char *modlist[],
566: NXStream *errStream,
567: void (*class_callback) (Class, Category),
568: struct mach_header **hdr_addr,
569: char *debug_file)
570: {
571: struct mach_header *header_addr;
572: int errflag = 0;
573:
574: #ifdef RUNTIME_DYLD
575: if (_dyld_present ())
576: {
577: NSObjectFileImage objectFileImage;
578: NSModule module;
579:
580: char **modules;
581:
582: callbackFunction = class_callback;
583: for (modules = &modlist[0]; *modules != 0; modules++)
584: {
585: NSObjectFileImageReturnCode code
586: = NSCreateObjectFileImageFromFile (*modules, &objectFileImage);
587:
588: if (code != NSObjectFileImageSuccess)
589: {
590: if (errStream)
591: NXPrintf (errStream,
592: "objc_loadModules(%s) NSObjectFileImageReturnCode = %d\n", *modules, code);
593:
594: errflag = 1;
595: continue;
596: }
597:
598: module = NSLinkModule(objectFileImage, *modules, 0);
599: }
600: callbackFunction = 0;
601: }
602: else
603: #endif
604:
605: {
606:
607: OBJC_LOCK (&loadLock);
608:
609: if (rld_load (errStream, &header_addr, modlist, debug_file))
610: {
611: errflag = objc_registerModule (header_addr, class_callback);
612:
613: /* Unload everything on errors. */
614: if (errflag)
615: rld_unload (errStream);
616: else
617: {
618: /* Return optional output parameter */
619: if (hdr_addr)
620: *hdr_addr = header_addr;
621: }
622: }
623: else
624: errflag = 1;
625:
626: OBJC_UNLOCK (&loadLock);
627: }
628:
629: return errflag;
630: }
631:
632:
633: /* Unloading isn't really thread safe. If an unload message calls
634: objc_loadModules() or objc_unloadModules(), then the current call
635: to objc_unloadModules() will probably unload the wrong stuff. */
636:
637: long objc_unloadModules (
638: NXStream *errStream,
639: void (*unload_callback) (Class, Category))
640: {
641: struct mach_header *header_addr = rld_get_current_header ();
642: int errflag = 0;
643:
644: if (header_addr)
645: {
646: objc_unregisterModule (header_addr, unload_callback);
647:
648: OBJC_LOCK (&loadLock);
649:
650: if (rld_unload (errStream) == 0)
651: errflag = 1;
652:
653: OBJC_UNLOCK (&loadLock);
654: }
655: else
656: {
657: NXPrintf (errStream, "objc_unloadModules(): No modules to unload\n");
658: errflag = 1;
659: }
660:
661: return errflag;
662: }
663:
664: #endif /* not KERNEL */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.