Skip to content

Conversation

@cezarbbb
Copy link
Contributor

@cezarbbb cezarbbb commented Jan 12, 2026

In order to be able to export symbols from a specified upstream C static library, I redesigned a solution that, compared to a previous PR #150335 I submitted, will not have any extra symbols leaking out.
If LTO compilation is enabled for C static libraries, --include-libs behaves the same as the default.
The test code is the same as the PR #150335.
Here are the results:

  1. cargo +include-libs rustc --release -- -L ./ -Z include-libs=libc_add.a
                 U abort@GLIBC_2.2.5
                 U bcmp@GLIBC_2.2.5
0000000000014f60 T c_add
                 U calloc@GLIBC_2.2.5
                 U close@GLIBC_2.2.5
0000000000014f70 T c_sub
                 w __cxa_finalize@GLIBC_2.2.5
                 w __cxa_thread_atexit_impl@GLIBC_2.18
                 U dl_iterate_phdr@GLIBC_2.2.5
0000000000014ee0 T downstream_add
                 U __errno_location@GLIBC_2.2.5
                 U free@GLIBC_2.2.5
                 U fstat64@GLIBC_2.33
                 U getcwd@GLIBC_2.2.5
                 U getenv@GLIBC_2.2.5
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U lseek64@GLIBC_2.2.5
                 U malloc@GLIBC_2.2.5
                 U memcpy@GLIBC_2.14
                 U memmove@GLIBC_2.2.5
                 U memset@GLIBC_2.2.5
                 U mmap64@GLIBC_2.2.5
                 U munmap@GLIBC_2.2.5
                 U open64@GLIBC_2.2.5
                 U posix_memalign@GLIBC_2.2.5
                 U pthread_key_create@GLIBC_2.34
                 U pthread_key_delete@GLIBC_2.34
                 U pthread_setspecific@GLIBC_2.34
                 U read@GLIBC_2.2.5
                 U readlink@GLIBC_2.2.5
                 U realloc@GLIBC_2.2.5
                 U realpath@GLIBC_2.3
                 U stat64@GLIBC_2.33
                 w statx@GLIBC_2.28
                 U strlen@GLIBC_2.2.5
                 U syscall@GLIBC_2.2.5
                 U __tls_get_addr@GLIBC_2.3
                 U _Unwind_Backtrace@GCC_3.3
                 U _Unwind_DeleteException@GCC_3.0
                 U _Unwind_GetDataRelBase@GCC_3.0
                 U _Unwind_GetIP@GCC_3.0
                 U _Unwind_GetIPInfo@GCC_4.2.0
                 U _Unwind_GetLanguageSpecificData@GCC_3.0
                 U _Unwind_GetRegionStart@GCC_3.0
                 U _Unwind_GetTextRelBase@GCC_3.0
                 U _Unwind_RaiseException@GCC_3.0
                 U _Unwind_Resume@GCC_3.0
                 U _Unwind_SetGR@GCC_3.0
                 U _Unwind_SetIP@GCC_3.0
                 U write@GLIBC_2.2.5
                 U writev@GLIBC_2.2.5
  1. cargo +nightly rustc --release -- -L ./
                 U abort@GLIBC_2.2.5
                 U bcmp@GLIBC_2.2.5
                 U calloc@GLIBC_2.2.5
                 U close@GLIBC_2.2.5
                 w __cxa_finalize@GLIBC_2.2.5
                 w __cxa_thread_atexit_impl@GLIBC_2.18
                 U dl_iterate_phdr@GLIBC_2.2.5
0000000000011e10 T downstream_add
                 U __errno_location@GLIBC_2.2.5
                 U free@GLIBC_2.2.5
                 U fstat64@GLIBC_2.33
                 U getcwd@GLIBC_2.2.5
                 U getenv@GLIBC_2.2.5
                 w gettid@GLIBC_2.30
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U lseek64@GLIBC_2.2.5
                 U malloc@GLIBC_2.2.5
                 U memcpy@GLIBC_2.14
                 U memmove@GLIBC_2.2.5
                 U memset@GLIBC_2.2.5
                 U mmap64@GLIBC_2.2.5
                 U munmap@GLIBC_2.2.5
                 U open64@GLIBC_2.2.5
                 U posix_memalign@GLIBC_2.2.5
                 U pthread_key_create@GLIBC_2.34
                 U pthread_key_delete@GLIBC_2.34
                 U pthread_setspecific@GLIBC_2.34
                 U read@GLIBC_2.2.5
                 U readlink@GLIBC_2.2.5
                 U realloc@GLIBC_2.2.5
                 U realpath@GLIBC_2.3
                 U stat64@GLIBC_2.33
                 w statx@GLIBC_2.28
                 U strlen@GLIBC_2.2.5
                 U syscall@GLIBC_2.2.5
                 U __tls_get_addr@GLIBC_2.3
                 U _Unwind_Backtrace@GCC_3.3
                 U _Unwind_GetDataRelBase@GCC_3.0
                 U _Unwind_GetIP@GCC_3.0
                 U _Unwind_GetIPInfo@GCC_4.2.0
                 U _Unwind_GetLanguageSpecificData@GCC_3.0
                 U _Unwind_GetRegionStart@GCC_3.0
                 U _Unwind_GetTextRelBase@GCC_3.0
                 U _Unwind_RaiseException@GCC_3.0
                 U _Unwind_Resume@GCC_3.0
                 U _Unwind_SetGR@GCC_3.0
                 U _Unwind_SetIP@GCC_3.0
                 U write@GLIBC_2.2.5
                 U writev@GLIBC_2.2.5

r? @bjorn3

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 12, 2026
@rustbot
Copy link
Collaborator

rustbot commented Jan 12, 2026

⚠️ Warning ⚠️

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

"display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
ignore_directory_in_diagnostics_source_blocks: Vec<String> = (Vec::new(), parse_string_push, [UNTRACKED],
"do not display the source code block in diagnostics for files in the directory"),
include_libs: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this -Zexport-staticlib-symbols or something like that.

let data = member.data(&*archive_data).unwrap();

// clang LTO: raw LLVM bitcode
if data.len() >= 4 && &data[0..4] == b"BC\xc0\xde" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if data.len() >= 4 && &data[0..4] == b"BC\xc0\xde" {
if data.starts_with(b"BC\xc0\xde") {

.expect("wanted an c staticlib");
for member in archive.members() {
let member = member.unwrap();
let data = member.data(&*archive_data).unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When parsing the staticlib fails we should report nice errors rather than ICE.

let symbol = symbol.unwrap();
out.push((
String::from_utf8(symbol.name().to_vec()).unwrap(),
SymbolExportKind::Text,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do need to distinguish between text and data symbols. Also on Windows I believe and on macOS I know we currently use the pre-C mangling names in exported_symbols. I think the post mangling name is fine here too for Windows, but you did need to check. On macOS however it is definitively not ok. The symbol names in the object file are prefixed with _, but the linker doesn't accept this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After testing, the symbol does have a prefix _ on macos, but not on windows. I have removed the prefix symbol (I don’t know why it was added back in the export_symbols function?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

64-bit Windows symbols do not use special mangling, but 32-bit symbols are prefixed with an additional leading underscore.

So:

int foo() { return 42; }

Would be foo symbol on 64-bit Windows, and _foo on 32-bit Windows.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And extern "stdcall" has extra mangling, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only that, all calling conventions have their own mangling: https://learn.microsoft.com/en-us/cpp/error-messages/tool-errors/name-decoration?view=msvc-170

I don't remember whether linkers can export symbols using .DEF files if the symbol doesn't exactly match calling convention. IIRC, GNU ld and LLD (not so sure about this one) can handle it, at least in some cases.

}
}
for symbol in archive.symbols().unwrap().unwrap() {
let symbol = symbol.unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to only add symbols with SymbolScope::Dynamic. Otherwise the linker will complain.

@bjorn3
Copy link
Member

bjorn3 commented Jan 12, 2026

I think this is a reasonable approach. This will need a test though.

@JayanAXHF JayanAXHF added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 12, 2026
@cezarbbb
Copy link
Contributor Author

I think this is a reasonable approach. This will need a test though.我认为这是一个合理的做法。不过这需要测试。

Working on it.

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

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants