Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -79,7 +79,7 @@ size_t NumFdes = 0; struct FdeData { - uint32_t Pc; + uint64_t Pc; uint32_t FdeVA; }; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -502,14 +502,16 @@ uint8_t *Buf = getParent()->Loc + OutSecOff; std::vector Ret; + uint64_t VA = InX::EhFrameHdr->getVA(); for (CieRecord *Rec : CieRecords) { uint8_t Enc = getFdeEncoding(Rec->Cie); for (EhSectionPiece *Fde : Rec->Fdes) { uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); - if (Pc > UINT32_MAX) - fatal(toString(Fde->Sec) + ": PC address is too large: " + Twine(Pc)); + if (Pc - VA != (uint64_t)signExtend(Pc - VA, 32)) + fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" + + Twine::utohexstr(Pc - VA)); uint32_t FdeVA = getParent()->Addr + Fde->OutputOff; - Ret.push_back({(uint32_t)Pc, FdeVA}); + Ret.push_back({Pc, FdeVA}); } } return Ret; Index: test/ELF/Inputs/eh-frame-pcrel-overflow.s =================================================================== --- /dev/null +++ test/ELF/Inputs/eh-frame-pcrel-overflow.s @@ -0,0 +1,25 @@ +.text +.global foo +foo: + ret + +.section .eh_frame, "a" + .long 12 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x52 # Augmentation string: 'R','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x00 # DW_EH_PE_absptr + + .byte 0xFF + + .long 12 # Size + .long 0x14 # ID + .quad foo + 0x90000000 Index: test/ELF/eh-frame-pcaddr-overflow.s =================================================================== --- test/ELF/eh-frame-pcaddr-overflow.s +++ /dev/null @@ -1,32 +0,0 @@ -# REQUIRES: x86 - -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: not ld.lld --eh-frame-hdr --section-start .text=0x1000000000000000 \ -# RUN: %t.o -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: {{.*}}.o:(.eh_frame): PC address is too large: 2387527121043355528 - -.text -.global foo -foo: - nop - -.section .eh_frame, "a" - .long 12 # Size - .long 0x00 # ID - .byte 0x01 # Version. - - .byte 0x52 # Augmentation string: 'R','\0' - .byte 0x00 - - .byte 0x01 - - .byte 0x01 # LEB128 - .byte 0x01 # LEB128 - - .byte 0x00 # DW_EH_PE_absptr - - .byte 0xFF - - .long 12 # Size - .long 0x14 # ID - .quad foo + 0x1122334455667788 Index: test/ELF/eh-frame-pcrel-overflow.s =================================================================== --- /dev/null +++ test/ELF/eh-frame-pcrel-overflow.s @@ -0,0 +1,33 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/eh-frame-pcrel-overflow.s -o %t1.o +# RUN: ld.lld --eh-frame-hdr -Ttext=0x90000000 %t.o -o /dev/null +# RUN: not ld.lld --eh-frame-hdr %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s +# CHECK: error: {{.*}}.o:(.eh_frame): PC offset is too large: 0x90000eac + +.text +.global _start +_start: + ret + +.section .eh_frame, "a" + .long 12 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x52 # Augmentation string: 'R','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x00 # DW_EH_PE_absptr + + .byte 0xFF + + .long 12 # Size + .long 0x14 # ID + .quad _start + 0x70000000