Code that removes unused synthetic sections has a bug
that leaves unused section in output if its description is duplicated
in linkerscript. Testcase shows the issue, patch fixes it.
Details
Diff Detail
Event Timeline
ELF/Writer.cpp | ||
---|---|---|
1203–1204 | This loop needs a (brief) comment. |
Sorry, but I do not understand this function well. It seems too complicated compared to what it does (which doesn't sound too complicated). Can you refactor?
- Addressed review comments.
- Changed inplementation to use Live flag for removing output section.
ELF/Writer.cpp | ||
---|---|---|
-1–2 | No. That was just short way to write the code. Rewrote this place to longer, but more straightforward way, |
- Previous revision deviated too far from original intention of patch and can be separate refactoring, reverted it to use original approach.
- Addressed comments.
ELF/Writer.cpp | ||
---|---|---|
1204–1209 | Here we scan not over output sections, but over commands it contains. OS is an OutputSection*. It would be possible to avoid scanning if we would have pointer to InputSectionDescription command in each section (and InputSectionDescription can probably have poiner to OutputSection then), but we do not have it currently and I doubt we really need it. |
ELF/Writer.cpp | ||
---|---|---|
1218–1222 | I think I do not understand this code. You don't need to use all_of, right? The only way in which OS becomes empty is (1) it contains only one InputSectionDescription and (2) that InputSectionDescription is empty, no? |
ELF/Writer.cpp | ||
---|---|---|
1218–1222 | No. If OS has 2 or more ISDs which are empty, it is also empty. |
ELF/Writer.cpp | ||
---|---|---|
1218–1222 | So you are saying that .got output section is not created for .got : { *(.got) } if .got synthetic input section is empty, that is what I expected. But what about some output section .foo where it is created as .foo : { *(.bar) }, if no input file have .bar section? Do we still create .foo? If yes, that behavior is inconsistent. If no, there must be a place we remove empty output sections. Doing the same thing here doesn't make sense. |
ELF/Writer.cpp | ||
---|---|---|
1218–1222 |
No.
That place is adjustSectionsBeforeSorting(). There we mark output sections as Live even if they Alternative to removing of OS sections here is to set Live bit to false under some condition, which is I belive "if all ISDs are empty" and that is what this patch anyways already checks for removing the section. |
ELF/Writer.cpp | ||
---|---|---|
1218–1222 | I don't think I fully understand your justification. Are you saying that there is a reason that you have to have two pieces of code that basically does the same thing? |
ELF/Writer.cpp | ||
---|---|---|
1218–1222 | What we have now is code in removeEmptyCommands() which removes all output sections that are not live. In current method we have live section which should be dead after removing synthetic, so either needs to be marked as dead so that removeEmptyCommands() can handle it or be removed. For first case code here can probably be (after additional patch changing things outside this method, without that if will not work): Approach #1: OS->Live = !llvm::all_of(OS->Commands, [](BaseCommand *B) { auto *ISD = dyn_cast<InputSectionDescription>(B); return ISD && ISD->Sections.empty(); }); for second - code from this patch, which is: Approach #2: bool IsEmpty = llvm::all_of(OS->Commands, [](BaseCommand *B) { auto *ISD = dyn_cast<InputSectionDescription>(B); return ISD && ISD->Sections.empty(); }); if (IsEmpty) llvm::erase_if(Script->Opt.Commands, [&](BaseCommand *Cmd) { return Cmd == OS; }); Difference is in llvm::erase_if call, which also present in original code this patch fixes. Doing approach #1 is probably better. |
// SS is an unused synthetic section. Remove it from output section commands.