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

ctor not running for statically linked C library #280

Open
vsbogd opened this issue May 30, 2023 · 7 comments · Fixed by #281
Open

ctor not running for statically linked C library #280

vsbogd opened this issue May 30, 2023 · 7 comments · Fixed by #281

Comments

@vsbogd
Copy link

vsbogd commented May 30, 2023

Very similar to #27. I am opening it to ask for help in understanding what exactly doesn't work here.

I have a project with the following structure:

  • Rust library which uses ctor;
  • static C API library, which is compiled by cargo and cbindgen and depends on the Rust library with ctor

When C API library is built in release mode and linked to the executable binary then ctor is successfully called on start. If library is build in debug mode then ctor function is not included into the final binary by the linker while it is still present in a static library itself.

I use absolutely same minimal gcc options to try both debug and release:

gcc ./main.c -o ./debug -I. -L./c/target/debug -l:libhyperonc.a -lm

I have tried to repeat the issue building a minimal example from scratch but in minimal example it works correctly.

Platform: Linux x86_64
ctor version 0.2.0
Rust version 1.69.0
GCC version 12.2.1
LD version 2.40

@mmastrac
Copy link
Owner

@vsbogd Try with the new 0.2.1 and cargo +nightly --features=used_linker. It's possible this may help. If so, we just need to wait for that feature to stabilize.

@vsbogd
Copy link
Author

vsbogd commented May 30, 2023

I receive an error when try using used_linker feature:

$ cat Cargo.toml | grep ctor
ctor = "0.2.1"
$ cargo +nightly build --features=used_linker
error: Package `hyperon v0.1.2` does not have the feature `used_linker`

Do I miss something?

@mmastrac
Copy link
Owner

You'll need to add a feature to hyperon in its Cargo.toml that depends on the ctor feature:

[features]
used_linker = ["ctor/used_linker"]

@vsbogd
Copy link
Author

vsbogd commented May 30, 2023

Thanks @mmastrac . I also needed to add used_linker into both my libraries: Rust and C API in order to compile C API.

Unfortunately it doesn't help. I still can see on_load which is marked as ctor in both static libraries:

$ objdump -t ./c/target/debug/libhyperonc.a | grep on_load 
0000000000000000 l    d  .text._ZN7hyperon7on_load17hdc39ff8fb07a0999E	0000000000000000 .text._ZN7hyperon7on_load17hdc39ff8fb07a0999E
0000000000000000 l     F .text._ZN7hyperon7on_load17hdc39ff8fb07a0999E	000000000000000b _ZN7hyperon7on_load17hdc39ff8fb07a0999E
0000000000000000 g     F .text.startup	0000000000000008 _ZN7hyperon26on_load___rust_ctor___ctor26on_load___rust_ctor___ctor17hc8a7af7b1d321ffcE
0000000000000000 g     O .init_array	0000000000000008 on_load___rust_ctor___ctor

$ objdump -t ./c/target/release/libhyperonc.a | grep on_load 
0000000000000000 l    d  .gcc_except_table._ZN7hyperon26on_load___rust_ctor___ctor26on_load___rust_ctor___ctor17hf96ede0c9e76c82eE	0000000000000000 .gcc_except_table._ZN7hyperon26on_load___rust_ctor___ctor26on_load___rust_ctor___ctor17hf96ede0c9e76c82eE
0000000000000000 l       .gcc_except_table._ZN7hyperon26on_load___rust_ctor___ctor26on_load___rust_ctor___ctor17hf96ede0c9e76c82eE	0000000000000000 GCC_except_table107
0000000000000000 g     F .text.startup	000000000000005c _ZN7hyperon26on_load___rust_ctor___ctor26on_load___rust_ctor___ctor17hf96ede0c9e76c82eE
0000000000000000 g     O .init_array	0000000000000008 on_load___rust_ctor___ctor

and cannot see it in executable linked with debug library:

$ objdump -t debug | grep on_load

$ objdump -t release | grep on_load
0000000000399500 g     O .init_array	0000000000000008              on_load___rust_ctor___ctor
0000000000066450 g     F .text	000000000000005c              _ZN7hyperon26on_load___rust_ctor___ctor26on_load___rust_ctor___ctor17hf96ede0c9e76c82eE

@paukala
Copy link

paukala commented May 6, 2024

This issue is still present today. At least in my case, the issue seems to be related to the codegen-units setting, which defaults to 256 for debug and 16 for release builds. Lowering this value for debug builds (i.e. for the dev profile) solves the issue, although leading to increased build times:

# Cargo.toml
# ...

[profile.dev]
codegen-units = 16

@dbartussek
Copy link

Messing with codegen-units unfortunately doesn't seem to be a surefire way of solving this problem.
I've built a simple test project to reproduce this issue because I encountered it in my own code: https://github.com/dbartussek/Rust-CRT-XCU-issue

The only way I've found to keep the initializer around was to have a static variable that Rust thinks might be touched by the code run from main.

@mmastrac
Copy link
Owner

The only way I've found to keep the initializer around was to have a static variable that Rust thinks might be touched by the code run from main.

What pattern ended up working for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants