Skip to content

[LLD] unable to link a uncalled constructor function in static lib #144669

@Eternalni

Description

@Eternalni

#include

extern "C" {

attribute((constructor(101), used, retain, section(".llvm.keep,.init.250"), noinline, visibility("hidden"))) static void
_init_cpu_features() {
__builtin_cpu_init();
std::cout << "?" << std::endl;
};
}

build this function to a static lib _initd.lib, link it by cmake: "set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_CURRENT_LIST_DIR}/libs -l_initd.lib ")"
howevery, "?" not printed, and __builtin_cpu_supports always return false in main.cpp

Activity

Eternalni

Eternalni commented on Jun 18, 2025

@Eternalni
Author

call _init_cpu_features(); in function main, will print two "?". if never called it, no print

Alcaro

Alcaro commented on Jun 18, 2025

@Alcaro
Contributor

Isn't that always the behavior of static libraries? If an object file in a .a isn't needed to complete the link, then it's discarded, even if it has constructors. This allows garbage collecting unused constructors, and allowing some forms of fallback implementations, where a function is taken from the main program if it exists, but a fallback is taken from a .a if needed. (I believe that's how DllMain works.)

I agree it's unexpected and occasionally unhelpful, though. It would be useful to have a 'always include this object from the .a, even if seemingly unnecessary' switch somewhere.

Eternalni

Eternalni commented on Jun 18, 2025

@Eternalni
Author

init.lib:

[[gnu::used, gnu::retain, gnu::constructor(101)]]
void _init_cpu_features(){
__builtin_cpu_init();
std::cout << "init" << std::endl;
}

void lldtest() { std::cout << "test" << std::endl; }

main.cpp:

int main(int, char **){
//lldtest();
__builtin_cpu_supports("avx"); // false
}

if lldtest() called, then _init_cpu_features will run before main(), else, _init_cpu_features dont work.
does the linker discard the entire static library if no symboles ars explicitly referenced in it?

Eternalni

Eternalni commented on Jun 18, 2025

@Eternalni
Author

Isn't that always the behavior of static libraries? If an object file in a .a isn't needed to complete the link, then it's discarded, even if it has constructors. This allows garbage collecting unused constructors, and allowing some forms of fallback implementations, where a function is taken from the main program if it exists, but a fallback is taken from a .a if needed. (I believe that's how DllMain works.)

I agree it's unexpected and occasionally unhelpful, though. It would be useful to have a 'always include this object from the .a, even if seemingly unnecessary' switch somewhere.

Thanks, i roughly understand now, the linker tries to discard seemingly unused code.
But according to my latest test: when other symbols unrelated to this constructor are explicitly called in the .a file, the constructor is not discarded and executes normally. perhaps this involves more than just garbage collection logic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @Alcaro@llvmbot@Eternalni

        Issue actions

          [LLD] unable to link a uncalled constructor function in static lib · Issue #144669 · llvm/llvm-project