-
-
Notifications
You must be signed in to change notification settings - Fork 105
Description
Summary
When linking a shared library that contains object files with COMMON symbols (e.g. .gomp_critical_user_.var emitted by Clang for #pragma omp critical), wild leaves them as undefined (U) in the output instead of allocating them into BSS (B). Both lld and GNU ld correctly handle this case.
Version
wild 0.8.0 (d789d5d6716de3f665ff3da0c53d02dc65e49e3b)
Also verified the bug is present on current main (62a18be).
Reproduction
// test.c
#include <omp.h>
#include <stdio.h>
void do_work(int* data, int n) {
int error_count = 0;
#pragma omp parallel for reduction(+:error_count)
for (int i = 0; i < n; i++) {
if (data[i] < 0) {
#pragma omp critical
{
fprintf(stderr, "Error at %d\n", i);
error_count++;
}
}
}
}# Compile the object file
clang -c -fopenmp=libomp test.c -o test.o
# Confirm the COMMON symbols exist in the object file
$ nm test.o | grep gomp
0000000000000020 C .gomp_critical_user_.reduction.var
0000000000000020 C .gomp_critical_user_.var
# Link with lld — COMMON symbols correctly become BSS
$ clang -shared -fopenmp=libomp test.o -o test_lld.so -fuse-ld=lld
$ nm -D test_lld.so | grep gomp
0000000000003fb8 B .gomp_critical_user_.reduction.var
0000000000003f98 B .gomp_critical_user_.var
# Link with wild — COMMON symbols left undefined
$ clang -shared -fopenmp=libomp test.o -o test_wild.so -fuse-ld=wild
$ nm -D test_wild.so | grep gomp
U .gomp_critical_user_.reduction.var
U .gomp_critical_user_.varExpected behavior
COMMON symbols (C) in input object files should be allocated into BSS and appear as defined (B) in the output shared library, matching lld and GNU ld behavior.
Actual behavior
COMMON symbols remain undefined (U) in the output shared library, causing dlopen to fail at runtime:
undefined symbol: .gomp_critical_user_.var
Impact
Any shared library built with wild that contains OpenMP #pragma omp critical or #pragma omp ... reduction(...) (compiled with Clang) will fail to load at runtime.
Analysis
I traced this to SymbolCopyInfo::new() in libwild/src/layout.rs (around line 4384):
if sym.as_common().is_some() && !symbol_state.has_resolution() {
return None;
}This skips COMMON symbols from the symtab when they don't have a resolution flag set. The load_symbol path in RegularLayoutState correctly calls common.allocate() for COMMON symbols, and load_non_hidden_symbols sets EXPORT_DYNAMIC. However, it appears the COMMON symbol either doesn't get its resolution flags set properly by the time allocate_symtab_space runs, or SymbolCopyInfo::new() is too aggressive in filtering them out.
Notes
- GNU
ldhas a-d/-dc/-dpflag to "force common symbols to be defined", butllddoesn't need it (it always defines them). wild doesn't support this flag either. - A related fix for TLS COMMON symbols was made in commit
4f0688e(fix: put common TLS symbols into correct section #1310), but that addressed TLS symbols being placed in the wrong section, not the general case of non-TLS COMMON symbols being dropped from shared library output.