The .dynamic section of an ELF almost doesn't need to be written to with the exception of the DT_DEBUG entry. For several reasons having a read only .dynamic section would be useful. This change adds the -z keyword "rodynamic" which forces .dynamic to be read-only. In this case DT_DEBUG will not be emited.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
I have a couple of questions.
- Why can't .dynamic be read-only for all output?
- .dynamic is already covered by PT_GNU_RELRO segments. Does it make sense to make it read-only from beginning?
It seems that you are proposing a new command line option that even GNU linkers don't have, so this patch needs extra attention. Are you adding that option to GNU linkers too?
On second thought, it isn't good to discuss new linker command line option in a code review thread, as most people do not read every review threads. Please start a thread in llvm-dev to propose a new option with an explanation why you want it.
Does it make sense to make it read-only from beginning?
For me I think having .dynamic relro is sufficient, and might actually like to have MIPS use the conventional DT_DEBUG scheme.
Agreed. It seems that this scheme exists only for historical reasons: looking through binutils history, DT_MIPS_RLD_MAP was introduced in 1994 [0], while PT_GNU_RELRO was introduced 10 years later [1].
[0] https://github.com/bminor/binutils-gdb/commit/4c040a649b610ab1a0b5aa30c01148bffa9e2f4b
[1] https://github.com/bminor/binutils-gdb/commit/8c37241be3b1baf394090269b4b67babceb83d61
After some discussion on llvm-dev it was decided that it would be best to not mess with DT_DEBUG_INDIRECT.
I'm not convinced that we need this, so please don't submit.
If this is for your OS's vDSO which needs to be read by an in-kernel ELF loader which doesn't support the entire ELF spec, this patch is to work around your loader's limitation. If you don't want to implement a complete ELF loader, why do you want to "fix" the problem in the right way? It is odd that you do hack at one place and do the right thing at the other place. Your loader can ignore RW bit and map .dynamic sections to read-only segments.
ELF/SyntheticSections.cpp | ||
---|---|---|
1008 ↗ | (On Diff #100014) | ... on MIPS and on Fuchsia OS which passes -z rodynamic. |
1011 ↗ | (On Diff #100014) | Probably it is better to not add this comment as it is not informative but could be confusing (e.g. why users may want it on other systems?) |
1057 ↗ | (On Diff #100014) | Add a space after // and a full stop at end of the line. But you want to extend the comment to explain the background. I'd write something like: DT_DEBUG points to a location containing some debug info so that debuggers can find debug info at runtime. We need it for each process, so we don't write it for DSOs. DT_DEBUG is the only .dynamic entry to which the loader is expected to write. Some systems, such as Fuchsia, chose to make .dynamic sections completely read-only (and provides alternative mean to find debug info). If the target is such system, we don't write DT_DEBUG. |
ELF/Config.h | ||
---|---|---|
147 ↗ | (On Diff #100329) | These variables are named after their corresponding command line options, so ZRodynamic. |
ELF/SyntheticSections.cpp | ||
1060 ↗ | (On Diff #100329) | You want to break the paragraph by adding a blank // line. |
1061–1062 ↗ | (On Diff #100329) | Let's avoid writing comments too abstractly. "Some systems (currently only Fuchsia)" and instead of "Such systemS", "Fuchsia". |
ELF/Config.h | ||
---|---|---|
147–148 ↗ | (On Diff #100335) | Sort. |
ELF/Driver.cpp | ||
690–691 ↗ | (On Diff #100335) | Sort |
ELF/SyntheticSections.cpp | ||
1064 ↗ | (On Diff #100335) | What I wanted is this // blah blah blah ... // blah blah blah ... // // blah blah blah ... // blah blah blah ... and not // blah blah blah ... // blah blah blah ... // blah blah blah ... // blah blah blah ... // (Please look around to find a local convention and follow it.) |
test/ELF/rodynamic.s | ||
---|---|---|
2 ↗ | (On Diff #100347) | This doesn't test the feature you've just added, since -shared is passed. You want to remove that flag. |
8–13 ↗ | (On Diff #100347) | This checks the presence of .dynamic section, which is not what you actually want to do. You want to use llvm-readobj like this. RUN: ld.lld -o %t1 %t.o RUN: llvm-readobj -dynamic-table %t1 | FileCheck -check-prefix=DEFAULT %s DEFAULT: DEBUG RUN: ld.lld -o %t2 %t.o -z rodynamic RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s CHECK-NOT: DEBUG |
Right! I forgot to check that DEBUG wasn't being emitted in the test. I also forgot to check the default behavior. The other part of the test ensures that the .dynamic section is in fact read-only and that in the default case it is read-write. I had to produce a shared library to make the executable have a .dynamic section as well so I added a simple file to Inputs.