Skip to content

linksection("..") not respected in debug build #24330

@AxlLind

Description

@AxlLind

Zig Version

0.15.1

Steps to Reproduce and Observed Behavior

I am trying to build a shared object with a constructor function. In C/GCC you would use __attribute__((constructor)) here. I could not find an equivalent in Zig so I am populating the .init_array manually instead.

This seems to work fine in release but in a debug build linksection is not respected.

Minimal example

const std = @import("std");

fn constructor() callconv(.c) void {
    std.debug.print("hello from constructor\n", .{});
}

export const constructors: [1]*const fn () callconv(.c) void linksection(".init_array") = .{&constructor};

// --- build.zig ---
const std = @import("std");

pub fn build(b: *std.Build) void {
    const lib = b.addSharedLibrary(.{
        .name = "test",
        .root_module = b.createModule(.{
            .root_source_file = b.path("src/main.zig"),
            .target = b.standardTargetOptions(.{}),
            .optimize = b.standardOptimizeOption(.{}),
        }),
    });
    b.installArtifact(lib);
}

Steps to reproduce

In release this works as expected:

$ zig build --release=fast
$ readelf --sections zig-out/lib/libtest.so | rg .init_array
  [13] .init_array       INIT_ARRAY       0000000000002990  00000990
$ LD_PRELOAD=zig-out/lib/libtest.so sleep 1
hello from constructor

However, in a debug build linksection is seemingly ignored:

$ zig build
$ readelf --sections zig-out/lib/libtest.so | rg .init_array
# nothing
$ LD_PRELOAD=zig-out/lib/libtest.so sleep 1
# nothing

The constructors symbol instead ends up in .data.rel.ro:

$ readelf --symbols zig-out/lib/libtest.so | rg constructors
    24: 00000000001a3bd0     8 OBJECT  GLOBAL DEFAULT   18 constructors
$ readelf --sections zig-out/lib/libtest.so | rg '\[18\]'
  [18] .data.rel.ro      PROGBITS         000000000017c830  001a3830

Expected Behavior

I expected the constructors symbol to end up in the .init_array section even in a debug build and for the behavior to be the same between a debug and release build.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions