Skip to content

Commit 4ed846a

Browse files
committed
Add -Z no-unique-section-names to reduce ELF header bloat.
This change adds a new compiler flag that can help reduce the size of ELF binaries that contain many functions. By default, when enabling function sections (which is the default for most targets), the LLVM backend will generate different section names for each function. For example, a function "func" would generate a section called ".text.func". Normally this is fine because the linker will merge all those sections into a single one in the binary. However, starting with LLVM 12 (llvm/llvm-project@ee5d1a0), the backend will also generate unique section names for exception handling, resulting in thousands of ".gcc_except_table.*" sections ending up in the final binary because some linkers don't currently merge or strip these EH sections. This can bloat the ELF headers and string table significantly in binaries that contain many functions. The new option is analogous to Clang's -fno-unique-section-names, and instructs LLVM to generate the same ".text" and ".gcc_except_table" section for each function, resulting in smaller object files and potentially a smaller final binary.
1 parent 25ec827 commit 4ed846a

File tree

6 files changed

+17
-0
lines changed

6 files changed

+17
-0
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+2
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ pub fn target_machine_factory(
161161
let ffunction_sections =
162162
sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections);
163163
let fdata_sections = ffunction_sections;
164+
let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names;
164165

165166
let code_model = to_llvm_code_model(sess.code_model());
166167

@@ -205,6 +206,7 @@ pub fn target_machine_factory(
205206
use_softfp,
206207
ffunction_sections,
207208
fdata_sections,
209+
funique_section_names,
208210
trap_unreachable,
209211
singlethread,
210212
asm_comments,

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,7 @@ extern "C" {
21532153
UseSoftFP: bool,
21542154
FunctionSections: bool,
21552155
DataSections: bool,
2156+
UniqueSectionNames: bool,
21562157
TrapUnreachable: bool,
21572158
Singlethread: bool,
21582159
AsmComments: bool,

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ fn test_debugging_options_tracking_hash() {
740740
tracked!(new_llvm_pass_manager, Some(true));
741741
tracked!(no_generate_arange_section, true);
742742
tracked!(no_link, true);
743+
tracked!(no_unique_section_names, true);
743744
tracked!(no_profiler_runtime, true);
744745
tracked!(osx_rpath_install_name, true);
745746
tracked!(panic_abort_tests, true);

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
459459
LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
460460
bool FunctionSections,
461461
bool DataSections,
462+
bool UniqueSectionNames,
462463
bool TrapUnreachable,
463464
bool Singlethread,
464465
bool AsmComments,
@@ -488,6 +489,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
488489
}
489490
Options.DataSections = DataSections;
490491
Options.FunctionSections = FunctionSections;
492+
Options.UniqueSectionNames = UniqueSectionNames;
491493
Options.MCOptions.AsmVerbose = AsmComments;
492494
Options.MCOptions.PreserveAsmComments = AsmComments;
493495
Options.MCOptions.ABIName = ABIStr;

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,8 @@ options! {
11881188
"compile without linking"),
11891189
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
11901190
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
1191+
no_unique_section_names: bool = (false, parse_bool, [TRACKED],
1192+
"do not use unique names for text and data sections when -Z function-sections is used"),
11911193
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
11921194
"prevent automatic injection of the profiler_builtins crate"),
11931195
normalize_docs: bool = (false, parse_bool, [TRACKED],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# `no-unique-section-names`
2+
3+
------------------------
4+
5+
This flag currently applies only to ELF-based targets using the LLVM codegen backend. It prevents the generation of unique ELF section names for each separate code and data item when `-Z function-sections` is also in use, which is the default for most targets. This option can reduce the size of object files, and depending on the linker, the final ELF binary as well.
6+
7+
For example, a function `func` will by default generate a code section called `.text.func`. Normally this is fine because the linker will merge all those `.text.*` sections into a single one in the binary. However, starting with [LLVM 12](https://github.com/llvm/llvm-project/commit/ee5d1a04), the backend will also generate unique section names for exception handling, so you would see a section name of `.gcc_except_table.func` in the object file and potentially in the final ELF binary, which could add significant bloat to programs that contain many functions.
8+
9+
This flag instructs LLVM to use the same `.text` and `.gcc_except_table` section name for each function, and it is analogous to Clang's `-fno-unique-section-names` option.

0 commit comments

Comments
 (0)