Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

function nullptr in shared library data section #781

Open
bnoordhuis opened this issue Feb 20, 2018 · 5 comments
Open

function nullptr in shared library data section #781

bnoordhuis opened this issue Feb 20, 2018 · 5 comments
Labels
use case Describes a real use case that is difficult or impossible, but does not propose a solution.
Milestone

Comments

@bnoordhuis
Copy link
Contributor

export const init_array section(".init_array") = [1]extern fn() void { init };
extern fn init() void {}
pub fn main() void {}
$ ./build/zig --verbose-link build-lib --output lib.so lib.zig
lld -m elf_x86_64 -shared -o lib.so -dynamic-linker /lib64/ld-linux-x86-64.so.2 -soname liblib.so.0 ./zig-cache/lib.o ./zig-cache/builtin.o ./zig-cache/compiler_rt.o

$ objdump -s lib.so | grep -A1 'section .init_array'
Contents of section .init_array:
 3b7a0 00000000 00000000                    ........

Trying to load lib.so crashes with a nullptr dereference in glibc's dynamic linker. Changing the type to [1]usize and using @ptrToInt(init) isn't accepted ("unable to evaluate constant expression".)

The right address is filled in (and called) with zig --library c build-exe lib.zig.

(Aside: something like __attribute__((constructor)) would be nice.)

@bnoordhuis
Copy link
Contributor Author

It magically started working after I did a rebuild against a newer llvm version so this might be a llvm bug. The .init_array field is still 0 according to objdump but the constructor is called.

@andrewrk
Copy link
Member

What's the use case for this?

I would generally recommend against trying to have a shared library constructor. It's quite intentional that we don't have static constructors.

But if it solves a problem, let's talk about that.

@bnoordhuis
Copy link
Contributor Author

The use case is auto-registration of Node.js add-ons: https://github.com/nodejs/node/blob/v9.5.0/src/node.h#L485-L515

@andrewrk
Copy link
Member

It looks like the goal is to call node_module_register. Would it work to have some kind of initialization function in your module that calls this function? like this

@andrewrk andrewrk modified the milestones: 0.3.0, 0.4.0 Feb 25, 2018
@andrewrk andrewrk modified the milestones: 0.4.0, 0.5.0 Feb 7, 2019
@andrewrk andrewrk modified the milestones: 0.5.0, 0.6.0 Sep 20, 2019
@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Feb 10, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 10, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Nov 6, 2020
@SpexGuy SpexGuy added the use case Describes a real use case that is difficult or impossible, but does not propose a solution. label Mar 20, 2021
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
@kmeaw
Copy link

kmeaw commented Aug 13, 2022

I am also trying to export .init_array. I need a shared library which modifies the code of the application it is being loaded into, so I am not able to change the application's code - it is forced to load the library by the user passing a value into LD_PRELOAD.

pub fn init() callconv(.C) void {
    std.debug.print("{s}", .{"init()"});
}

export const init_array linksection(".init_array") = [1]fn() callconv(.C) void { init };

This code works as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
use case Describes a real use case that is difficult or impossible, but does not propose a solution.
Projects
None yet
Development

No branches or pull requests

4 participants