Previously when BC file had global variable that was accessed from script,
it was optimized away.
In this patch I add left side of assignment expression to list of symbols referenced
by script. That marks them used from regular objects for LTO and fixes issue observed.
Details
Diff Detail
Event Timeline
Out of curiosity, where did you hit this?
Is there any way to test that the assignment updates the value of foo to be 1 ?
Looks phab ate my first reply. Duplicating again for history:
Out of curiosity, where did you hit this?
I did not hit, just basing on my knowledge about how things work, I supposed this case will not work and checked.
Is there any way to test that the assignment updates the value of foo to be 1 ?
I believe yes, I'll update the testcase.
What happens if foo is specified in the linker script but actually doesn't appear in any bitcode file?
IIRC we should error in that case.
I think we will create absolute symbol foo for this case.
If it would be foo = bar then we would error out.
I was wrong, if all inputs are BC and we have foo = 1 script then I do not see it in output and link succeeds.
I'll take a look closer on this case.
As far I see without this patch situation is the same. We do not create absolute symbols if have
foo = 1 script and only bitcode inputs that does not have foo symbol.
I think such case should be fixed in a different patch then.
My appologies. Everything is fine with emiting absolute symbols.
Looks I looked into temporarily LTO object instead of final binary.
I updated testcase to show they work fine. Sorry for all noise.
ELF/ScriptParser.cpp | ||
---|---|---|
632 ↗ | (On Diff #112365) | I need to distinguish assignments inside output section declaration and outside (global). ONLY_IF_RO { abc = 1; *(foo) } And in that case we should not create abc at all. |
705–707 ↗ | (On Diff #112365) | Unfortunaly not, because PROVIDE/HIDDEN/PROVIDE_HIDDEN are using it too. We should not provide symbol that was not referenced. |
FWIW, this is just an incarnation of a more general problem, i.e. the fact that the interaction between LTO and linker scripts is/wasn't well studied in the past.
I guess we may want to fix this case, but I'm afraid several other problems will arise.
I wonder when/where we should draw the line between supporting arbitrary interactions between the two or just suggesting people to pass -fno-lto to an handful of files in their compile step, as GCC seems to be doing.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65252
(also, cc @pcc for thoughts)
I feel like a reasonable position to start with would be "you can't use a linker script to talk about sections in an LTO input file, only symbols". i.e. a SECTIONS clause would not be able to refer to sections in LTO input files, but you would be able to redefine symbols (that support already exists for --wrap and --defsym of course) and define symbols in terms of other symbols defined in LTO input files.
That basically seems to be the position that GCC has taken, and doesn't seem too onerous to support in LLD.
ELF/LTO.cpp | ||
---|---|---|
164–171 | I think we should be setting LinkerRedefined to true for these symbols instead of VisibleToRegularObj, otherwise the optimizer may IPO past them. |
ELF/LTO.cpp | ||
---|---|---|
164–171 | I am not really familar with LTO logic, but if that is true, that sounds like a bug of LTO for me. But actually I think it does not do that: And that prevents making them internal here: After all when parsing LTO objects and symbols: |
ELF/LTO.cpp | ||
---|---|---|
164–171 | When I mentioned bar and foo, I meant those from my testcase. foo is assigned in script, bar is not. |
ELF/LTO.cpp | ||
---|---|---|
164–171 | By "IPO past them" I meant that the optimizer may apply inlining or otherwise use the symbol's definition to optimize code that references the symbol, which is what setting LinkerRedefined prevents. That is orthogonal to whether the symbol is dropped. For example suppose we have these two TUs: int f() { return g(); } int g() { return 1; } int h() { return 2; } and this linker script: g = h; If we mark g as VisibleToRegularObj, that would not prevent g from being inlined into f at LTO time, causing f to incorrectly return 1. Setting LinkerRedefined prevents g from being inlined, so f will return 2 as a result of the linker script replacing g with h. |
ELF/LTO.cpp | ||
---|---|---|
164–171 | Ah, got it, thanks for explanation ! I'll try to prepare testcase and update the diff with this change. |
ELF/LTO.cpp | ||
---|---|---|
164–171 | "following symbols" doesn't explain what this code is for. It's basically saying that this code does something as is written. Please update the comment. |
ELF/LTO.cpp | ||
---|---|---|
165–170 | "We have to do this because ..." part explains why we can't do IPO for both (1) and (2) symbols. So, writing it as part of (2) is not correct. |
I would inline this function into the caller.