-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LLD][AArch64] Mark .plt with PURECODE flag if all input sections also have it #132224
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
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// REQUIRES: aarch64 | ||
// RUN: rm -rf %t && split-file %s %t && cd %t | ||
|
||
// RUN: llvm-mc -filetype=obj -triple=aarch64 start.s -o start.o | ||
// RUN: llvm-mc -filetype=obj -triple=aarch64 xo-same-section.s -o xo-same-section.o | ||
// RUN: llvm-mc -filetype=obj -triple=aarch64 rx-same-section.s -o rx-same-section.o | ||
// RUN: llvm-mc -filetype=obj -triple=aarch64 xo-different-section.s -o xo-different-section.o | ||
// RUN: llvm-mc -filetype=obj -triple=aarch64 rx-different-section.s -o rx-different-section.o | ||
// RUN: llvm-mc -filetype=obj -triple=aarch64 %p/Inputs/plt-aarch64.s -o plt.o | ||
// RUN: ld.lld -shared plt.o -soname=t2.so -o plt.so | ||
// RUN: ld.lld start.o xo-same-section.o plt.so -o xo-same-section | ||
// RUN: ld.lld start.o rx-same-section.o plt.so -o rx-same-section | ||
// RUN: ld.lld start.o xo-different-section.o plt.so -o xo-different-section | ||
// RUN: ld.lld start.o rx-different-section.o plt.so -o rx-different-section | ||
// RUN: llvm-readelf -S -l xo-same-section | FileCheck --check-prefix=CHECK-XO %s | ||
// RUN: llvm-readelf -S -l rx-same-section | FileCheck --check-prefix=CHECK-RX %s | ||
// RUN: llvm-readelf -S -l xo-different-section | FileCheck --check-prefix=CHECK-XO %s | ||
// RUN: llvm-readelf -S -l rx-different-section | FileCheck --check-prefix=CHECK-RX %s | ||
// RUN: llvm-objdump -d --no-show-raw-insn xo-same-section | FileCheck --check-prefix=DISASM %s | ||
// RUN: llvm-objdump -d --no-show-raw-insn rx-same-section | FileCheck --check-prefix=DISASM %s | ||
// RUN: llvm-objdump -d --no-show-raw-insn xo-different-section | FileCheck --check-prefix=DISASM %s | ||
// RUN: llvm-objdump -d --no-show-raw-insn rx-different-section | FileCheck --check-prefix=DISASM %s | ||
|
||
/// Name Type Address Off Size ES Flg Lk Inf Al | ||
// CHECK-XO: .plt PROGBITS 00000000002102e0 0002e0 000040 00 AXy 0 0 16 | ||
// CHECK-RX: .plt PROGBITS 00000000002102e0 0002e0 000040 00 AX 0 0 16 | ||
|
||
/// The address of .plt above should be within this program header. | ||
/// Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align | ||
// CHECK-XO: LOAD 0x0002c8 0x00000000002102c8 0x00000000002102c8 0x000058 0x000058 E 0x10000 | ||
// CHECK-RX: LOAD 0x0002c8 0x00000000002102c8 0x00000000002102c8 0x000058 0x000058 R E 0x10000 | ||
|
||
// DISASM-LABEL: Disassembly of section .plt: | ||
// DISASM-LABEL: <.plt>: | ||
// DISASM-NEXT: 2102e0: stp x16, x30, [sp, #-0x10]! | ||
// DISASM-NEXT: adrp x16, 0x230000 <weak+0x230000> | ||
// DISASM-NEXT: ldr x17, [x16, #0x400] | ||
// DISASM-NEXT: add x16, x16, #0x400 | ||
// DISASM-NEXT: br x17 | ||
// DISASM-NEXT: nop | ||
// DISASM-NEXT: nop | ||
// DISASM-NEXT: nop | ||
|
||
// DISASM-LABEL: <bar@plt>: | ||
// DISASM-NEXT: 210300: adrp x16, 0x230000 <weak+0x230000> | ||
// DISASM-NEXT: ldr x17, [x16, #0x408] | ||
// DISASM-NEXT: add x16, x16, #0x408 | ||
// DISASM-NEXT: br x17 | ||
|
||
// DISASM-LABEL: <weak@plt>: | ||
// DISASM-NEXT: 210310: adrp x16, 0x230000 <weak+0x230000> | ||
// DISASM-NEXT: ldr x17, [x16, #0x410] | ||
// DISASM-NEXT: add x16, x16, #0x410 | ||
// DISASM-NEXT: br x17 | ||
|
||
//--- start.s | ||
.section .text,"axy",@progbits,unique,0 | ||
.global _start, foo, bar | ||
.weak weak | ||
_start: | ||
bl foo | ||
bl bar | ||
bl weak | ||
ret | ||
|
||
//--- xo-same-section.s | ||
.section .text,"axy",@progbits,unique,0 | ||
.global foo | ||
foo: | ||
ret | ||
|
||
//--- rx-same-section.s | ||
.section .text,"ax",@progbits,unique,0 | ||
.global foo | ||
foo: | ||
ret | ||
|
||
//--- xo-different-section.s | ||
.section .foo,"axy",@progbits,unique,0 | ||
.global foo | ||
foo: | ||
ret | ||
|
||
//--- rx-different-section.s | ||
.section .foo,"ax",@progbits,unique,0 | ||
.global foo | ||
foo: | ||
ret |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Alternatively it should be possible to universally set SHF_AARCH64_PURECODE and then
handle this in
Writer.cpp::createPhdrs()
https://github.com/llvm/llvm-project/blob/main/lld/ELF/Writer.cpp#L2381
Something like:
It is true that the .plt could in theory be the first section, but this would normally take a linker script making it the first OutputSection, but I think that's unlikely, and could be fixed with PHDRS.
I did think we might do this for all OutputSections but I guess for bare-metal there's still a use case for separate XO and non-XO segments.
Another possibility is to record any non-XO OutputSection that we see in ctx.
Uh oh!
There was an error while loading. Please reload this page.
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.
sec
can't be compared withctx.in.plt
there, because it is an output section, andctx.in.plt
is an input section. We'd have to dofindSection(ctx, ".plt")
in order to get the.plt
output section.Another concern I have with manipulating the output sections directly is that maybe one of the non-synthetic input sections might be placed in the
.plt
output section? I'm not sure if this really happens with real code, but I'd rather write a solution that works in every case by usingSHF_AARCH64_PURECODE
correctly on the input sections.For an alternate solution, another possible spot I found where we can modify the flags of
ctx.in.plt
is in this loop insideaddOrphanSections
:llvm-project/lld/ELF/LinkerScript.cpp
Lines 1015 to 1040 in 77edfbb
Adding something like this here works:
We can save looping through the input sections an extra time in the
PltSection
constructor, but the logic gets decoupled fromPltSection
, which I'm not a fan of. What do you think about this?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.
Apologies for the long comment!
It is possible to find the OutputSection that contains the .plt, it would be something like
.in.plt->parent
. That would mean that we would only need to check OutputSections rather than input sections. If the .plt is mixed with non XO InputSections then the OutputSection is in will be non-XO. However ...Taking a step back, I think it will be worth thinking through what the heuristics for Program Header generation are when it comes to XO. Apologies I didn't have time to write this up yesterday Evening. I think there could be more than just the
.plt
that is affected.In principle any orphan section with SHF_PURECODE (that generates an OutputSection) will propagate SHF_PURECODE to the OutputSection, which is going to auto-generate an XO program header on a transition from non-XO, which isn't going to be helpful for a non-XO program. How much of a problem this is I don't know. For an Android/Linux system needing full XO, there may be a non-zero number of libraries that need SHF_PURECODE just in case they are used in an XO context. In a contrived worst case we have alternate XO, non-XO output sections and get a separate program header for each OutputSection.
Thinking of a model for how this would be used, I think we have two (possibly three) cases:
For the bare-metal system we would like to have separate XO and non-XO program headers for the same output file. It is up to the user to write the linker script to separate out the XO and non-XO into distinct memory regions, and possibly use PHDRS to make sure they get what they need.
For the OS that can only have a program thats XO or not XO, we ideally want all executable OutputSections to be XO before generating an XO program header.
For the OS that can have multiple XO and non XO parts, then there's no good simple heuristic that I can think of that's always going to work. However I think we can probably rule this use case out.
With that in mind I propose that we do something like:
Not sure I've got that completely right, but it should be close. I think that could be applied in createPhdrs().
The alternative view is that this is too complicated and it is only the PLT that the linker should care about, getting XO right is the users responsibility.
In that case it may simplify to
Again this could be done at the start of createPhdrs().
Uh oh!
There was an error while loading. Please reload this page.
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.
Thanks for the thorough reply! It really helped refine my understanding of the problem.
You're right that the main use case we care about is the whole program being XO or RX. What do you think about doing the following:
SHF_AARCH64_PURECODE
for.plt
.--rosegment
to control this behaviour.We can do this by just adding the following snippet in
createPhdrs()
:if (newFlags & PF_X) incompatible &= ~PF_R;
For bare-metal targets, this wouldn't allow separate auto-generated program headers with XO and RX code though, a linker script (or just a flag?) would be required to separate those out into different program headers. I don't have any experience working with bare-metal, do you think this is a reasonable requirement? If not, can we detect in the linker whether we're linking for a target with an OS or not?
If you think this would be a good approach, I'll open a separate PR superseding this one, as it's a more general solution.
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.
For the bare metal case with linker script I think that would be OK. I expect that in a majority of cases a MEMORY region would be setup for the XO and non-XO memory. These would have distinct addresses such that a separate program header would be created anyway. If it weren't then PHDRS could be used to force the separation.
We'd need to release note the change in behaviour but I think that it is worth it to get the merging case right.
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'll open a separate PR then with my proposed approach. Thank you for your insights!