sdk-core
v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Toggle main menu visibility
Loading...
Searching...
No Matches
crt0.c
1
/*
2
# _____ ___ ____ ___ ____
3
# ____| | ____| | | |____|
4
# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5
#-----------------------------------------------------------------------
6
# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
7
# Licenced under Academic Free License version 2.0
8
# Review ps2sdk README & LICENSE files for further details.
9
*/
10
11
#include <
kernel.h
>
12
#include <
stdio.h
>
13
#include <stdint.h>
14
#include <stdnoreturn.h>
// noreturn
15
#include <
string.h
>
16
#include <
startup.h
>
17
18
extern
char
* _end;
19
extern
char
* _heap_size;
20
extern
char
* _fbss;
21
extern
char
* _stack;
22
extern
char
* _stack_size;
23
24
__attribute__
((weak))
void
_ps2sdk_memory_init();
25
__attribute__
((weak))
void
_init();
26
__attribute__
((weak))
void
_fini();
27
28
// Real, confirmed bug (2026-09-07): __attribute__((constructor)) never ran
29
// anywhere in this SDK, on real hardware or any emulator - "if (_init)
30
// _init();" below was always a no-op. _init/__libc_init_array are
31
// normally provided by gcc's own crtbegin.o/crtend.o, which -nostartfiles
32
// (required here - this file *is* the startup code) never links. This
33
// compiler emits the legacy .ctors section (confirmed via objdump - not
34
// .init_array), so crtbegin.o's own __do_global_ctors_aux is what would
35
// have walked it; without that object, nothing does. __CTOR_LIST__/
36
// __CTOR_END__ (provided by the linkfile, see its own comment) bound the
37
// section directly, sidestepping the need for crtbegin.o's own -1
38
// start-sentinel/0 end-terminator convention entirely. Real GCC .ctors
39
// calling order is reverse-array (highest address/lowest priority
40
// first), matching __do_global_ctors_aux's own real behavior.
41
extern
void (*__CTOR_LIST__[])(void);
42
extern
void (*__CTOR_END__[])(void);
43
44
// clang emits .init_array instead of .ctors for global/static C++
45
// constructors - see the linkfile's own comment on __init_array_start/
46
// __init_array_end. Unlike .ctors (walked in reverse), .init_array runs
47
// in forward array order per the Itanium C++ ABI.
48
extern
void (*__init_array_start[])(void);
49
extern
void (*__init_array_end[])(void);
50
51
// Real, confirmed bug: any global/static C++ object with a non-trivial
52
// destructor fails to link with "undefined reference to `__dso_handle`".
53
// GCC emits a __cxa_atexit(dtor, obj, &__dso_handle) call at that
54
// object's construction point; __dso_handle is normally defined by
55
// gcc's own crtbegin.o, which -nostartfiles (required here - this file
56
// *is* the startup code, see above) never links. A statically-linked
57
// PS2 ELF is always exactly one "module" (no dlclose, no shared
58
// objects), so the value only needs to be a stable, unique address -
59
// same minimal fix used by other no-crtbegin bare-metal targets
60
// (avr-libc and similar). weak so a real crtbegin.o's own definition
61
// would still win if some future path ever links one instead.
62
void
*__dso_handle
__attribute__
((weak)) = &__dso_handle;
63
64
static
void
_call_global_ctors(
void
)
65
{
66
int
count
= __CTOR_END__ - __CTOR_LIST__;
67
for
(
int
i =
count
- 1; i >= 0; i--)
68
__CTOR_LIST__[i]();
69
70
int
init_array_count = __init_array_end - __init_array_start;
71
for
(
int
i = 0; i < init_array_count; i++)
72
__init_array_start[i]();
73
}
74
75
void
_libcglue_args_parse(
int
argc,
char
** argv);
76
void
_libcglue_init();
77
void
_libcglue_deinit();
78
int
main(
int
argc,
char
** argv);
79
80
// __attribute__((used)): _main is only reachable via the raw "j _main"
81
// below, not a real C call the compiler can see - without this it gets
82
// optimized away as dead code before the asm ever runs. Real linker
83
// relocation from that jump keeps it past --gc-sections regardless.
84
static
void
_main()
__attribute__
((used));
85
86
static struct
sargs
args;
87
static struct
sargs_start
*args_start;
88
89
/*
90
* First function to be called by the loader
91
* This function sets up the stack and heap.
92
* DO NOT USE THE STACK IN THIS FUNCTION!
93
*/
94
void
__start(struct
sargs_start
*pargs)
95
{
96
__asm__ __volatile__(
97
"# Clear bss area \n"
98
".set noat \n"
99
"la $2, _fbss \n"
100
"la $3, _end \n"
101
"1: \n"
102
"sltu $1, $2, $3 \n"
103
"beq $1, $0, 2f \n"
104
"nop \n"
105
"sq $0, ($2) \n"
106
"addiu $2, $2, 16 \n"
107
"j 1b \n"
108
"nop \n"
109
"2: \n"
110
" \n"
111
"# Save first argument \n"
112
"sw %1, %0 \n"
113
" \n"
114
"# SetupThread \n"
115
"la $4, _gp \n"
116
"la $5, _stack \n"
117
"la $6, _stack_size \n"
118
"la $7, args \n"
119
"la $8, ExitThread \n"
120
"move $gp, $4 \n"
121
"addiu $3, $0, 60 \n"
122
"syscall \n"
123
"move $sp, $2 \n"
124
" \n"
125
"# Jump to _main \n"
126
"j _main \n"
127
".set at \n"
128
:
/* No outputs. */
129
:
"m"
(args_start),
"r"
(pargs)
130
:
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
,
"8"
);
131
}
132
133
/*
134
* Intermediate function between _start and main, stack can be used as normal.
135
*/
136
static
void
_main()
137
{
138
int
retval;
139
struct
sargs
*pa;
140
141
// initialize heap
142
SetupHeap(&_end, (
int
)&_heap_size);
143
144
// writeback data cache
145
FlushCache(0);
146
147
// Capability to override 32MiB on DESR/DVR models
148
// NOTE: this call can restart the application
149
if
(_ps2sdk_memory_init)
150
_ps2sdk_memory_init();
151
152
// Initialize the kernel (Apply necessary patches).
153
_InitSys();
154
155
// Use arguments sent through start if sent (by ps2link for instance)
156
pa = &args;
157
if
(args.argc == 0 && args_start != NULL && args_start->args.argc != 0)
158
pa = &args_start->args;
159
160
// call libcglue argument parsing
161
_libcglue_args_parse(pa->argc, pa->argv);
162
163
// initialize libcglue
164
_libcglue_init();
165
166
// Enable interruts
167
EI();
168
169
// call global constructors - see _call_global_ctors's own comment
170
// for why this replaces the old (always-dead) "if (_init) _init();"
171
_call_global_ctors();
172
173
// call main
174
retval = main(pa->argc, pa->argv);
175
176
// call global destructors (weak)
177
if
(_fini)
178
_fini();
179
180
// uninitialize libcglue
181
_libcglue_deinit();
182
183
// Exit
184
Exit(retval);
185
}
186
187
noreturn
void
_exit(
int
status)
188
{
189
// call global destructors (weak)
190
if
(_fini)
191
_fini();
192
193
// uninitialize libcglue
194
_libcglue_deinit();
195
196
// Exit
197
Exit(status);
198
}
kernel.h
startup.h
stdio.h
string.h
__attribute__
Definition
gif_registers.h:40
sargs_start
Definition
startup.h:38
sargs
Definition
startup.h:31
count
u32 count
start sector of fragmented bd/file
Definition
usbhdfsd-common.h:1
core
startup
src
ee
crt0.c
Generated by
1.18.0