Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions lld/test/ELF/eh-frame-large-fde-encoding.s
Original file line number Diff line number Diff line change
@@ -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) }
}
4 changes: 4 additions & 0 deletions llvm/include/llvm/MC/MCTargetOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ LLVM_ABI bool getX86RelaxRelocations();

LLVM_ABI bool getX86Sse2Avx();

LLVM_ABI bool getLargeFDEEncoding();

LLVM_ABI StringRef getABIName();

LLVM_ABI StringRef getAsSecureLogFile();
Expand Down
13 changes: 9 additions & 4 deletions llvm/lib/MC/MCObjectFileInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand Down
6 changes: 2 additions & 4 deletions llvm/lib/MC/MCTargetOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ MCOPT(bool, Crel)
MCOPT(bool, ImplicitMapSyms)
MCOPT(bool, X86RelaxRelocations)
MCOPT(bool, X86Sse2Avx)
MCOPT(bool, LargeFDEEncoding)
MCSTROPT(ABIName)
MCSTROPT(AsSecureLogFile)

Expand Down Expand Up @@ -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."),
Expand Down Expand Up @@ -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();
Expand Down