Staticlib rename internal symbols#156950
Conversation
|
btw if this underwent a lot of changes and needs re-testing, I'm up for it (I compile Rust to 6 targets). |
This comment has been minimized.
This comment has been minimized.
Functionally, there shouldn't be any changes; it's mostly more "Rusty" modifications. After #155338 is landed, I will rebase the current PR, and you can test it after that. |
… r=petrochenkov Staticlib hide internal symbols According to issue rust-lang#104707, when building a staticlib, all Rust internal symbols — mangled symbols, `#[rustc_std_internal_symbol]` items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only `#[no_mangle]` symbols via a linker version script. `-Zstaticlib-hide-internal-symbols` directly post-processes ELF object files in the archive: parsing the `SHT_SYMTAB` sections and setting `STV_HIDDEN` visibility on any `GLOBAL/WEAK` defined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead. Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect. **Update**: The rename counterpart (`-Zstaticlib-rename-internal-symbols`) is in rust-lang#156950. The test code are as follows: 1.a std rust staticlib: ```rust use std::collections::HashMap; use std::panic::{catch_unwind, AssertUnwindSafe}; #[no_mangle] pub extern "C" fn my_add(a: i32, b: i32) -> i32 { a + b } #[no_mangle] pub extern "C" fn my_hash_lookup(key: u64) -> u64 { let mut map = HashMap::new(); for i in 0..100u64 { map.insert(i, i.wrapping_mul(2654435761)); } *map.get(&key).unwrap_or(&0) } pub fn internal_reverse(s: &str) -> String { s.chars().rev().collect() } #[no_mangle] pub extern "C" fn my_format_number(n: i32) -> i32 { let s = format!("number: {}", n); s.len() as i32 } #[no_mangle] pub extern "C" fn my_safe_div(a: i32, b: i32) -> i32 { match catch_unwind(AssertUnwindSafe(|| { if b == 0 { panic!("division by zero!"); } a / b })) { Ok(result) => result, Err(_) => -1, } } #[no_mangle] pub extern "C" fn my_uncaught_panic() { panic!("uncaught panic across FFI"); } ``` 1.b downstream c program: ```c extern int my_add(int a, int b); extern unsigned long my_hash_lookup(unsigned long key); extern int my_format_number(int n); extern int my_safe_div(int a, int b); extern void my_uncaught_panic(void); int main() { int failures = 0; if (my_add(10, 20) != 30) failures++; if (my_hash_lookup(5) != 5UL * 2654435761UL) failures++; if (my_format_number(42) != 10) failures++; if (my_safe_div(100, 5) != 20) failures++; if (my_safe_div(100, 0) != -1) failures++; pid_t pid = fork(); if (pid == 0) { alarm(5); my_uncaught_panic(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 1.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin 616K 584K 33K (5%) 246 5 241 lto_fat 525K 525K 0 (0%) 6 5 1 opt_s 1.7M 1.5M 204K (12%) 1735 5 1730 opt_z 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin_z 602K 570K 32K (5%) 246 5 241 lto_fat_z 514K 514K 0 (0%) 6 5 1 full 514K 514K 0 (0%) 6 5 1 ``` 1.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin 616K 599K 18K (2%) 246 5 241 lto_fat 525K 535K -1% (-1%) 6 5 1 opt_s 1.7M 1.5M 162K (9%) 1735 5 1730 opt_z 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin_z 602K 585K 18K (2%) 246 5 241 lto_fat_z 514K 524K -1% (-1%) 6 5 1 full 514K 523K -1% (-1%) 6 5 1 ``` 2.a no_std rust staticlib ```rust #![no_std] #![feature(core_intrinsics)] use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn embedded_add(a: i32, b: i32) -> i32 { a.wrapping_add(b) } #[no_mangle] pub extern "C" fn embedded_checksum(data: *const u8, len: usize) -> u8 { if data.is_null() { return 0; } let slice = unsafe { core::slice::from_raw_parts(data, len) }; let mut sum: u8 = 0; for &byte in slice { sum = sum.wrapping_add(byte); } sum } fn internal_helper() -> i32 { 42 } #[no_mangle] pub extern "C" fn call_internal() -> i32 { internal_helper() } #[no_mangle] pub extern "C" fn embedded_trigger_abort() { core::intrinsics::abort(); } ``` 2.b downstream c program ```c extern int embedded_add(int a, int b); extern unsigned char embedded_checksum(const unsigned char *data, unsigned long len); extern int call_internal(void); extern void embedded_trigger_abort(void); int main() { int failures = 0; if (embedded_add(10, 20) != 30) failures++; unsigned char data[] = {1, 2, 3}; if (embedded_checksum(data, 3) != 6) failures++; if (call_internal() != 42) failures++; pid_t pid = fork(); if (pid == 0) { embedded_trigger_abort(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 2.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 429K 56K (11%) 490 4 486 lto_thin 180K 180K 0 (0%) 4 4 0 lto_fat 179K 179K 0 (0%) 4 4 0 opt_s 485K 429K 56K (11%) 490 4 486 opt_z 485K 429K 56K (11%) 490 4 486 lto_thin_z 180K 180K 0 (0%) 4 4 0 lto_fat_z 179K 179K 0 (0%) 4 4 0 full 179K 179K 0 (0%) 4 4 0 ``` 2.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 447K 39K (7%) 490 4 486 lto_thin 180K 189K -5% (-5%) 4 4 0 lto_fat 179K 189K -5% (-5%) 4 4 0 opt_s 485K 448K 38K (7%) 490 4 486 opt_z 485K 448K 38K (7%) 490 4 486 lto_thin_z 180K 189K -5% (-5%) 4 4 0 lto_fat_z 179K 189K -5% (-5%) 4 4 0 full 179K 189K -5% (-5%) 4 4 0 ``` Test results show that this compiler option is beneficial for scenarios where LTO cannot be enabled. r? @bjorn3 @petrochenkov
… r=petrochenkov Staticlib hide internal symbols According to issue rust-lang#104707, when building a staticlib, all Rust internal symbols — mangled symbols, `#[rustc_std_internal_symbol]` items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only `#[no_mangle]` symbols via a linker version script. `-Zstaticlib-hide-internal-symbols` directly post-processes ELF object files in the archive: parsing the `SHT_SYMTAB` sections and setting `STV_HIDDEN` visibility on any `GLOBAL/WEAK` defined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead. Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect. **Update**: The rename counterpart (`-Zstaticlib-rename-internal-symbols`) is in rust-lang#156950. The test code are as follows: 1.a std rust staticlib: ```rust use std::collections::HashMap; use std::panic::{catch_unwind, AssertUnwindSafe}; #[no_mangle] pub extern "C" fn my_add(a: i32, b: i32) -> i32 { a + b } #[no_mangle] pub extern "C" fn my_hash_lookup(key: u64) -> u64 { let mut map = HashMap::new(); for i in 0..100u64 { map.insert(i, i.wrapping_mul(2654435761)); } *map.get(&key).unwrap_or(&0) } pub fn internal_reverse(s: &str) -> String { s.chars().rev().collect() } #[no_mangle] pub extern "C" fn my_format_number(n: i32) -> i32 { let s = format!("number: {}", n); s.len() as i32 } #[no_mangle] pub extern "C" fn my_safe_div(a: i32, b: i32) -> i32 { match catch_unwind(AssertUnwindSafe(|| { if b == 0 { panic!("division by zero!"); } a / b })) { Ok(result) => result, Err(_) => -1, } } #[no_mangle] pub extern "C" fn my_uncaught_panic() { panic!("uncaught panic across FFI"); } ``` 1.b downstream c program: ```c extern int my_add(int a, int b); extern unsigned long my_hash_lookup(unsigned long key); extern int my_format_number(int n); extern int my_safe_div(int a, int b); extern void my_uncaught_panic(void); int main() { int failures = 0; if (my_add(10, 20) != 30) failures++; if (my_hash_lookup(5) != 5UL * 2654435761UL) failures++; if (my_format_number(42) != 10) failures++; if (my_safe_div(100, 5) != 20) failures++; if (my_safe_div(100, 0) != -1) failures++; pid_t pid = fork(); if (pid == 0) { alarm(5); my_uncaught_panic(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 1.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin 616K 584K 33K (5%) 246 5 241 lto_fat 525K 525K 0 (0%) 6 5 1 opt_s 1.7M 1.5M 204K (12%) 1735 5 1730 opt_z 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin_z 602K 570K 32K (5%) 246 5 241 lto_fat_z 514K 514K 0 (0%) 6 5 1 full 514K 514K 0 (0%) 6 5 1 ``` 1.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin 616K 599K 18K (2%) 246 5 241 lto_fat 525K 535K -1% (-1%) 6 5 1 opt_s 1.7M 1.5M 162K (9%) 1735 5 1730 opt_z 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin_z 602K 585K 18K (2%) 246 5 241 lto_fat_z 514K 524K -1% (-1%) 6 5 1 full 514K 523K -1% (-1%) 6 5 1 ``` 2.a no_std rust staticlib ```rust #![no_std] #![feature(core_intrinsics)] use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn embedded_add(a: i32, b: i32) -> i32 { a.wrapping_add(b) } #[no_mangle] pub extern "C" fn embedded_checksum(data: *const u8, len: usize) -> u8 { if data.is_null() { return 0; } let slice = unsafe { core::slice::from_raw_parts(data, len) }; let mut sum: u8 = 0; for &byte in slice { sum = sum.wrapping_add(byte); } sum } fn internal_helper() -> i32 { 42 } #[no_mangle] pub extern "C" fn call_internal() -> i32 { internal_helper() } #[no_mangle] pub extern "C" fn embedded_trigger_abort() { core::intrinsics::abort(); } ``` 2.b downstream c program ```c extern int embedded_add(int a, int b); extern unsigned char embedded_checksum(const unsigned char *data, unsigned long len); extern int call_internal(void); extern void embedded_trigger_abort(void); int main() { int failures = 0; if (embedded_add(10, 20) != 30) failures++; unsigned char data[] = {1, 2, 3}; if (embedded_checksum(data, 3) != 6) failures++; if (call_internal() != 42) failures++; pid_t pid = fork(); if (pid == 0) { embedded_trigger_abort(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 2.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 429K 56K (11%) 490 4 486 lto_thin 180K 180K 0 (0%) 4 4 0 lto_fat 179K 179K 0 (0%) 4 4 0 opt_s 485K 429K 56K (11%) 490 4 486 opt_z 485K 429K 56K (11%) 490 4 486 lto_thin_z 180K 180K 0 (0%) 4 4 0 lto_fat_z 179K 179K 0 (0%) 4 4 0 full 179K 179K 0 (0%) 4 4 0 ``` 2.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 447K 39K (7%) 490 4 486 lto_thin 180K 189K -5% (-5%) 4 4 0 lto_fat 179K 189K -5% (-5%) 4 4 0 opt_s 485K 448K 38K (7%) 490 4 486 opt_z 485K 448K 38K (7%) 490 4 486 lto_thin_z 180K 189K -5% (-5%) 4 4 0 lto_fat_z 179K 189K -5% (-5%) 4 4 0 full 179K 189K -5% (-5%) 4 4 0 ``` Test results show that this compiler option is beneficial for scenarios where LTO cannot be enabled. r? @bjorn3 @petrochenkov
… r=petrochenkov Staticlib hide internal symbols According to issue rust-lang#104707, when building a staticlib, all Rust internal symbols — mangled symbols, `#[rustc_std_internal_symbol]` items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only `#[no_mangle]` symbols via a linker version script. `-Zstaticlib-hide-internal-symbols` directly post-processes ELF object files in the archive: parsing the `SHT_SYMTAB` sections and setting `STV_HIDDEN` visibility on any `GLOBAL/WEAK` defined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead. Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect. **Update**: The rename counterpart (`-Zstaticlib-rename-internal-symbols`) is in rust-lang#156950. The test code are as follows: 1.a std rust staticlib: ```rust use std::collections::HashMap; use std::panic::{catch_unwind, AssertUnwindSafe}; #[no_mangle] pub extern "C" fn my_add(a: i32, b: i32) -> i32 { a + b } #[no_mangle] pub extern "C" fn my_hash_lookup(key: u64) -> u64 { let mut map = HashMap::new(); for i in 0..100u64 { map.insert(i, i.wrapping_mul(2654435761)); } *map.get(&key).unwrap_or(&0) } pub fn internal_reverse(s: &str) -> String { s.chars().rev().collect() } #[no_mangle] pub extern "C" fn my_format_number(n: i32) -> i32 { let s = format!("number: {}", n); s.len() as i32 } #[no_mangle] pub extern "C" fn my_safe_div(a: i32, b: i32) -> i32 { match catch_unwind(AssertUnwindSafe(|| { if b == 0 { panic!("division by zero!"); } a / b })) { Ok(result) => result, Err(_) => -1, } } #[no_mangle] pub extern "C" fn my_uncaught_panic() { panic!("uncaught panic across FFI"); } ``` 1.b downstream c program: ```c extern int my_add(int a, int b); extern unsigned long my_hash_lookup(unsigned long key); extern int my_format_number(int n); extern int my_safe_div(int a, int b); extern void my_uncaught_panic(void); int main() { int failures = 0; if (my_add(10, 20) != 30) failures++; if (my_hash_lookup(5) != 5UL * 2654435761UL) failures++; if (my_format_number(42) != 10) failures++; if (my_safe_div(100, 5) != 20) failures++; if (my_safe_div(100, 0) != -1) failures++; pid_t pid = fork(); if (pid == 0) { alarm(5); my_uncaught_panic(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 1.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin 616K 584K 33K (5%) 246 5 241 lto_fat 525K 525K 0 (0%) 6 5 1 opt_s 1.7M 1.5M 204K (12%) 1735 5 1730 opt_z 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin_z 602K 570K 32K (5%) 246 5 241 lto_fat_z 514K 514K 0 (0%) 6 5 1 full 514K 514K 0 (0%) 6 5 1 ``` 1.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin 616K 599K 18K (2%) 246 5 241 lto_fat 525K 535K -1% (-1%) 6 5 1 opt_s 1.7M 1.5M 162K (9%) 1735 5 1730 opt_z 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin_z 602K 585K 18K (2%) 246 5 241 lto_fat_z 514K 524K -1% (-1%) 6 5 1 full 514K 523K -1% (-1%) 6 5 1 ``` 2.a no_std rust staticlib ```rust #![no_std] #![feature(core_intrinsics)] use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn embedded_add(a: i32, b: i32) -> i32 { a.wrapping_add(b) } #[no_mangle] pub extern "C" fn embedded_checksum(data: *const u8, len: usize) -> u8 { if data.is_null() { return 0; } let slice = unsafe { core::slice::from_raw_parts(data, len) }; let mut sum: u8 = 0; for &byte in slice { sum = sum.wrapping_add(byte); } sum } fn internal_helper() -> i32 { 42 } #[no_mangle] pub extern "C" fn call_internal() -> i32 { internal_helper() } #[no_mangle] pub extern "C" fn embedded_trigger_abort() { core::intrinsics::abort(); } ``` 2.b downstream c program ```c extern int embedded_add(int a, int b); extern unsigned char embedded_checksum(const unsigned char *data, unsigned long len); extern int call_internal(void); extern void embedded_trigger_abort(void); int main() { int failures = 0; if (embedded_add(10, 20) != 30) failures++; unsigned char data[] = {1, 2, 3}; if (embedded_checksum(data, 3) != 6) failures++; if (call_internal() != 42) failures++; pid_t pid = fork(); if (pid == 0) { embedded_trigger_abort(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 2.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 429K 56K (11%) 490 4 486 lto_thin 180K 180K 0 (0%) 4 4 0 lto_fat 179K 179K 0 (0%) 4 4 0 opt_s 485K 429K 56K (11%) 490 4 486 opt_z 485K 429K 56K (11%) 490 4 486 lto_thin_z 180K 180K 0 (0%) 4 4 0 lto_fat_z 179K 179K 0 (0%) 4 4 0 full 179K 179K 0 (0%) 4 4 0 ``` 2.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 447K 39K (7%) 490 4 486 lto_thin 180K 189K -5% (-5%) 4 4 0 lto_fat 179K 189K -5% (-5%) 4 4 0 opt_s 485K 448K 38K (7%) 490 4 486 opt_z 485K 448K 38K (7%) 490 4 486 lto_thin_z 180K 189K -5% (-5%) 4 4 0 lto_fat_z 179K 189K -5% (-5%) 4 4 0 full 179K 189K -5% (-5%) 4 4 0 ``` Test results show that this compiler option is beneficial for scenarios where LTO cannot be enabled. r? @bjorn3 @petrochenkov
… r=petrochenkov Staticlib hide internal symbols According to issue rust-lang#104707, when building a staticlib, all Rust internal symbols — mangled symbols, `#[rustc_std_internal_symbol]` items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only `#[no_mangle]` symbols via a linker version script. `-Zstaticlib-hide-internal-symbols` directly post-processes ELF object files in the archive: parsing the `SHT_SYMTAB` sections and setting `STV_HIDDEN` visibility on any `GLOBAL/WEAK` defined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead. Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect. **Update**: The rename counterpart (`-Zstaticlib-rename-internal-symbols`) is in rust-lang#156950. The test code are as follows: 1.a std rust staticlib: ```rust use std::collections::HashMap; use std::panic::{catch_unwind, AssertUnwindSafe}; #[no_mangle] pub extern "C" fn my_add(a: i32, b: i32) -> i32 { a + b } #[no_mangle] pub extern "C" fn my_hash_lookup(key: u64) -> u64 { let mut map = HashMap::new(); for i in 0..100u64 { map.insert(i, i.wrapping_mul(2654435761)); } *map.get(&key).unwrap_or(&0) } pub fn internal_reverse(s: &str) -> String { s.chars().rev().collect() } #[no_mangle] pub extern "C" fn my_format_number(n: i32) -> i32 { let s = format!("number: {}", n); s.len() as i32 } #[no_mangle] pub extern "C" fn my_safe_div(a: i32, b: i32) -> i32 { match catch_unwind(AssertUnwindSafe(|| { if b == 0 { panic!("division by zero!"); } a / b })) { Ok(result) => result, Err(_) => -1, } } #[no_mangle] pub extern "C" fn my_uncaught_panic() { panic!("uncaught panic across FFI"); } ``` 1.b downstream c program: ```c extern int my_add(int a, int b); extern unsigned long my_hash_lookup(unsigned long key); extern int my_format_number(int n); extern int my_safe_div(int a, int b); extern void my_uncaught_panic(void); int main() { int failures = 0; if (my_add(10, 20) != 30) failures++; if (my_hash_lookup(5) != 5UL * 2654435761UL) failures++; if (my_format_number(42) != 10) failures++; if (my_safe_div(100, 5) != 20) failures++; if (my_safe_div(100, 0) != -1) failures++; pid_t pid = fork(); if (pid == 0) { alarm(5); my_uncaught_panic(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 1.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin 616K 584K 33K (5%) 246 5 241 lto_fat 525K 525K 0 (0%) 6 5 1 opt_s 1.7M 1.5M 204K (12%) 1735 5 1730 opt_z 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin_z 602K 570K 32K (5%) 246 5 241 lto_fat_z 514K 514K 0 (0%) 6 5 1 full 514K 514K 0 (0%) 6 5 1 ``` 1.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin 616K 599K 18K (2%) 246 5 241 lto_fat 525K 535K -1% (-1%) 6 5 1 opt_s 1.7M 1.5M 162K (9%) 1735 5 1730 opt_z 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin_z 602K 585K 18K (2%) 246 5 241 lto_fat_z 514K 524K -1% (-1%) 6 5 1 full 514K 523K -1% (-1%) 6 5 1 ``` 2.a no_std rust staticlib ```rust #![no_std] #![feature(core_intrinsics)] use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn embedded_add(a: i32, b: i32) -> i32 { a.wrapping_add(b) } #[no_mangle] pub extern "C" fn embedded_checksum(data: *const u8, len: usize) -> u8 { if data.is_null() { return 0; } let slice = unsafe { core::slice::from_raw_parts(data, len) }; let mut sum: u8 = 0; for &byte in slice { sum = sum.wrapping_add(byte); } sum } fn internal_helper() -> i32 { 42 } #[no_mangle] pub extern "C" fn call_internal() -> i32 { internal_helper() } #[no_mangle] pub extern "C" fn embedded_trigger_abort() { core::intrinsics::abort(); } ``` 2.b downstream c program ```c extern int embedded_add(int a, int b); extern unsigned char embedded_checksum(const unsigned char *data, unsigned long len); extern int call_internal(void); extern void embedded_trigger_abort(void); int main() { int failures = 0; if (embedded_add(10, 20) != 30) failures++; unsigned char data[] = {1, 2, 3}; if (embedded_checksum(data, 3) != 6) failures++; if (call_internal() != 42) failures++; pid_t pid = fork(); if (pid == 0) { embedded_trigger_abort(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 2.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 429K 56K (11%) 490 4 486 lto_thin 180K 180K 0 (0%) 4 4 0 lto_fat 179K 179K 0 (0%) 4 4 0 opt_s 485K 429K 56K (11%) 490 4 486 opt_z 485K 429K 56K (11%) 490 4 486 lto_thin_z 180K 180K 0 (0%) 4 4 0 lto_fat_z 179K 179K 0 (0%) 4 4 0 full 179K 179K 0 (0%) 4 4 0 ``` 2.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 447K 39K (7%) 490 4 486 lto_thin 180K 189K -5% (-5%) 4 4 0 lto_fat 179K 189K -5% (-5%) 4 4 0 opt_s 485K 448K 38K (7%) 490 4 486 opt_z 485K 448K 38K (7%) 490 4 486 lto_thin_z 180K 189K -5% (-5%) 4 4 0 lto_fat_z 179K 189K -5% (-5%) 4 4 0 full 179K 189K -5% (-5%) 4 4 0 ``` Test results show that this compiler option is beneficial for scenarios where LTO cannot be enabled. r? @bjorn3 @petrochenkov
Rollup merge of #155338 - cezarbbb:staticlib-symbol-hygiene, r=petrochenkov Staticlib hide internal symbols According to issue #104707, when building a staticlib, all Rust internal symbols — mangled symbols, `#[rustc_std_internal_symbol]` items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only `#[no_mangle]` symbols via a linker version script. `-Zstaticlib-hide-internal-symbols` directly post-processes ELF object files in the archive: parsing the `SHT_SYMTAB` sections and setting `STV_HIDDEN` visibility on any `GLOBAL/WEAK` defined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead. Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect. **Update**: The rename counterpart (`-Zstaticlib-rename-internal-symbols`) is in #156950. The test code are as follows: 1.a std rust staticlib: ```rust use std::collections::HashMap; use std::panic::{catch_unwind, AssertUnwindSafe}; #[no_mangle] pub extern "C" fn my_add(a: i32, b: i32) -> i32 { a + b } #[no_mangle] pub extern "C" fn my_hash_lookup(key: u64) -> u64 { let mut map = HashMap::new(); for i in 0..100u64 { map.insert(i, i.wrapping_mul(2654435761)); } *map.get(&key).unwrap_or(&0) } pub fn internal_reverse(s: &str) -> String { s.chars().rev().collect() } #[no_mangle] pub extern "C" fn my_format_number(n: i32) -> i32 { let s = format!("number: {}", n); s.len() as i32 } #[no_mangle] pub extern "C" fn my_safe_div(a: i32, b: i32) -> i32 { match catch_unwind(AssertUnwindSafe(|| { if b == 0 { panic!("division by zero!"); } a / b })) { Ok(result) => result, Err(_) => -1, } } #[no_mangle] pub extern "C" fn my_uncaught_panic() { panic!("uncaught panic across FFI"); } ``` 1.b downstream c program: ```c extern int my_add(int a, int b); extern unsigned long my_hash_lookup(unsigned long key); extern int my_format_number(int n); extern int my_safe_div(int a, int b); extern void my_uncaught_panic(void); int main() { int failures = 0; if (my_add(10, 20) != 30) failures++; if (my_hash_lookup(5) != 5UL * 2654435761UL) failures++; if (my_format_number(42) != 10) failures++; if (my_safe_div(100, 5) != 20) failures++; if (my_safe_div(100, 0) != -1) failures++; pid_t pid = fork(); if (pid == 0) { alarm(5); my_uncaught_panic(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 1.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin 616K 584K 33K (5%) 246 5 241 lto_fat 525K 525K 0 (0%) 6 5 1 opt_s 1.7M 1.5M 204K (12%) 1735 5 1730 opt_z 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin_z 602K 570K 32K (5%) 246 5 241 lto_fat_z 514K 514K 0 (0%) 6 5 1 full 514K 514K 0 (0%) 6 5 1 ``` 1.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin 616K 599K 18K (2%) 246 5 241 lto_fat 525K 535K -1% (-1%) 6 5 1 opt_s 1.7M 1.5M 162K (9%) 1735 5 1730 opt_z 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin_z 602K 585K 18K (2%) 246 5 241 lto_fat_z 514K 524K -1% (-1%) 6 5 1 full 514K 523K -1% (-1%) 6 5 1 ``` 2.a no_std rust staticlib ```rust #![no_std] #![feature(core_intrinsics)] use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn embedded_add(a: i32, b: i32) -> i32 { a.wrapping_add(b) } #[no_mangle] pub extern "C" fn embedded_checksum(data: *const u8, len: usize) -> u8 { if data.is_null() { return 0; } let slice = unsafe { core::slice::from_raw_parts(data, len) }; let mut sum: u8 = 0; for &byte in slice { sum = sum.wrapping_add(byte); } sum } fn internal_helper() -> i32 { 42 } #[no_mangle] pub extern "C" fn call_internal() -> i32 { internal_helper() } #[no_mangle] pub extern "C" fn embedded_trigger_abort() { core::intrinsics::abort(); } ``` 2.b downstream c program ```c extern int embedded_add(int a, int b); extern unsigned char embedded_checksum(const unsigned char *data, unsigned long len); extern int call_internal(void); extern void embedded_trigger_abort(void); int main() { int failures = 0; if (embedded_add(10, 20) != 30) failures++; unsigned char data[] = {1, 2, 3}; if (embedded_checksum(data, 3) != 6) failures++; if (call_internal() != 42) failures++; pid_t pid = fork(); if (pid == 0) { embedded_trigger_abort(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 2.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 429K 56K (11%) 490 4 486 lto_thin 180K 180K 0 (0%) 4 4 0 lto_fat 179K 179K 0 (0%) 4 4 0 opt_s 485K 429K 56K (11%) 490 4 486 opt_z 485K 429K 56K (11%) 490 4 486 lto_thin_z 180K 180K 0 (0%) 4 4 0 lto_fat_z 179K 179K 0 (0%) 4 4 0 full 179K 179K 0 (0%) 4 4 0 ``` 2.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 447K 39K (7%) 490 4 486 lto_thin 180K 189K -5% (-5%) 4 4 0 lto_fat 179K 189K -5% (-5%) 4 4 0 opt_s 485K 448K 38K (7%) 490 4 486 opt_z 485K 448K 38K (7%) 490 4 486 lto_thin_z 180K 189K -5% (-5%) 4 4 0 lto_fat_z 179K 189K -5% (-5%) 4 4 0 full 179K 189K -5% (-5%) 4 4 0 ``` Test results show that this compiler option is beneficial for scenarios where LTO cannot be enabled. r? @bjorn3 @petrochenkov
2445a49 to
55c16ed
Compare
This comment has been minimized.
This comment has been minimized.
|
Can we now remove the |
|
@rustbot ready |
55c16ed to
a86abb9
Compare
a86abb9 to
0762f85
Compare
|
I didn't look at the strtab building code in detail yet, probably in the next review round. |
0762f85 to
1d6f596
Compare
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
|
@rustbot ready |
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…t, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, rust-lang#156950). Requested in rust-lang#156950 (comment). r? @petrochenkov
…henkov Staticlib hide internal symbols According to issue rust-lang/rust#104707, when building a staticlib, all Rust internal symbols — mangled symbols, `#[rustc_std_internal_symbol]` items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only `#[no_mangle]` symbols via a linker version script. `-Zstaticlib-hide-internal-symbols` directly post-processes ELF object files in the archive: parsing the `SHT_SYMTAB` sections and setting `STV_HIDDEN` visibility on any `GLOBAL/WEAK` defined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead. Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect. **Update**: The rename counterpart (`-Zstaticlib-rename-internal-symbols`) is in rust-lang/rust#156950. The test code are as follows: 1.a std rust staticlib: ```rust use std::collections::HashMap; use std::panic::{catch_unwind, AssertUnwindSafe}; #[no_mangle] pub extern "C" fn my_add(a: i32, b: i32) -> i32 { a + b } #[no_mangle] pub extern "C" fn my_hash_lookup(key: u64) -> u64 { let mut map = HashMap::new(); for i in 0..100u64 { map.insert(i, i.wrapping_mul(2654435761)); } *map.get(&key).unwrap_or(&0) } pub fn internal_reverse(s: &str) -> String { s.chars().rev().collect() } #[no_mangle] pub extern "C" fn my_format_number(n: i32) -> i32 { let s = format!("number: {}", n); s.len() as i32 } #[no_mangle] pub extern "C" fn my_safe_div(a: i32, b: i32) -> i32 { match catch_unwind(AssertUnwindSafe(|| { if b == 0 { panic!("division by zero!"); } a / b })) { Ok(result) => result, Err(_) => -1, } } #[no_mangle] pub extern "C" fn my_uncaught_panic() { panic!("uncaught panic across FFI"); } ``` 1.b downstream c program: ```c extern int my_add(int a, int b); extern unsigned long my_hash_lookup(unsigned long key); extern int my_format_number(int n); extern int my_safe_div(int a, int b); extern void my_uncaught_panic(void); int main() { int failures = 0; if (my_add(10, 20) != 30) failures++; if (my_hash_lookup(5) != 5UL * 2654435761UL) failures++; if (my_format_number(42) != 10) failures++; if (my_safe_div(100, 5) != 20) failures++; if (my_safe_div(100, 0) != -1) failures++; pid_t pid = fork(); if (pid == 0) { alarm(5); my_uncaught_panic(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 1.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin 616K 584K 33K (5%) 246 5 241 lto_fat 525K 525K 0 (0%) 6 5 1 opt_s 1.7M 1.5M 204K (12%) 1735 5 1730 opt_z 1.7M 1.5M 204K (12%) 1735 5 1730 lto_thin_z 602K 570K 32K (5%) 246 5 241 lto_fat_z 514K 514K 0 (0%) 6 5 1 full 514K 514K 0 (0%) 6 5 1 ``` 1.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin 616K 599K 18K (2%) 246 5 241 lto_fat 525K 535K -1% (-1%) 6 5 1 opt_s 1.7M 1.5M 162K (9%) 1735 5 1730 opt_z 1.7M 1.5M 162K (9%) 1735 5 1730 lto_thin_z 602K 585K 18K (2%) 246 5 241 lto_fat_z 514K 524K -1% (-1%) 6 5 1 full 514K 523K -1% (-1%) 6 5 1 ``` 2.a no_std rust staticlib ```rust #![no_std] #![feature(core_intrinsics)] use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn embedded_add(a: i32, b: i32) -> i32 { a.wrapping_add(b) } #[no_mangle] pub extern "C" fn embedded_checksum(data: *const u8, len: usize) -> u8 { if data.is_null() { return 0; } let slice = unsafe { core::slice::from_raw_parts(data, len) }; let mut sum: u8 = 0; for &byte in slice { sum = sum.wrapping_add(byte); } sum } fn internal_helper() -> i32 { 42 } #[no_mangle] pub extern "C" fn call_internal() -> i32 { internal_helper() } #[no_mangle] pub extern "C" fn embedded_trigger_abort() { core::intrinsics::abort(); } ``` 2.b downstream c program ```c extern int embedded_add(int a, int b); extern unsigned char embedded_checksum(const unsigned char *data, unsigned long len); extern int call_internal(void); extern void embedded_trigger_abort(void); int main() { int failures = 0; if (embedded_add(10, 20) != 30) failures++; unsigned char data[] = {1, 2, 3}; if (embedded_checksum(data, 3) != 6) failures++; if (call_internal() != 42) failures++; pid_t pid = fork(); if (pid == 0) { embedded_trigger_abort(); _exit(0); } else { waitpid(pid, &status, 0); } return failures; } ``` The test results with different compiler flags(which might cause binary size reduction) are as follows: 2.c result with `-Zstaticlib-hide-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 429K 56K (11%) 490 4 486 lto_thin 180K 180K 0 (0%) 4 4 0 lto_fat 179K 179K 0 (0%) 4 4 0 opt_s 485K 429K 56K (11%) 490 4 486 opt_z 485K 429K 56K (11%) 490 4 486 lto_thin_z 180K 180K 0 (0%) 4 4 0 lto_fat_z 179K 179K 0 (0%) 4 4 0 full 179K 179K 0 (0%) 4 4 0 ``` 2.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols` ``` settings OFF ON -Zsave ALL OFF.dynsym ON.dynsym ------------------------------------------------------------------------ default 485K 447K 39K (7%) 490 4 486 lto_thin 180K 189K -5% (-5%) 4 4 0 lto_fat 179K 189K -5% (-5%) 4 4 0 opt_s 485K 448K 38K (7%) 490 4 486 opt_z 485K 448K 38K (7%) 490 4 486 lto_thin_z 180K 189K -5% (-5%) 4 4 0 lto_fat_z 179K 189K -5% (-5%) 4 4 0 full 179K 189K -5% (-5%) 4 4 0 ``` Test results show that this compiler option is beneficial for scenarios where LTO cannot be enabled. r? @bjorn3 @petrochenkov
Rollup merge of #157691 - cezarbbb:staticlib-move-symbol-edit, r=petrochenkov Move symbol hiding code to a new file Move the symbol visibility editing code (`apply_hide` and helpers) from `archive.rs` into a new `symbol_edit.rs` module. This is a pure code move with no functional changes — extracted to reduce the size of `archive.rs` and to provide a natural home for future symbol editing logic (e.g. renaming, #156950). Requested in #156950 (comment). r? @petrochenkov
This comment has been minimized.
This comment has been minimized.
1d6f596 to
27a996e
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
This PR is rebased on PR #157691 now. @petrochenkov |
| }; | ||
| ab.build(out_filename, exported_symbols); | ||
|
|
||
| let rename_suffix = |
There was a problem hiding this comment.
| let rename_suffix = | |
| let rename_suffix = rename.then(|| crate_info.symbol_rename_suffix.clone()); |
And this can be moved into the map below.
| let rename = rename_set | ||
| .as_ref() | ||
| .and_then(|set| sym.rename_suffix.as_deref().map(|s| (set, s))); | ||
| let edited = apply_edits(data, &sym.exported, sym.hide, rename); |
There was a problem hiding this comment.
| let edited = apply_edits(data, &sym.exported, sym.hide, rename); | |
| Box::new(apply_edits(data, &sym.exported, sym.hide, rename)); |
IIRC I asked this on the previous PR already, Cow<[u8]> implements AsRef<[u8]> so you should be able to box it directly, without matching on the Cow, no?
| } | ||
| let Ok(name_bytes) = sym.name(endian, strings) else { continue }; | ||
| let Ok(name) = str::from_utf8(name_bytes) else { continue }; | ||
| if !exported.contains(name) { |
There was a problem hiding this comment.
So we rename an undefined name if it is 1) not exported and 2) defined in some other object in the archive.
Yeah, I guess in this case there's no other choice than to collect all the defined non-exported names.
| } | ||
| } | ||
| } | ||
| Some(names) |
There was a problem hiding this comment.
| Some(names) | |
| Some((names, rename_suffix)) |
So you don't have to awkwardly add it later.
|
|
||
| let data_ptr = data.as_ptr() as usize; | ||
| let strings = symtab.strings(); | ||
| let data_ptr = data.as_ptr() as usize; |
There was a problem hiding this comment.
Mega-nit: unnecessary change.
| let sym_addr = sym as *const Elf::Sym as usize; | ||
| let is_defined = !sym.is_undefined(endian); | ||
|
|
||
| if hide && is_defined && !exported.contains(name) { |
There was a problem hiding this comment.
| if hide && is_defined && !exported.contains(name) { | |
| if hide && !sym.is_undefined(endian) && !exported.contains(name) { |
Nit: is_defined used once.
| Some(patches) | ||
| let mut result = if !renames.is_empty() { | ||
| let (_, suffix) = rename.unwrap(); | ||
| elf_rebuild_strtab::<Elf>(data, &renames, suffix, §ions, header, endian)? |
There was a problem hiding this comment.
If strtab rebuilding can fail, then we should probably apply hiding first?
That's assuming we are working on best effort basis (I assume so because right now all the ELF parsing issues are just silently ignored).
| } | ||
|
|
||
| for entry in renames { | ||
| let Some(&new_st_name) = rename_map.get(&entry.name) else { continue }; |
There was a problem hiding this comment.
| let Some(&new_st_name) = rename_map.get(&entry.name) else { continue }; | |
| let new_st_name = rename_map[entry.name]; |
The name must always be in the rename_map from what I see.
|
Most of the ELF comments apply to Mach-O too, as usual. |
View all comments
Follow-up to #155338.
-Zstaticlib-rename-internal-symbolsappends a crate-specific suffix (_rs{StableCrateId}) to non-exported symbols, resolving duplicate symbol conflicts when linking multiple Rust staticlibs into the same binary.The implementation collects all defined
GLOBAL/WEAKsymbol names not in the exported set across all .o files, then renames them by extending the strtab and patching symbol name offsets. When combined with-Zstaticlib-hide-internal-symbols, the renamed symbols also receiveSTV_HIDDENvisibility.Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect.
r?@bjorn3 @petrochenkov