# MulleObjC Startup Code Internal Mechanism: Constructor-Driven Runtime Initialization

> Explore the MulleObjC startup mechanism. Discover how compiler constructors enable constructor-driven runtime initialization before main, registering symbols and setting up the environment.

- Repository: [mulle-objc/mulleobjc-startup](https://github.com/mulle-objc/mulleobjc-startup)
- Tags: internals
- Published: 2026-03-07

---

**The MulleObjC startup code uses a compiler constructor attribute to execute the static `bang()` function before `main()`, which registers the universe symbol, copies the default configuration, and invokes `MulleObjCBang` to initialize the runtime, class tables, and exception handling automatically.**

The **mulle-objc/mulleobjc-startup** repository contains the minimal bootstrap layer that brings the MulleObjC runtime to life. Understanding the MulleObjC startup code internal mechanism reveals how the Objective-C environment becomes fully operational before your `main()` function executes, without requiring explicit initialization calls.

## The Three-Phase Bootstrap Process in MulleObjC-startup.m

The core implementation lives in `src/MulleObjC-startup.m`, where the static function `bang()` orchestrates three distinct initialization phases that prepare the runtime for object allocation and message passing.

### Registering the Universal Symbol

First, the startup module exports a registration symbol so the dynamic loader can locate the runtime entry point. The preprocessor macro `MULLE_OBJC_DEFINE__register_mulle_objc_universe` generates the `register_mulle_objc_universe` symbol at line 41 of `src/MulleObjC-startup.m`. This symbol serves as the anchor point for the universe—the central data structure that holds all class, selector, and method tables.

### Building the Universe Configuration

Next, the code copies the **global default universe configuration** into a local structure. The function `mulle_objc_global_get_default_universeconfiguration()` provides the template, which is stored in a local `struct _mulle_objc_universeconfiguration` between lines 66 and 71. This configuration includes allocator settings and runtime behavior flags that can be overridden before initialization proceeds.

### Initializing via MulleObjCBang

Finally, control passes to `MulleObjCBang`, defined in the private header `mulle-objc-startup-private.inc`. This helper function receives the universe pointer, allocator, and configuration struct, then performs the heavy lifting: registering the universe in the global variable `mulle_objc_universe`, loading the class table, setting up the autorelease pool, and executing any additional constructors compiled with `__attribute__((constructor))`.

## The Role of mulle-objc-startup-private.inc

The `mulle-objc-startup-private.inc` header is an internal component shipped with the main MulleObjC library (not this repository). It contains the compiler-generated constructor that automatically invokes `bang()` before program entry. This header also defines platform-specific symbols for dllexport/dllimport handling and ensures the startup sequence runs without manual intervention.

```objc
#include <MulleObjC/mulle-objc-startup-private.inc>

```

When the dynamic loader resolves this include, the constructor attribute ensures the runtime is ready for object allocation and message passing immediately upon program start.

## Versioning and ABI Compatibility

The startup module encodes its version as a compile-time constant for binary compatibility checks, particularly when loading plug-ins:

```c
#define MULLE_OBJC__STARTUP_VERSION  ((0UL << 20) | (20 << 8) | 7)

```

This 32-bit value packs major, minor, and patch components (0.20.7 in this case), allowing the runtime to verify that loaded libraries match the startup code's ABI expectations.

## Runtime Integration Points

The MulleObjC startup code internal mechanism wires together several critical subsystems before user code executes:

- **Universe Management**: The `struct _mulle_objc_universe` becomes accessible through the global pointer `mulle_objc_universe`, enabling constant-time lookups for class and selector tables.
- **Memory Allocation**: While the default configuration uses standard `malloc`-based allocators, the `struct _mulle_objc_universeconfiguration` allows embedding custom allocators for specialized memory management.
- **Exception Handling**: The startup module pulls in private exception-handler tables from [`mulle-objc-exceptionhandlertable-private.h`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/mulle-objc-exceptionhandlertable-private.h), mapping Objective-C `@try/@catch` blocks to C-level handlers immediately.

## Practical Usage Example

Because initialization occurs automatically, you can write standard Objective-C without explicit setup calls:

```c
/* main.c */
#import <MulleObjC/MulleObjC.h>

@interface Greeter : NSObject
- (void) greet;
@end

@implementation Greeter
- (void) greet { printf("Hello from MulleObjC!\n"); }
@end

int main(void)
{
    // Runtime is already initialized by MulleObjC-startup
    Greeter *g = [Greeter new];
    [g greet];
    [g release];
    return 0;
}

```

Compile and link using the project's build tool:

```bash
mulle-sde -project MulleObjC-startup -target example \
    -c main.c \
    -link -framework MulleObjC

```

Execution proceeds without manual runtime configuration because the constructor in `mulle-objc-startup-private.inc` has already executed `bang()`.

## Summary

- The **MulleObjC startup code** relies on compiler constructors to execute before `main()` entry.
- The `bang()` function in `src/MulleObjC-startup.m` handles symbol registration, configuration copying, and `MulleObjCBang` invocation.
- `MulleObjCBang` initializes the universe, class tables, autorelease pools, and exception handling.
- Version constant `MULLE_OBJC__STARTUP_VERSION` ensures ABI compatibility across plug-in boundaries.
- No manual initialization is required; the runtime is fully operational when user code begins.

## Frequently Asked Questions

### What triggers MulleObjC startup code to run before main()?

The execution is driven by a compiler-generated constructor defined in `mulle-objc-startup-private.inc`. This constructor calls the static `bang()` function automatically during dynamic loading, ensuring the runtime initializes before program entry without explicit user code.

### How does MulleObjCBang differ from the bang() function?

The `bang()` function in `src/MulleObjC-startup.m` is specific to this repository and handles platform-specific symbol registration and configuration setup. `MulleObjCBang`, defined in the private include, is the generic runtime initializer that actually creates the `struct _mulle_objc_universe`, loads class tables, and sets up memory management and exception handling.

### Can I customize the allocator used during MulleObjC startup?

Yes. The `mulle_objc_global_get_default_universeconfiguration()` function provides default settings, but you can modify the allocator field in `struct _mulle_objc_universeconfiguration` before `MulleObjCBang` executes. This allows embedding custom memory allocators or pools that persist throughout the program lifetime.

### Where is the startup version defined and why does it matter?

The version is defined as `MULLE_OBJC__STARTUP_VERSION` in the startup source, currently encoding version 0.20.7. This matters for ABI compatibility verification when dynamically loading plug-ins or frameworks, ensuring that external code links against a compatible runtime initialization sequence.