1/*
2 * Copyright (c) 1999-2008 Apple 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 * The common startup code.  This code is if'ed with the 'C' preprocessor
26 * macros __DYNAMIC__ and GCRT.  It is used to create
27 * the following files when compiled with the following macros defined:
28 *
29 *  File      Dedined Macros	   Purpose
30 * crt1.o	__DYNAMIC__	    startup for programs compiled -dynamic
31 * gcrt1.o	__DYNAMIC__, GCRT   profiling startup, programs compiled -dynamic
32 *
33 * crt0.o			    startup for programs compiled -static
34 *
35 */
36
37#include <stddef.h>
38
39/*
40 * Global data definitions (initialized data).
41 */
42int           NXArgc = 0;
43const char**  NXArgv = NULL;
44const char**  environ = NULL;
45const char*   __progname = NULL;
46
47#if ADD_PROGRAM_VARS
48extern void* __dso_handle;
49struct ProgramVars
50{
51    void*           mh;
52    int*            NXArgcPtr;
53    const char***   NXArgvPtr;
54    const char***   environPtr;
55    const char**    __prognamePtr;
56};
57__attribute__((used))  static struct ProgramVars pvars
58__attribute__ ((section ("__DATA,__program_vars")))  = { &__dso_handle, &NXArgc, &NXArgv, &environ, &__progname };
59
60#endif
61
62
63/*
64 * This file is not needed for executables targeting 10.5 or later
65 * start calls main() directly.
66 */
67#if __DYNAMIC__ && OLD_LIBSYSTEM_SUPPORT
68/*
69 * The following symbols are reference by System Framework symbolicly (instead
70 * of through undefined references (to allow prebinding). To get strip(1) to
71 * know these symbols are not to be stripped they need to have the
72 * REFERENCED_DYNAMICALLY bit (0x10) set.  This would have been done automaticly
73 * by ld(1) if these symbols were referenced through undefined symbols.
74 * The catch_exception_raise symbol is special in that the Mach API specifically
75 * requires that the library call into the user program for its implementation.
76 * Therefore, we need to create a common definition and make sure the symbol
77 * doesn't get stripped.
78 */
79asm(".desc _NXArgc, 0x10");
80asm(".desc _NXArgv, 0x10");
81asm(".desc _environ, 0x10");
82asm(".desc __mh_execute_header, 0x10");
83#if defined(__ppc__) || defined(__i386__)
84asm(".comm _catch_exception_raise, 4");
85asm(".desc _catch_exception_raise, 0x10");
86asm(".comm _catch_exception_raise_state, 4");
87asm(".desc _catch_exception_raise_state, 0x10");
88asm(".comm _catch_exception_raise_state_identity, 4");
89asm(".desc _catch_exception_raise_state_identity, 0x10");
90asm(".comm _do_mach_notify_dead_name, 4");
91asm(".desc _do_mach_notify_dead_name, 0x10");
92asm(".comm _do_seqnos_mach_notify_dead_name, 4");
93asm(".desc _do_seqnos_mach_notify_dead_name, 0x10");
94asm(".comm _do_mach_notify_no_senders, 4");
95asm(".desc _do_mach_notify_no_senders, 0x10");
96asm(".comm _do_seqnos_mach_notify_no_senders, 4");
97asm(".desc _do_seqnos_mach_notify_no_senders, 0x10");
98asm(".comm _do_mach_notify_port_deleted, 4");
99asm(".desc _do_mach_notify_port_deleted, 0x10");
100asm(".comm _do_seqnos_mach_notify_port_deleted, 4");
101asm(".desc _do_seqnos_mach_notify_port_deleted, 0x10");
102asm(".comm _do_mach_notify_send_once, 4");
103asm(".desc _do_mach_notify_send_once, 0x10");
104asm(".comm _do_seqnos_mach_notify_send_once, 4");
105asm(".desc _do_seqnos_mach_notify_send_once, 0x10");
106asm(".comm _clock_alarm_reply, 4");
107asm(".desc _clock_alarm_reply, 0x10");
108asm(".comm _receive_samples, 4");
109asm(".desc _receive_samples, 0x10");
110#endif /* __ppc__ || __i386__ */
111asm(".desc ___progname, 0x10");
112
113/*
114 * Common data definitions.  If the routines in System Framework are not pulled
115 * into the executable then the static linker will allocate these as common
116 * symbols.  The code in here tests the value of these are non-zero to know if
117 * the routines in System Framework got pulled in and should be called.  The
118 * first two are pointers to functions.  The second two use just the symbol
119 * itself.  In the later case we are using the symbol with two different 'C'
120 * types.  To make it as clean as possible the 'C' type declared is that of the
121 * external function.  The common symbol is declared with an asm() and the code
122 * casts the function name to a pointer to an int and then indirects through
123 * the pointer to see if the value is not zero to know the function got linked
124 * in.  Then the code uses a pointer in the data area to the function to call
125 * the function.  The pointer in the data area is needed on various RISC
126 * architectutes like the PowerPC to avoid a relocation overflow error when
127 * linking programs with large data area.
128 */
129extern int (*mach_init_routine)(void);
130extern int (*_cthread_init_routine)(void);
131#if !__DYNAMIC__
132asm(".comm __cplus_init, 4");
133extern void _cplus_init(void);
134#endif
135#if __DYNAMIC__ && __ppc__
136asm(".comm ___darwin_gcc3_preregister_frame_info, 4");
137extern void __darwin_gcc3_preregister_frame_info (void);
138static void (*pointer_to__darwin_gcc3_preregister_frame_info)(void) =
139	__darwin_gcc3_preregister_frame_info;
140#endif
141
142/*
143 * Prototypes for routines that are called.
144 */
145extern int main(int argc, const char* argv[], const char* envp[], const char* apple[]);
146extern void exit(int status) __attribute__ ((noreturn));
147extern int atexit(void (*fcn)(void));
148static const char* crt_basename(const char* path);
149
150#if GCRT
151extern void moninit(void);
152static void _mcleanup(void);
153extern void monitor(char *lowpc,char *highpc,char *buf,int bufsiz,int nfunc);
154#endif /* GCRT */
155
156#if __DYNAMIC__
157extern int _dyld_func_lookup(const char *dyld_func_name,unsigned long *address);
158extern void __keymgr_dwarf2_register_sections (void);
159#endif /* __DYNAMIC__ */
160
161#if __DYNAMIC__ && __ppc__
162static void _call_objcInit(void);
163#endif
164
165extern int errno;
166
167/*
168 * _start() is called from the machine dependent assembly entry point "start:" .
169 * It takes care of setting up the stack so 'C' routines can be called and
170 * passes argc, argv and envp to here.
171 */
172__private_extern__
173void
174_start(int argc, const char* argv[], const char* envp[])
175{
176    const char** apple;
177#if __DYNAMIC__
178    void (*term)(void);
179    void (*init)(void);
180#endif
181
182	// initialize global variables
183	NXArgc = argc;
184	NXArgv = argv;
185	environ = envp;
186	__progname = ((argv[0] != NULL) ? crt_basename(argv[0]) : "");
187	// see start.s for how "apple" parameter follow envp
188	for(apple = envp; *apple != NULL; ++apple) { /* loop */ }
189	++apple;
190
191	// initialize libSystem
192	if ( mach_init_routine != 0 )
193	    (void) mach_init_routine();
194	if ( _cthread_init_routine != 0 )
195	    (*_cthread_init_routine)();
196
197#ifdef __DYNAMIC__
198	__keymgr_dwarf2_register_sections ();
199#endif
200
201#if __ppc__ && __DYNAMIC__
202       /* Call a ppc GCC 3.3-specific function (in libgcc.a) to
203          "preregister" exception frame info, meaning to set up the
204          dyld hooks that do the actual registration.  */
205       if ( *((int *)pointer_to__darwin_gcc3_preregister_frame_info) != 0 )
206           pointer_to__darwin_gcc3_preregister_frame_info ();
207#endif
208
209#if !__DYNAMIC__
210        if(*((int *)_cplus_init) != 0)
211            _cplus_init();
212#endif
213
214#ifdef __DYNAMIC__
215	/*
216	 * Call into dyld to run all initializers. This must be done
217	 * after mach_init()
218	 */
219        _dyld_func_lookup("__dyld_make_delayed_module_initializer_calls",
220                          (unsigned long *)&init);
221        init();
222#endif
223
224#if __DYNAMIC__ && __ppc__
225        _call_objcInit();
226#endif
227
228#ifdef GCRT
229	atexit(_mcleanup);
230	moninit();
231#endif
232
233#ifdef __DYNAMIC__
234	/*
235	 * If the dyld we are running with supports module termination routines
236	 * for all types of images then register the function to call them with
237	 * atexit().
238	 */
239        _dyld_func_lookup("__dyld_mod_term_funcs", (unsigned long *)&term);
240        if ( term != 0 )
241	    atexit(term);
242#endif
243
244	// clear errno, so main() starts fresh
245	errno = 0;
246
247	// call main() and return to exit()
248	exit(main(argc, argv, envp, apple));
249}
250
251#if GCRT
252/*
253 * For profiling the routine _mcleanup gets registered with atexit so monitor(0)
254 * gets called.
255 */
256static
257void
258_mcleanup(
259void)
260{
261	monitor(0,0,0,0,0);
262}
263#endif /* GCRT */
264
265static
266const char *
267crt_basename(const char *path)
268{
269    const char *s;
270    const char *last = path;
271
272    for (s = path; *s != '\0'; s++) {
273        if (*s == '/') last = s+1;
274    }
275
276    return last;
277}
278
279#if __DYNAMIC__ && __ppc__
280static
281int
282crt_strbeginswith(const char *s1, const char *s2)
283{
284    int i;
285
286    for (i = 0; ; i++) {
287        if (s2[i] == '\0') return 1;
288        else if (s1[i] != s2[i]) return 0;
289    }
290}
291
292/*
293 * Look for a function called _objcInit() in any library whose name
294 * starts with "libobjc", and call it if one exists. This is used to
295 * initialize the Objective-C runtime on Mac OS X 10.3 and earlier.
296 * This is completely unnecessary on Mac OS X 10.4 and later.
297 */
298static
299void
300_call_objcInit(void)
301{
302    unsigned int i, count;
303
304    unsigned int (*_dyld_image_count_fn)(void);
305    const char *(*_dyld_get_image_name_fn)(unsigned int image_index);
306    const void *(*_dyld_get_image_header_fn)(unsigned int image_index);
307    const void *(*NSLookupSymbolInImage_fn)(const void *image, const char *symbolName, unsigned int options);
308    void *(*NSAddressOfSymbol_fn)(const void *symbol);
309
310    // Find some dyld functions.
311    _dyld_func_lookup("__dyld_image_count",
312                      (unsigned long *)&_dyld_image_count_fn);
313    _dyld_func_lookup("__dyld_get_image_name",
314                      (unsigned long *)&_dyld_get_image_name_fn);
315    _dyld_func_lookup("__dyld_get_image_header",
316                      (unsigned long *)&_dyld_get_image_header_fn);
317    _dyld_func_lookup("__dyld_NSLookupSymbolInImage",
318                      (unsigned long *)&NSLookupSymbolInImage_fn);
319    _dyld_func_lookup("__dyld_NSAddressOfSymbol",
320                      (unsigned long *)&NSAddressOfSymbol_fn);
321
322    // If any of the dyld functions don't exist, assume we're
323    // on a post-Panther dyld and silently do nothing.
324    if (!_dyld_image_count_fn) return;
325    if (!_dyld_get_image_name_fn) return;
326    if (!_dyld_get_image_header_fn) return;
327    if (!NSLookupSymbolInImage_fn) return;
328    if (!NSAddressOfSymbol_fn) return;
329
330    // Search for an image whose library name starts with "libobjc".
331    count = (*_dyld_image_count_fn)();
332    for (i = 0; i < count; i++) {
333        const void *image;
334        const char *path = (*_dyld_get_image_name_fn)(i);
335        const char *base = crt_basename(path);
336        if (!crt_strbeginswith(base, "libobjc")) continue;
337
338        // Call _objcInit() if library exports it.
339        if ((image = (*_dyld_get_image_header_fn)(i))) {
340            const void *symbol;
341            // 4 == NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
342            if ((symbol = (*NSLookupSymbolInImage_fn)(image,"__objcInit",4))) {
343                void (*_objcInit_fn)(void) =
344                    (void(*)(void))(*NSAddressOfSymbol_fn)(symbol);
345                if (_objcInit_fn) {
346                    (*_objcInit_fn)();
347                    break;
348                }
349            }
350        }
351    }
352}
353
354#endif /* __DYNAMIC__ && __ppc__ */
355
356#endif /* __DYNAMIC__ && OLD_LIBSYSTEM_SUPPORT */
357