-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add -Z no-unique-section-names to reduce ELF header bloat. #89581
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @cjgillot (or someone else) soon. Please see the contribution instructions for more information. |
@@ -1188,6 +1188,8 @@ options! { | |||
"compile without linking"), | |||
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED], | |||
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), | |||
no_unique_section_names: bool = (false, parse_bool, [TRACKED], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't use parse_no_flag
- unlike the other no_*
flags above - because the parse_no_flag
function says its use is deprecated, so I made it a plain bool. Also, not entirely sure what tracking is for, so I set it to [TRACKED]
because function_sections
is also tracked.
This seems pretty reasonable. Is there a reason we shouldn't enable this by default? It seems like the general approach should be that if it makes your binary smaller, since it prevents dead section elimination but otherwise is beneficial. Is that right? It would be good to add a page to the unstable book in this PR https://github.com/rust-lang/rust/tree/master/src/doc/unstable-book/src/compiler-flags with some appropriate links and details on this. |
I'm basing the defaults on what Clang does, and wasn't comfortable changing the default behavior for all ELF targets. Clang (and LLVM) default to So to clarify, my understanding is that if you use the GNU Do you think |
I don't think we should change the behavior in this PR, mostly wanted to get a read on whether it would make sense to in the future. |
Sounds good. I'll get working on the unstable book page. |
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.
I added documentation for the new flag. |
Thanks. This looks basically good to go -- could you file a tracking issue (just a regular issue with a pointer to the future docs and a link to this PR is good) and list it in the unstable book entry? r=me with that done (please use |
@bors r+ |
📌 Commit 4ed846a has been approved by |
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@ee5d1a04), 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 like LLD don't currently merge or strip these EH sections (see discussion [here](https://reviews.llvm.org/D83655)). 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 a smaller final binary. The motivation to add this new option was because we have a binary that ended up with so many ELF sections (over 65,000) that it broke some existing ELF tools, which couldn't handle so many sections. Here's our old binary: ``` $ readelf --sections old.elf | head -1 There are 71746 section headers, starting at offset 0x2a246508: $ readelf --sections old.elf | grep shstrtab [71742] .shstrtab STRTAB 0000000000000000 2977204c ad44bb 00 0 0 1 ``` That's an 11MB+ string table. Here's the new binary using this option: ``` $ readelf --sections new.elf | head -1 There are 43 section headers, starting at offset 0x29143ca8: $ readelf --sections new.elf | grep shstrtab [40] .shstrtab STRTAB 0000000000000000 29143acc 0001db 00 0 0 1 ``` The whole binary size went down by over 20MB, which is quite significant.
…askrgr Rollup of 4 pull requests Successful merges: - rust-lang#89581 (Add -Z no-unique-section-names to reduce ELF header bloat.) - rust-lang#90196 (Fix and extent ControlFlow `traverse_inorder` example) - rust-lang#90255 (:arrow_up: rust-analyzer) - rust-lang#90266 (Prevent duplicate caller bounds candidates by exposing default substs in Unevaluated) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
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, 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 like LLD don't currently merge or strip these EH sections (see discussion here). 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 a smaller final binary.The motivation to add this new option was because we have a binary that ended up with so many ELF sections (over 65,000) that it broke some existing ELF tools, which couldn't handle so many sections.
Here's our old binary:
That's an 11MB+ string table. Here's the new binary using this option:
The whole binary size went down by over 20MB, which is quite significant.