-
Notifications
You must be signed in to change notification settings - Fork 15.7k
[lld][llvm/mc] Add support for sdata8 for FDE CIE #174508
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
base: main
Are you sure you want to change the base?
Conversation
|
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
|
@llvm/pr-subscribers-lld-elf @llvm/pr-subscribers-llvm-mc Author: Farid Zakaria (fzakaria) ChangesMotivationThis is related to #174486 and part of a larger effort to support larger binaries (>2GiB I have a separate change that leverages thunks to support large This can also still occur if a linker script places the
Full diff: https://github.com/llvm/llvm-project/pull/174508.diff 10 Files Affected:
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a1572578fb141..7c71220d16ed9 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -120,6 +120,9 @@ CODEGENOPT(StackSizeSection , 1, 0, Benign) ///< Set when -fstack-size-section
///< Set when -femit-compact-unwind-non-canonical is enabled.
CODEGENOPT(EmitCompactUnwindNonCanonical, 1, 0, Benign)
+///< Set when -flarge-fde-encoding is enabled.
+CODEGENOPT(LargeFDEEncoding, 1, 0, Benign)
+
///< Set when -fxray-always-emit-customevents is enabled.
CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0, Benign)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 04756ce486eaf..555528088676d 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4780,6 +4780,11 @@ defm emit_compact_unwind_non_canonical : BoolFOption<"emit-compact-unwind-non-ca
PosFlag<SetTrue, [], [ClangOption, CC1Option, CC1AsOption],
"Try emitting Compact-Unwind for non-canonical entries. Maybe overridden by other constraints">,
NegFlag<SetFalse>>;
+defm large_fde_encoding : BoolFOption<"large-fde-encoding",
+ CodeGenOpts<"LargeFDEEncoding">, DefaultFalse,
+ PosFlag<SetTrue, [], [ClangOption, CC1Option, CC1AsOption],
+ "Use 8-byte pointers for ELF FDE CFI encoding. Useful when text sections may exceed 2GB">,
+ NegFlag<SetFalse>>;
def g_Flag : Flag<["-"], "g">, Group<g_Group>,
Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>,
HelpText<"Generate source-level debug information">;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e4b64a0c2ff48..20d3d26d9de3d 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -514,6 +514,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
Options.MCOptions.EmitDwarfUnwind = CodeGenOpts.getEmitDwarfUnwind();
Options.MCOptions.EmitCompactUnwindNonCanonical =
CodeGenOpts.EmitCompactUnwindNonCanonical;
+ Options.MCOptions.LargeFDEEncoding = CodeGenOpts.LargeFDEEncoding;
Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
Options.MCOptions.MCUseDwarfDirectory =
diff --git a/clang/test/Driver/flarge-fde-encoding.c b/clang/test/Driver/flarge-fde-encoding.c
new file mode 100644
index 0000000000000..e20da6651f4c8
--- /dev/null
+++ b/clang/test/Driver/flarge-fde-encoding.c
@@ -0,0 +1,10 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang -### --target=x86_64-linux-gnu -flarge-fde-encoding %s 2>&1 | FileCheck %s --check-prefix=POS
+// RUN: %clang -### --target=x86_64-linux-gnu -fno-large-fde-encoding %s 2>&1 | FileCheck %s --check-prefix=NEG
+// RUN: %clang -### --target=x86_64-linux-gnu %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
+
+// POS: "-flarge-fde-encoding"
+// NEG-NOT: "-flarge-fde-encoding"
+// DEFAULT-NOT: "-flarge-fde-encoding"
+
+int dummy;
diff --git a/lld/test/ELF/eh-frame-large-fde-encoding.s b/lld/test/ELF/eh-frame-large-fde-encoding.s
new file mode 100644
index 0000000000000..e374de8444e67
--- /dev/null
+++ b/lld/test/ELF/eh-frame-large-fde-encoding.s
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+
+## Test that demonstrates FDE encoding overflow when .eh_frame is placed
+## far from .text, and the fix using 8-byte (sdata8) FDE encoding.
+##
+## With the default 4-byte FDE encoding (sdata4), a PC-relative offset
+## to .text can overflow if .eh_frame is placed more than 2GB away.
+## Using -large-fde-encoding (or mcmodel=large) switches to 8-byte
+## FDE encoding which can address the full 64-bit address space.
+
+# RUN: rm -rf %t && split-file %s %t
+
+## Test 1: With default sdata4 encoding, placing .eh_frame far from .text
+## causes an overflow error.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu --large-fde-encoding=false \
+# RUN: %t/test.s -o %t/test-small.o
+# RUN: not ld.lld %t/test-small.o -T %t/far.lds -o /dev/null 2>&1 | \
+# RUN: FileCheck %s --check-prefix=OVERFLOW
+
+## Test 2: With sdata8 encoding via -large-fde-encoding, no overflow.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -large-fde-encoding \
+# RUN: %t/test.s -o %t/test-large.o
+# RUN: ld.lld %t/test-large.o -T %t/far.lds -o %t/out
+
+# OVERFLOW: ld.lld: error: <internal>:(.eh_frame+0x{{[0-9a-fA-F]+}}): relocation R_X86_64_PC32 out of range
+
+#--- test.s
+.text
+.globl _start
+.type _start, @function
+_start:
+ .cfi_startproc
+ ret
+ .cfi_endproc
+
+#--- far.lds
+SECTIONS {
+ ## Place .text at a low address
+ . = 0x1000;
+ .text : { *(.text) }
+
+ ## Place .eh_frame more than 2GB away to trigger overflow with sdata4
+ . = 0x100001000;
+ .eh_frame : { *(.eh_frame) }
+}
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 235d58d585b40..da62be369a43c 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -108,6 +108,10 @@ class MCTargetOptions {
// Whether or not to use full register names on PowerPC.
bool PPCUseFullRegisterNames : 1;
+ // Use 8-byte pointer size for ELF FDE CFI encoding, regardless of code model.
+ // Useful when text sections may exceed 2GB even with medium code model
+ bool LargeFDEEncoding : 1;
+
LLVM_ABI MCTargetOptions();
/// getABIName - If this returns a non-empty string this represents the
diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
index 168131b43cca8..beba9f835afeb 100644
--- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
+++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
@@ -63,6 +63,8 @@ LLVM_ABI bool getX86RelaxRelocations();
LLVM_ABI bool getX86Sse2Avx();
+LLVM_ABI bool getLargeFDEEncoding();
+
LLVM_ABI StringRef getABIName();
LLVM_ABI StringRef getAsSecureLogFile();
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 5afe00eee2242..9667d17e63939 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -24,6 +24,7 @@
#include "llvm/MC/MCSectionSPIRV.h"
#include "llvm/MC/MCSectionWasm.h"
#include "llvm/MC/MCSectionXCOFF.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/TargetParser/Triple.h"
using namespace llvm;
@@ -332,7 +333,6 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) {
TLSExtraDataSection = TLSTLVSection;
}
-
void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
switch (T.getArch()) {
case Triple::mips:
@@ -354,10 +354,15 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
case Triple::ppc64le:
case Triple::aarch64:
case Triple::aarch64_be:
- case Triple::x86_64:
- FDECFIEncoding = dwarf::DW_EH_PE_pcrel |
- (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);
+ case Triple::x86_64: {
+ // Check if the user requested large FDE encoding via MCTargetOptions
+ const MCTargetOptions *TO = Ctx->getTargetOptions();
+ bool Use8ByteFDE = Large || (TO && TO->LargeFDEEncoding);
+ FDECFIEncoding =
+ dwarf::DW_EH_PE_pcrel |
+ (Use8ByteFDE ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);
break;
+ }
case Triple::bpfel:
case Triple::bpfeb:
FDECFIEncoding = dwarf::DW_EH_PE_sdata8;
diff --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp
index be6d19d111620..ff3ce40a555ee 100644
--- a/llvm/lib/MC/MCTargetOptions.cpp
+++ b/llvm/lib/MC/MCTargetOptions.cpp
@@ -20,11 +20,9 @@ MCTargetOptions::MCTargetOptions()
EmitDwarfUnwind(EmitDwarfUnwindType::Default),
MCUseDwarfDirectory(DefaultDwarfDirectory),
EmitCompactUnwindNonCanonical(false), EmitSFrameUnwind(false),
- PPCUseFullRegisterNames(false) {}
+ PPCUseFullRegisterNames(false), LargeFDEEncoding(false) {}
-StringRef MCTargetOptions::getABIName() const {
- return ABIName;
-}
+StringRef MCTargetOptions::getABIName() const { return ABIName; }
StringRef MCTargetOptions::getAssemblyLanguage() const {
return AssemblyLanguage;
diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
index 22494fa11eb2a..8ad5ac02cdaa6 100644
--- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
+++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
@@ -59,6 +59,7 @@ MCOPT(bool, Crel)
MCOPT(bool, ImplicitMapSyms)
MCOPT(bool, X86RelaxRelocations)
MCOPT(bool, X86Sse2Avx)
+MCOPT(bool, LargeFDEEncoding)
MCSTROPT(ABIName)
MCSTROPT(AsSecureLogFile)
@@ -168,6 +169,13 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() {
"instructions with VEX prefix"));
MCBINDOPT(X86Sse2Avx);
+ static cl::opt<bool> LargeFDEEncoding(
+ "large-fde-encoding",
+ cl::desc("Use 8-byte pointer size for ELF FDE CFI encoding, useful "
+ "when text sections may exceed 2GB even with medium code"),
+ cl::init(false));
+ MCBINDOPT(LargeFDEEncoding);
+
static cl::opt<std::string> ABIName(
"target-abi",
cl::desc("The name of the ABI to be targeted from the backend."),
@@ -199,6 +207,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() {
Options.ImplicitMapSyms = getImplicitMapSyms();
Options.X86RelaxRelocations = getX86RelaxRelocations();
Options.X86Sse2Avx = getX86Sse2Avx();
+ Options.LargeFDEEncoding = getLargeFDEEncoding();
Options.EmitDwarfUnwind = getEmitDwarfUnwind();
Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical();
Options.EmitSFrameUnwind = getEmitSFrameUnwind();
|
|
@llvm/pr-subscribers-clang-codegen Author: Farid Zakaria (fzakaria) ChangesMotivationThis is related to #174486 and part of a larger effort to support larger binaries (>2GiB I have a separate change that leverages thunks to support large This can also still occur if a linker script places the
Full diff: https://github.com/llvm/llvm-project/pull/174508.diff 10 Files Affected:
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a1572578fb141..7c71220d16ed9 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -120,6 +120,9 @@ CODEGENOPT(StackSizeSection , 1, 0, Benign) ///< Set when -fstack-size-section
///< Set when -femit-compact-unwind-non-canonical is enabled.
CODEGENOPT(EmitCompactUnwindNonCanonical, 1, 0, Benign)
+///< Set when -flarge-fde-encoding is enabled.
+CODEGENOPT(LargeFDEEncoding, 1, 0, Benign)
+
///< Set when -fxray-always-emit-customevents is enabled.
CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0, Benign)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 04756ce486eaf..555528088676d 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4780,6 +4780,11 @@ defm emit_compact_unwind_non_canonical : BoolFOption<"emit-compact-unwind-non-ca
PosFlag<SetTrue, [], [ClangOption, CC1Option, CC1AsOption],
"Try emitting Compact-Unwind for non-canonical entries. Maybe overridden by other constraints">,
NegFlag<SetFalse>>;
+defm large_fde_encoding : BoolFOption<"large-fde-encoding",
+ CodeGenOpts<"LargeFDEEncoding">, DefaultFalse,
+ PosFlag<SetTrue, [], [ClangOption, CC1Option, CC1AsOption],
+ "Use 8-byte pointers for ELF FDE CFI encoding. Useful when text sections may exceed 2GB">,
+ NegFlag<SetFalse>>;
def g_Flag : Flag<["-"], "g">, Group<g_Group>,
Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>,
HelpText<"Generate source-level debug information">;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e4b64a0c2ff48..20d3d26d9de3d 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -514,6 +514,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
Options.MCOptions.EmitDwarfUnwind = CodeGenOpts.getEmitDwarfUnwind();
Options.MCOptions.EmitCompactUnwindNonCanonical =
CodeGenOpts.EmitCompactUnwindNonCanonical;
+ Options.MCOptions.LargeFDEEncoding = CodeGenOpts.LargeFDEEncoding;
Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
Options.MCOptions.MCUseDwarfDirectory =
diff --git a/clang/test/Driver/flarge-fde-encoding.c b/clang/test/Driver/flarge-fde-encoding.c
new file mode 100644
index 0000000000000..e20da6651f4c8
--- /dev/null
+++ b/clang/test/Driver/flarge-fde-encoding.c
@@ -0,0 +1,10 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang -### --target=x86_64-linux-gnu -flarge-fde-encoding %s 2>&1 | FileCheck %s --check-prefix=POS
+// RUN: %clang -### --target=x86_64-linux-gnu -fno-large-fde-encoding %s 2>&1 | FileCheck %s --check-prefix=NEG
+// RUN: %clang -### --target=x86_64-linux-gnu %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
+
+// POS: "-flarge-fde-encoding"
+// NEG-NOT: "-flarge-fde-encoding"
+// DEFAULT-NOT: "-flarge-fde-encoding"
+
+int dummy;
diff --git a/lld/test/ELF/eh-frame-large-fde-encoding.s b/lld/test/ELF/eh-frame-large-fde-encoding.s
new file mode 100644
index 0000000000000..e374de8444e67
--- /dev/null
+++ b/lld/test/ELF/eh-frame-large-fde-encoding.s
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+
+## Test that demonstrates FDE encoding overflow when .eh_frame is placed
+## far from .text, and the fix using 8-byte (sdata8) FDE encoding.
+##
+## With the default 4-byte FDE encoding (sdata4), a PC-relative offset
+## to .text can overflow if .eh_frame is placed more than 2GB away.
+## Using -large-fde-encoding (or mcmodel=large) switches to 8-byte
+## FDE encoding which can address the full 64-bit address space.
+
+# RUN: rm -rf %t && split-file %s %t
+
+## Test 1: With default sdata4 encoding, placing .eh_frame far from .text
+## causes an overflow error.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu --large-fde-encoding=false \
+# RUN: %t/test.s -o %t/test-small.o
+# RUN: not ld.lld %t/test-small.o -T %t/far.lds -o /dev/null 2>&1 | \
+# RUN: FileCheck %s --check-prefix=OVERFLOW
+
+## Test 2: With sdata8 encoding via -large-fde-encoding, no overflow.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -large-fde-encoding \
+# RUN: %t/test.s -o %t/test-large.o
+# RUN: ld.lld %t/test-large.o -T %t/far.lds -o %t/out
+
+# OVERFLOW: ld.lld: error: <internal>:(.eh_frame+0x{{[0-9a-fA-F]+}}): relocation R_X86_64_PC32 out of range
+
+#--- test.s
+.text
+.globl _start
+.type _start, @function
+_start:
+ .cfi_startproc
+ ret
+ .cfi_endproc
+
+#--- far.lds
+SECTIONS {
+ ## Place .text at a low address
+ . = 0x1000;
+ .text : { *(.text) }
+
+ ## Place .eh_frame more than 2GB away to trigger overflow with sdata4
+ . = 0x100001000;
+ .eh_frame : { *(.eh_frame) }
+}
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 235d58d585b40..da62be369a43c 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -108,6 +108,10 @@ class MCTargetOptions {
// Whether or not to use full register names on PowerPC.
bool PPCUseFullRegisterNames : 1;
+ // Use 8-byte pointer size for ELF FDE CFI encoding, regardless of code model.
+ // Useful when text sections may exceed 2GB even with medium code model
+ bool LargeFDEEncoding : 1;
+
LLVM_ABI MCTargetOptions();
/// getABIName - If this returns a non-empty string this represents the
diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
index 168131b43cca8..beba9f835afeb 100644
--- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
+++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
@@ -63,6 +63,8 @@ LLVM_ABI bool getX86RelaxRelocations();
LLVM_ABI bool getX86Sse2Avx();
+LLVM_ABI bool getLargeFDEEncoding();
+
LLVM_ABI StringRef getABIName();
LLVM_ABI StringRef getAsSecureLogFile();
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 5afe00eee2242..9667d17e63939 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -24,6 +24,7 @@
#include "llvm/MC/MCSectionSPIRV.h"
#include "llvm/MC/MCSectionWasm.h"
#include "llvm/MC/MCSectionXCOFF.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/TargetParser/Triple.h"
using namespace llvm;
@@ -332,7 +333,6 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) {
TLSExtraDataSection = TLSTLVSection;
}
-
void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
switch (T.getArch()) {
case Triple::mips:
@@ -354,10 +354,15 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
case Triple::ppc64le:
case Triple::aarch64:
case Triple::aarch64_be:
- case Triple::x86_64:
- FDECFIEncoding = dwarf::DW_EH_PE_pcrel |
- (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);
+ case Triple::x86_64: {
+ // Check if the user requested large FDE encoding via MCTargetOptions
+ const MCTargetOptions *TO = Ctx->getTargetOptions();
+ bool Use8ByteFDE = Large || (TO && TO->LargeFDEEncoding);
+ FDECFIEncoding =
+ dwarf::DW_EH_PE_pcrel |
+ (Use8ByteFDE ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);
break;
+ }
case Triple::bpfel:
case Triple::bpfeb:
FDECFIEncoding = dwarf::DW_EH_PE_sdata8;
diff --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp
index be6d19d111620..ff3ce40a555ee 100644
--- a/llvm/lib/MC/MCTargetOptions.cpp
+++ b/llvm/lib/MC/MCTargetOptions.cpp
@@ -20,11 +20,9 @@ MCTargetOptions::MCTargetOptions()
EmitDwarfUnwind(EmitDwarfUnwindType::Default),
MCUseDwarfDirectory(DefaultDwarfDirectory),
EmitCompactUnwindNonCanonical(false), EmitSFrameUnwind(false),
- PPCUseFullRegisterNames(false) {}
+ PPCUseFullRegisterNames(false), LargeFDEEncoding(false) {}
-StringRef MCTargetOptions::getABIName() const {
- return ABIName;
-}
+StringRef MCTargetOptions::getABIName() const { return ABIName; }
StringRef MCTargetOptions::getAssemblyLanguage() const {
return AssemblyLanguage;
diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
index 22494fa11eb2a..8ad5ac02cdaa6 100644
--- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
+++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
@@ -59,6 +59,7 @@ MCOPT(bool, Crel)
MCOPT(bool, ImplicitMapSyms)
MCOPT(bool, X86RelaxRelocations)
MCOPT(bool, X86Sse2Avx)
+MCOPT(bool, LargeFDEEncoding)
MCSTROPT(ABIName)
MCSTROPT(AsSecureLogFile)
@@ -168,6 +169,13 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() {
"instructions with VEX prefix"));
MCBINDOPT(X86Sse2Avx);
+ static cl::opt<bool> LargeFDEEncoding(
+ "large-fde-encoding",
+ cl::desc("Use 8-byte pointer size for ELF FDE CFI encoding, useful "
+ "when text sections may exceed 2GB even with medium code"),
+ cl::init(false));
+ MCBINDOPT(LargeFDEEncoding);
+
static cl::opt<std::string> ABIName(
"target-abi",
cl::desc("The name of the ABI to be targeted from the backend."),
@@ -199,6 +207,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() {
Options.ImplicitMapSyms = getImplicitMapSyms();
Options.X86RelaxRelocations = getX86RelaxRelocations();
Options.X86Sse2Avx = getX86Sse2Avx();
+ Options.LargeFDEEncoding = getLargeFDEEncoding();
Options.EmitDwarfUnwind = getEmitDwarfUnwind();
Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical();
Options.EmitSFrameUnwind = getEmitSFrameUnwind();
|
|
@llvm/pr-subscribers-lld Author: Farid Zakaria (fzakaria) ChangesMotivationThis is related to #174486 and part of a larger effort to support larger binaries (>2GiB I have a separate change that leverages thunks to support large This can also still occur if a linker script places the
Full diff: https://github.com/llvm/llvm-project/pull/174508.diff 10 Files Affected:
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a1572578fb141..7c71220d16ed9 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -120,6 +120,9 @@ CODEGENOPT(StackSizeSection , 1, 0, Benign) ///< Set when -fstack-size-section
///< Set when -femit-compact-unwind-non-canonical is enabled.
CODEGENOPT(EmitCompactUnwindNonCanonical, 1, 0, Benign)
+///< Set when -flarge-fde-encoding is enabled.
+CODEGENOPT(LargeFDEEncoding, 1, 0, Benign)
+
///< Set when -fxray-always-emit-customevents is enabled.
CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0, Benign)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 04756ce486eaf..555528088676d 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4780,6 +4780,11 @@ defm emit_compact_unwind_non_canonical : BoolFOption<"emit-compact-unwind-non-ca
PosFlag<SetTrue, [], [ClangOption, CC1Option, CC1AsOption],
"Try emitting Compact-Unwind for non-canonical entries. Maybe overridden by other constraints">,
NegFlag<SetFalse>>;
+defm large_fde_encoding : BoolFOption<"large-fde-encoding",
+ CodeGenOpts<"LargeFDEEncoding">, DefaultFalse,
+ PosFlag<SetTrue, [], [ClangOption, CC1Option, CC1AsOption],
+ "Use 8-byte pointers for ELF FDE CFI encoding. Useful when text sections may exceed 2GB">,
+ NegFlag<SetFalse>>;
def g_Flag : Flag<["-"], "g">, Group<g_Group>,
Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>,
HelpText<"Generate source-level debug information">;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e4b64a0c2ff48..20d3d26d9de3d 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -514,6 +514,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
Options.MCOptions.EmitDwarfUnwind = CodeGenOpts.getEmitDwarfUnwind();
Options.MCOptions.EmitCompactUnwindNonCanonical =
CodeGenOpts.EmitCompactUnwindNonCanonical;
+ Options.MCOptions.LargeFDEEncoding = CodeGenOpts.LargeFDEEncoding;
Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
Options.MCOptions.MCUseDwarfDirectory =
diff --git a/clang/test/Driver/flarge-fde-encoding.c b/clang/test/Driver/flarge-fde-encoding.c
new file mode 100644
index 0000000000000..e20da6651f4c8
--- /dev/null
+++ b/clang/test/Driver/flarge-fde-encoding.c
@@ -0,0 +1,10 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang -### --target=x86_64-linux-gnu -flarge-fde-encoding %s 2>&1 | FileCheck %s --check-prefix=POS
+// RUN: %clang -### --target=x86_64-linux-gnu -fno-large-fde-encoding %s 2>&1 | FileCheck %s --check-prefix=NEG
+// RUN: %clang -### --target=x86_64-linux-gnu %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
+
+// POS: "-flarge-fde-encoding"
+// NEG-NOT: "-flarge-fde-encoding"
+// DEFAULT-NOT: "-flarge-fde-encoding"
+
+int dummy;
diff --git a/lld/test/ELF/eh-frame-large-fde-encoding.s b/lld/test/ELF/eh-frame-large-fde-encoding.s
new file mode 100644
index 0000000000000..e374de8444e67
--- /dev/null
+++ b/lld/test/ELF/eh-frame-large-fde-encoding.s
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+
+## Test that demonstrates FDE encoding overflow when .eh_frame is placed
+## far from .text, and the fix using 8-byte (sdata8) FDE encoding.
+##
+## With the default 4-byte FDE encoding (sdata4), a PC-relative offset
+## to .text can overflow if .eh_frame is placed more than 2GB away.
+## Using -large-fde-encoding (or mcmodel=large) switches to 8-byte
+## FDE encoding which can address the full 64-bit address space.
+
+# RUN: rm -rf %t && split-file %s %t
+
+## Test 1: With default sdata4 encoding, placing .eh_frame far from .text
+## causes an overflow error.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu --large-fde-encoding=false \
+# RUN: %t/test.s -o %t/test-small.o
+# RUN: not ld.lld %t/test-small.o -T %t/far.lds -o /dev/null 2>&1 | \
+# RUN: FileCheck %s --check-prefix=OVERFLOW
+
+## Test 2: With sdata8 encoding via -large-fde-encoding, no overflow.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -large-fde-encoding \
+# RUN: %t/test.s -o %t/test-large.o
+# RUN: ld.lld %t/test-large.o -T %t/far.lds -o %t/out
+
+# OVERFLOW: ld.lld: error: <internal>:(.eh_frame+0x{{[0-9a-fA-F]+}}): relocation R_X86_64_PC32 out of range
+
+#--- test.s
+.text
+.globl _start
+.type _start, @function
+_start:
+ .cfi_startproc
+ ret
+ .cfi_endproc
+
+#--- far.lds
+SECTIONS {
+ ## Place .text at a low address
+ . = 0x1000;
+ .text : { *(.text) }
+
+ ## Place .eh_frame more than 2GB away to trigger overflow with sdata4
+ . = 0x100001000;
+ .eh_frame : { *(.eh_frame) }
+}
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 235d58d585b40..da62be369a43c 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -108,6 +108,10 @@ class MCTargetOptions {
// Whether or not to use full register names on PowerPC.
bool PPCUseFullRegisterNames : 1;
+ // Use 8-byte pointer size for ELF FDE CFI encoding, regardless of code model.
+ // Useful when text sections may exceed 2GB even with medium code model
+ bool LargeFDEEncoding : 1;
+
LLVM_ABI MCTargetOptions();
/// getABIName - If this returns a non-empty string this represents the
diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
index 168131b43cca8..beba9f835afeb 100644
--- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
+++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
@@ -63,6 +63,8 @@ LLVM_ABI bool getX86RelaxRelocations();
LLVM_ABI bool getX86Sse2Avx();
+LLVM_ABI bool getLargeFDEEncoding();
+
LLVM_ABI StringRef getABIName();
LLVM_ABI StringRef getAsSecureLogFile();
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 5afe00eee2242..9667d17e63939 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -24,6 +24,7 @@
#include "llvm/MC/MCSectionSPIRV.h"
#include "llvm/MC/MCSectionWasm.h"
#include "llvm/MC/MCSectionXCOFF.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/TargetParser/Triple.h"
using namespace llvm;
@@ -332,7 +333,6 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) {
TLSExtraDataSection = TLSTLVSection;
}
-
void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
switch (T.getArch()) {
case Triple::mips:
@@ -354,10 +354,15 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
case Triple::ppc64le:
case Triple::aarch64:
case Triple::aarch64_be:
- case Triple::x86_64:
- FDECFIEncoding = dwarf::DW_EH_PE_pcrel |
- (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);
+ case Triple::x86_64: {
+ // Check if the user requested large FDE encoding via MCTargetOptions
+ const MCTargetOptions *TO = Ctx->getTargetOptions();
+ bool Use8ByteFDE = Large || (TO && TO->LargeFDEEncoding);
+ FDECFIEncoding =
+ dwarf::DW_EH_PE_pcrel |
+ (Use8ByteFDE ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);
break;
+ }
case Triple::bpfel:
case Triple::bpfeb:
FDECFIEncoding = dwarf::DW_EH_PE_sdata8;
diff --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp
index be6d19d111620..ff3ce40a555ee 100644
--- a/llvm/lib/MC/MCTargetOptions.cpp
+++ b/llvm/lib/MC/MCTargetOptions.cpp
@@ -20,11 +20,9 @@ MCTargetOptions::MCTargetOptions()
EmitDwarfUnwind(EmitDwarfUnwindType::Default),
MCUseDwarfDirectory(DefaultDwarfDirectory),
EmitCompactUnwindNonCanonical(false), EmitSFrameUnwind(false),
- PPCUseFullRegisterNames(false) {}
+ PPCUseFullRegisterNames(false), LargeFDEEncoding(false) {}
-StringRef MCTargetOptions::getABIName() const {
- return ABIName;
-}
+StringRef MCTargetOptions::getABIName() const { return ABIName; }
StringRef MCTargetOptions::getAssemblyLanguage() const {
return AssemblyLanguage;
diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
index 22494fa11eb2a..8ad5ac02cdaa6 100644
--- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
+++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
@@ -59,6 +59,7 @@ MCOPT(bool, Crel)
MCOPT(bool, ImplicitMapSyms)
MCOPT(bool, X86RelaxRelocations)
MCOPT(bool, X86Sse2Avx)
+MCOPT(bool, LargeFDEEncoding)
MCSTROPT(ABIName)
MCSTROPT(AsSecureLogFile)
@@ -168,6 +169,13 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() {
"instructions with VEX prefix"));
MCBINDOPT(X86Sse2Avx);
+ static cl::opt<bool> LargeFDEEncoding(
+ "large-fde-encoding",
+ cl::desc("Use 8-byte pointer size for ELF FDE CFI encoding, useful "
+ "when text sections may exceed 2GB even with medium code"),
+ cl::init(false));
+ MCBINDOPT(LargeFDEEncoding);
+
static cl::opt<std::string> ABIName(
"target-abi",
cl::desc("The name of the ABI to be targeted from the backend."),
@@ -199,6 +207,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() {
Options.ImplicitMapSyms = getImplicitMapSyms();
Options.X86RelaxRelocations = getX86RelaxRelocations();
Options.X86Sse2Avx = getX86Sse2Avx();
+ Options.LargeFDEEncoding = getLargeFDEEncoding();
Options.EmitDwarfUnwind = getEmitDwarfUnwind();
Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical();
Options.EmitSFrameUnwind = getEmitSFrameUnwind();
|
efriedma-quic
left a comment
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.
Does this work with LTO?
Should we turn this on by default with medium code model?
@efriedma-quic I think it's simpler to just turn on for medium code model but it does come with the additional space consideration which is why I set it as a separate toggle for the initial pass. |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
|
There are clang and llvm MC changes, so applying just the GCC's x86-64 port uses sdata4 with small and medium code models and sdata8 with large. While it's good for clang to keep consistency, an option to switch to sdata8 with medium code model might be useful, since large code model has the long branch penalty. |
|
@MaskRay -- Hi Ray, thanks for taking the time to look at this patch. I am not sure what entails "coordination" with GCC folks. Sending an email to their distribution list to let them know? The lld changes are only a test file but although the changes are specific to If I don't include the clang driver option, this can still be toggle via |
|
Current failure: |
|
I was actually quite interested in exploring this during my final months at the previous emplyer, but unfortunately, I didn't have the chance to implement it at the time. Apologies that I am writing the following in a rush. For better coordiation we should
|
|
@MaskRay is it better to remove the clang driver for now to make progress. What should the discussion be about in the ABI group? I can kickstart it but I am not sure the topic. Appreciate any guidance on how to make progress here. |
|
@MaskRay I removed the clang driver portion for now so it's specific to lld & MC |
Motivation
This is related to #174486 and part of a larger effort to support larger binaries (>2GiB
.text) while still retaining the medium code-model.I have a separate change that leverages thunks to support large
.textand I hit this overflows on the FDE. At the moment the only way around this is the large code model but I want to avoid it.This can also still occur if a linker script places the
.eh_framefar enough from the.textwhich is what the test leverages.