Skip to content

Commit 44988ee

Browse files
committed
Introduce 2-stage Objective-C initialization
This breaks loading into two deterministic stages: class registration and class resolution. The original GNUstep ABI as implemented in Clang emits calls to __objc_exec_class into the user static init section, interleaving them with other static initializers and subjecting them to static initialization ordering issues. +load can therefore be called on one class when another class's module hasn't even been registered. Clang -fobjc-runtime=microsoft preferentially emits objc_module_abi_8*s into a binary section that's then registered and resolved (in that order) once on load, and that loading happens in the "library" init phase on PE/COFF platforms. Compatibility with __objc_exec_class-based registration is not compromised.
1 parent 6e4fa86 commit 44988ee

File tree

1 file changed

+54
-9
lines changed

1 file changed

+54
-9
lines changed

loader.c

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ __attribute__((weak)) void (*dispatch_end_thread_4GC)(void);
4343
__attribute__((weak)) void *(*_dispatch_begin_NSAutoReleasePool)(void);
4444
__attribute__((weak)) void (*_dispatch_end_NSAutoReleasePool)(void *);
4545

46-
void __objc_exec_class(struct objc_module_abi_8 *module)
46+
void __objc_load_module(struct objc_module_abi_8 *module)
4747
{
4848
static BOOL first_run = YES;
4949

@@ -113,7 +113,6 @@ void __objc_exec_class(struct objc_module_abi_8 *module)
113113
{
114114
objc_load_class(symbols->definitions[defs++]);
115115
}
116-
unsigned int category_start = defs;
117116
// Load the categories from this module
118117
for (unsigned short i=0 ; i<symbols->category_count; i++)
119118
{
@@ -129,17 +128,63 @@ void __objc_exec_class(struct objc_module_abi_8 *module)
129128
// Load categories and statics that were deferred.
130129
objc_load_buffered_categories();
131130
objc_init_buffered_statics();
131+
}
132+
133+
void __objc_resolve_module(struct objc_module_abi_8 *module)
134+
{
135+
LOCK_RUNTIME_FOR_SCOPE();
132136
// Fix up the class links for loaded classes.
133137
objc_resolve_class_links();
134-
for (unsigned short i=0 ; i<symbols->category_count; i++)
138+
if (NULL != module)
135139
{
136-
struct objc_category *cat = (struct objc_category*)
137-
symbols->definitions[category_start++];
138-
Class class = (Class)objc_getClass(cat->class_name);
139-
if ((Nil != class) &&
140-
objc_test_class_flag(class, objc_class_flag_resolved))
140+
struct objc_symbol_table_abi_8 *symbols = module->symbol_table;
141+
unsigned int category_start = symbols->class_count;
142+
143+
for (unsigned short i=0 ; i<symbols->category_count; i++)
141144
{
142-
objc_send_load_message(class);
145+
struct objc_category *cat = (struct objc_category*)
146+
symbols->definitions[category_start++];
147+
Class class = (Class)objc_getClass(cat->class_name);
148+
if ((Nil != class) &&
149+
objc_test_class_flag(class, objc_class_flag_resolved))
150+
{
151+
objc_send_load_message(class);
152+
}
143153
}
144154
}
145155
}
156+
157+
158+
// Modern initialization breaks loading into two deterministic phases: class
159+
// registration and class resolution. The original GNUstep ABI implemented in Clang
160+
// emits calls to __objc_exec_class into the user static init area,
161+
// interleaving them with other static initializers and subjecting them to
162+
// the static init order fiasco. +load can therefore be called on one class
163+
// when another class's module hasn't been registered.
164+
//
165+
// On PE/COFF platforms, -fobjc-runtime=microsoft instructs Clang to emit
166+
// objc_module_abi_xxx pointers into a section in the binary. The boundaries of
167+
// that section are passed to __objc_load_modules by a linkonce/selectany
168+
// module initializer emitted into each object file.
169+
// This lets us load classes, categories and selectors from all of the modules
170+
// in a loaded image before calling +load on any of them.
171+
PUBLIC void __objc_load_modules(struct objc_module_abi_8 **start, struct objc_module_abi_8 **end)
172+
{
173+
for(struct objc_module_abi_8 **p = start; p < end; ++p)
174+
{
175+
if (*p)
176+
__objc_load_module(*p);
177+
}
178+
179+
for(struct objc_module_abi_8 **p = start; p < end; ++p)
180+
{
181+
if (*p)
182+
__objc_resolve_module(*p);
183+
}
184+
}
185+
186+
PUBLIC void __objc_exec_class(struct objc_module_abi_8 *module)
187+
{
188+
__objc_load_module(module);
189+
__objc_resolve_module(module);
190+
}

0 commit comments

Comments
 (0)