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

[ELF] Support high address DW_EH_sdata4 for ELFCLASS32 #92438

Conversation

MaskRay
Copy link
Member

@MaskRay MaskRay commented May 16, 2024

When the address pointer encoding in FDEs uses
DW_EH_PE_absptr|DW_EH_PE_sdata4, the address is sign-extended to 64-bit
by readFdeAddr. We should truncate the address to 32-bit for
ELFCLASS32. Otherwise, isInt<32>(pc - va) could be false, leading to a
spurious error in getFdeData.

In LLVM, this appears a MIPS-specific issue.
Fix #88852

Created using spr 1.3.5-bogner
@llvmbot
Copy link
Collaborator

llvmbot commented May 16, 2024

@llvm/pr-subscribers-lld-elf

@llvm/pr-subscribers-lld

Author: Fangrui Song (MaskRay)

Changes

When the address pointer encoding in FDEs uses
DW_EH_PE_absptr|DW_EH_PE_sdata4, the address is sign-extended to 64-bit
by readFdeAddr. We should truncate the address to 32-bit for
ELFCLASS32. Otherwise, isInt&lt;32&gt;(pc - va) would be false, leading to a
spurious error in getFdeData.

In LLVM, this appears a MIPS-specific issue.
Fix #88852


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

2 Files Affected:

  • (modified) lld/ELF/SyntheticSections.cpp (+1-1)
  • (modified) lld/test/ELF/mips-eh_frame-pic.s (+9)
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 22bfed0852bca..ad280289cebf9 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -613,7 +613,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff,
   size_t off = fdeOff + 8;
   uint64_t addr = readFdeAddr(buf + off, enc & 0xf);
   if ((enc & 0x70) == DW_EH_PE_absptr)
-    return addr;
+    return config->is64 ? addr : uint32_t(addr);
   if ((enc & 0x70) == DW_EH_PE_pcrel)
     return addr + getParent()->addr + off + outSecOff;
   fatal("unknown FDE size relative encoding");
diff --git a/lld/test/ELF/mips-eh_frame-pic.s b/lld/test/ELF/mips-eh_frame-pic.s
index 79076e74a7e3f..fd8560bc0163f 100644
--- a/lld/test/ELF/mips-eh_frame-pic.s
+++ b/lld/test/ELF/mips-eh_frame-pic.s
@@ -27,6 +27,11 @@
 ## relative addressing.
 # NOPIC32-ERR: ld.lld: error: relocation R_MIPS_32 cannot be used against local symbol
 
+## https://github.com/llvm/llvm-project/issues/88852: getFdePc should return a
+## 32-bit address.
+# RUN: ld.lld --eh-frame-hdr -Ttext=0x80000000 %t-nopic32.o -o %t-nopic32
+# RUN: llvm-readelf -x .eh_frame_hdr %t-nopic32 | FileCheck %s --check-prefix=NOPIC32-HDR
+
 ## For -fPIC, .eh_frame should contain DW_EH_PE_pcrel | DW_EH_PE_sdata4 values:
 # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux --position-independent %s -o %t-pic32.o
 # RUN: llvm-readobj -r %t-pic32.o | FileCheck %s --check-prefixes=RELOCS,PIC32-RELOCS
@@ -51,6 +56,10 @@
 ## Note: ld.bfd converts the R_MIPS_64 relocs to DW_EH_PE_pcrel | DW_EH_PE_sdata8
 ## for N64 ABI (and DW_EH_PE_pcrel | DW_EH_PE_sdata4 for MIPS32)
 
+# NOPIC32-HDR: Hex dump of section '.eh_frame_hdr':
+# NOPIC32-HDR: 0x80010038 011b033b 00000010 00000001 fffeffc8 .
+# NOPIC32-HDR: 0x80010048 00000028                            .
+
 .ent func
 .global func
 func:

Created using spr 1.3.5-bogner
@MaskRay MaskRay merged commit dd8cb3d into main May 20, 2024
3 of 4 checks passed
@MaskRay MaskRay deleted the users/MaskRay/spr/elf-support-high-address-dw_eh_sdata4-for-elfclass32 branch May 20, 2024 07:13
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.

[MIPS] Got PC offset is too large 0xffffffff.... when linking using LLD
3 participants