Skip to content

Proposal: Ability to append functions to .init_array/.fini_arrayย #23574

Open
@alexrp

Description

@alexrp

In certain specialized scenarios such as #20382, it's important to be able to designate constructor/destructor (henceforth init/fini) functions. Init functions allow running initialization code before main() in the case of a program, or when a shared library is loaded and thus before any exported functions are invoked. Conversely, fini functions allow running cleanup after main() returns in the case of a program, or when a shared library is unloaded.

To make this functionality available in Zig, I propose the following:

@appendInitFiniArray(comptime ptr: *const anyopaque, comptime options: std.builtin.InitFiniOptions) void;

// std.builtin
const InitFiniOptions = struct {
    array: enum { init, fini },
    priority: i32 = std.math.maxInt(u16),
};

This builtin function appends ptr to the designated array (.init_array/.fini_array) or the equivalent for the object format.

  • ptr must be comptime-known and resolve to a function with the signature fn () callconv(.c) void.
  • priority can be any i32, but it should be documented that priorities in the range 0 through 100 tend to be used for low-level libraries like libc. That's why C compilers default priority to 65535, which seems sensible for us to do, too.
  • It is valid to append the same ptr multiple times, even with the same priority value, though obviously not particularly sensible.
    • I see no point in attempting to prevent this in Sema as there are ways to circumvent it at link time anyway, and doing so is perfectly valid at the object format level.
  • The language reference should strongly discourage using this builtin function as a general-purpose initialization/cleanup mechanism, since doing so does not lead to particularly idiomatic Zig code. Basically, if you don't know whether you need @appendInitFiniArray(), you don't.
    • That's also part of why I chose this name, rather than the relatively innocent-sounding __attribute__((constructor))/__attribute__((destructor)) in GCC/Clang.

Example usage:

comptime {
    @appendInitFiniArray(&ctor, .{ .array = .init });
    @appendInitFiniArray(&dtor, .{ .array = .fini });
}

fn ctor() callconv(.c) void {
    // ...
}

fn dtor() callconv(.c) void {
    // ...
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementSolving this issue will likely involve adding new logic or components to the codebase.proposalThis issue suggests modifications. If it also has the "accepted" label then it is planned.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions