Skip to content
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

[lld/ELF][X86] Respect outSecOff when checking if GOTPCREL can be relaxed #86334

Merged
merged 1 commit into from
Mar 24, 2024

Conversation

aeubanks
Copy link
Contributor

The existing implementation didn't handle when the input text section was some offset from the output section.

This resulted in an assert in relaxGot() with an lld built with asserts for some large binaries, or even worse, a silently broken binary with an lld without asserts.

…axed

The existing implementation didn't handle when the input text section was some offset from the output section.

This resulted in an assert in relaxGot() with an lld built with asserts for some large binaries, or even worse, a silently broken binary with an lld without asserts.
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 22, 2024

@llvm/pr-subscribers-lld

@llvm/pr-subscribers-lld-elf

Author: Arthur Eubanks (aeubanks)

Changes

The existing implementation didn't handle when the input text section was some offset from the output section.

This resulted in an assert in relaxGot() with an lld built with asserts for some large binaries, or even worse, a silently broken binary with an lld without asserts.


Full diff: https://github.com/llvm/llvm-project/pull/86334.diff

2 Files Affected:

  • (modified) lld/ELF/Arch/X86_64.cpp (+4-3)
  • (modified) lld/test/ELF/x86-64-gotpc-relax-too-far.s (+11-1)
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index de459013595fed..a85bf3aa0c09d1 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -328,9 +328,10 @@ bool X86_64::relaxOnce(int pass) const {
         if (rel.expr != R_RELAX_GOT_PC)
           continue;
 
-        uint64_t v = sec->getRelocTargetVA(
-            sec->file, rel.type, rel.addend,
-            sec->getOutputSection()->addr + rel.offset, *rel.sym, rel.expr);
+        uint64_t v = sec->getRelocTargetVA(sec->file, rel.type, rel.addend,
+                                           sec->getOutputSection()->addr +
+                                               sec->outSecOff + rel.offset,
+                                           *rel.sym, rel.expr);
         if (isInt<32>(v))
           continue;
         if (rel.sym->auxIdx == 0) {
diff --git a/lld/test/ELF/x86-64-gotpc-relax-too-far.s b/lld/test/ELF/x86-64-gotpc-relax-too-far.s
index 74aa6d8f65a0d8..ba41faab67de5c 100644
--- a/lld/test/ELF/x86-64-gotpc-relax-too-far.s
+++ b/lld/test/ELF/x86-64-gotpc-relax-too-far.s
@@ -5,7 +5,10 @@
 # RUN: llvm-objdump --no-print-imm-hex -d %t/bin | FileCheck --check-prefix=DISASM %s
 # RUN: llvm-readelf -S %t/bin | FileCheck --check-prefixes=GOT %s
 # RUN: ld.lld -T %t/lds2 %t/a.o -o %t/bin2
-# RUN: llvm-readelf -S %t/bin2 | FileCheck --check-prefixes=UNNECESSARY-GOT %s
+# RUN: llvm-objdump --no-print-imm-hex -d %t/bin2 | FileCheck --check-prefix=DISASM %s
+# RUN: llvm-readelf -S %t/bin2 | FileCheck --check-prefixes=GOT %s
+# RUN: ld.lld -T %t/lds3 %t/a.o -o %t/bin3
+# RUN: llvm-readelf -S %t/bin3 | FileCheck --check-prefixes=UNNECESSARY-GOT %s
 
 # DISASM:      <_foo>:
 # DISASM-NEXT: movl    2097146(%rip), %eax
@@ -47,6 +50,13 @@ SECTIONS {
   data 0x80200000 : { *(data) }
 }
 #--- lds2
+SECTIONS {
+  .text.foo 0x100000 : { *(.text.foo) }
+  .text 0x1ff000 : { . = . + 0x1000 ; *(.text) }
+  .got 0x300000 : { *(.got) }
+  data 0x80200000 : { *(data) }
+}
+#--- lds3
 SECTIONS {
   .text.foo 0x100000 : { *(.text.foo) }
   .text 0x200000 : { *(.text) }

Copy link

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link

✅ With the latest revision this PR passed the Python code formatter.

@@ -47,6 +50,13 @@ SECTIONS {
data 0x80200000 : { *(data) }
}
#--- lds2
SECTIONS {
.text.foo 0x100000 : { *(.text.foo) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any checks to go along with the new sections?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a linker script to achieve the goal is too complex.
Use two input sections instead? The second input contains relocations while the first is for padding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any checks to go along with the new sections?

What do you mean by new sections? This linker script is a copy of the first one, but with the output section address adjusted.

Use two input sections instead? The second input contains relocations while the first is for padding.

if I'm understanding your request, using two input sections (e.g.)

.section .text,"ax"
.space 4096

.section .text,"ax"
.globl _start
.type _start, @function
_start:
  movl __stop_data@GOTPCREL(%rip), %eax  # out of range
  movq __stop_data@GOTPCREL(%rip), %rax  # out of range
  movq __stop_data@GOTPCREL(%rip), %rax  # in range
  movl __stop_data@GOTPCREL(%rip), %eax  # in range

adjusts rel.offset instead of sec->outSecOff so it doesn't trigger this bug

the bug I found was in the context of a linker script

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any checks to go along with the new sections?

if you mean .text.foo, perhaps we should remove that part of this test since it's obsoleted by the other part

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've added new sections. Presumably it affects the output, but we're not checking for anything.
Basically, if we remove the added part, or if it has no intended effect, the test should start failing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lds2 test does fail if . += 0x1000 below is removed or outSecOff from code is removed. So the test seems fine to me.

@@ -47,6 +50,13 @@ SECTIONS {
data 0x80200000 : { *(data) }
}
#--- lds2
SECTIONS {
.text.foo 0x100000 : { *(.text.foo) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lds2 test does fail if . += 0x1000 below is removed or outSecOff from code is removed. So the test seems fine to me.

@aeubanks aeubanks merged commit 4804805 into llvm:main Mar 24, 2024
7 checks passed
@aeubanks aeubanks deleted the fix-relax branch March 24, 2024 17:43
llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Mar 26, 2024
…axed (llvm#86334)

The existing implementation didn't handle when the input text section
was some offset from the output section.

This resulted in an assert in relaxGot() with an lld built with asserts
for some large binaries, or even worse, a silently broken binary with an
lld without asserts.

(cherry picked from commit 4804805)
tstellar pushed a commit to llvmbot/llvm-project that referenced this pull request Mar 27, 2024
…axed (llvm#86334)

The existing implementation didn't handle when the input text section
was some offset from the output section.

This resulted in an assert in relaxGot() with an lld built with asserts
for some large binaries, or even worse, a silently broken binary with an
lld without asserts.

(cherry picked from commit 4804805)
@pointhex pointhex mentioned this pull request May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants