diff --git a/lld/test/ELF/mips-eh_frame-pic.s b/lld/test/ELF/mips-eh_frame-pic.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/mips-eh_frame-pic.s @@ -0,0 +1,58 @@ +# REQUIRES: mips +## Check that we can link a shared library containing an eh_frame section without +## -z notext. This was not possible LLVM started emitting values using the +## DW_EH_PE_pcrel | DW_EH_PE_sdata4 encoding. + +## It should not be possible to link code compiled without -fPIC: +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-nopic.o +# RUN: llvm-dwarfdump --eh-frame %t-nopic.o | FileCheck %s --check-prefix=ABS64-EH-FRAME +# RUN: llvm-readobj -r %t-nopic.o | FileCheck %s --check-prefixes=RELOCS,ABS64-RELOCS +# RUN: not ld.lld -shared %t-nopic.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOPIC-ERR +## Note: ld.bfd can link this file because it rewrites the .eh_frame section to use +## relative addressing. +# NOPIC-ERR: ld.lld: error: can't create dynamic relocation R_MIPS_64 against local symbol in readonly segment + +## For -fPIC, .eh_frame should contain DW_EH_PE_pcrel | DW_EH_PE_sdata4 values: +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux --position-independent %s -o %t-pic.o +# RUN: llvm-readobj -r %t-pic.o | FileCheck %s --check-prefixes=RELOCS,PIC64-RELOCS +# RUN: ld.lld -shared %t-pic.o -o %t-pic.so +# RUN: llvm-dwarfdump --eh-frame %t-pic.so | FileCheck %s --check-prefix=PIC-EH-FRAME + +## Also check MIPS32: +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-nopic32.o +# RUN: llvm-dwarfdump --eh-frame %t-nopic32.o | FileCheck %s --check-prefix=ABS32-EH-FRAME +# RUN: llvm-readobj -r %t-nopic32.o | FileCheck %s --check-prefixes=RELOCS,ABS32-RELOCS +# RUN: not ld.lld -shared %t-nopic32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOPIC32-ERR +## Note: ld.bfd can link this file because it rewrites the .eh_frame section to use +## relative addressing. +# NOPIC32-ERR: ld.lld: error: can't create dynamic relocation R_MIPS_32 against local symbol in readonly segment + +## 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 +# RUN: ld.lld -shared %t-pic32.o -o %t-pic32.so +# RUN: llvm-dwarfdump --eh-frame %t-pic32.so | FileCheck %s --check-prefix=PIC-EH-FRAME + +# RELOCS: .rel{{a?}}.eh_frame { +# ABS32-RELOCS-NEXT: 0x1C R_MIPS_32 .text 0x0 +# ABS64-RELOCS-NEXT: 0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0 +# PIC64-RELOCS-NEXT: 0x1C R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE - 0x0 +# PIC32-RELOCS-NEXT: 0x1C R_MIPS_PC32 - 0x0 +# RELOCS-NEXT: } + +# ABS64-EH-FRAME: Augmentation data: 0C +## ^^ fde pointer encoding: DW_EH_PE_sdata8 +# ABS32-EH-FRAME: Augmentation data: 0B +## ^^ fde pointer encoding: DW_EH_PE_sdata4 +# PIC-EH-FRAME: Augmentation data: 1B +## ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4 +## 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) + +.ent func +.global func +func: + .cfi_startproc + nop + .cfi_endproc +.end func diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -304,9 +304,14 @@ case Triple::mipsel: case Triple::mips64: case Triple::mips64el: - FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4 - ? dwarf::DW_EH_PE_sdata4 - : dwarf::DW_EH_PE_sdata8; + // We cannot use DW_EH_PE_sdata8 for the large PositionIndependent case + // since there is no R_MIPS_PC64 relocation (only a 32-bit version). + if (PositionIndependent && !Large) + FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + else + FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4 + ? dwarf::DW_EH_PE_sdata4 + : dwarf::DW_EH_PE_sdata8; break; case Triple::ppc64: case Triple::ppc64le: diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp --- a/llvm/lib/Object/RelocationResolver.cpp +++ b/llvm/lib/Object/RelocationResolver.cpp @@ -105,6 +105,7 @@ case ELF::R_MIPS_32: case ELF::R_MIPS_64: case ELF::R_MIPS_TLS_DTPREL64: + case ELF::R_MIPS_PC32: return true; default: return false; @@ -119,6 +120,8 @@ return S + getELFAddend(R); case ELF::R_MIPS_TLS_DTPREL64: return S + getELFAddend(R) - 0x8000; + case ELF::R_MIPS_PC32: + return S + getELFAddend(R) - R.getOffset(); default: llvm_unreachable("Invalid relocation type"); } diff --git a/llvm/test/DebugInfo/Mips/eh_frame.ll b/llvm/test/DebugInfo/Mips/eh_frame.ll --- a/llvm/test/DebugInfo/Mips/eh_frame.ll +++ b/llvm/test/DebugInfo/Mips/eh_frame.ll @@ -1,7 +1,7 @@ ; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=static -O3 -filetype=obj -o - %s | \ -; RUN: llvm-readelf -r | FileCheck %s --check-prefix=CHECK-READELF +; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=CHECK-READELF,CHECK-READELF-STATIC ; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=pic -O3 -filetype=obj -o - %s | \ -; RUN: llvm-readelf -r | FileCheck %s --check-prefix=CHECK-READELF +; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=CHECK-READELF,CHECK-READELF-PIC ; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=static -O3 -filetype=obj -o - %s | \ ; RUN: llvm-objdump -s -j .gcc_except_table - | FileCheck %s --check-prefix=CHECK-EXCEPT-TABLE-STATIC ; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=pic -O3 -filetype=obj -o - %s | \ @@ -9,7 +9,8 @@ ; CHECK-READELF: .rel.eh_frame ; CHECK-READELF: DW.ref.__gxx_personality_v0 -; CHECK-READELF-NEXT: .text +; CHECK-READELF-STATIC-NEXT: R_MIPS_32 00000000 .text +; CHECK-READELF-PIC-NEXT: R_MIPS_PC32 ; CHECK-READELF-NEXT: .gcc_except_table ; CHECK-EXCEPT-TABLE-STATIC: 0000 ff9b1501 0c011500 00150e23 01231e00 ...........#.#.. diff --git a/llvm/test/MC/Mips/eh-frame.s b/llvm/test/MC/Mips/eh-frame.s --- a/llvm/test/MC/Mips/eh-frame.s +++ b/llvm/test/MC/Mips/eh-frame.s @@ -1,56 +1,95 @@ // Test the bits of .eh_frame on mips that are already implemented correctly. // RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips-unknown-linux-gnu -// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefix=REL32 %s -// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF32 %s +// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,ABS32 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_ABS %s // RUN: llvm-mc -filetype=obj %s -o %t.o -triple mipsel-unknown-linux-gnu -// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefix=REL32 %s -// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF32 %s +// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,ABS32 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_ABS %s // RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64-unknown-linux-gnu -// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefix=REL64 %s -// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF64 %s +// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s // RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64el-unknown-linux-gnu -// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefix=REL64 %s -// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF64 %s +// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s + +/// Check that position-indenpendent code use PC-relative relocations: +// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips-unknown-linux-gnu --position-independent +// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,PIC32 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_PIC %s + +// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mipsel-unknown-linux-gnu --position-independent +// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,PIC32 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_PIC %s + +// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64-unknown-linux-gnu --position-independent +// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,PIC64 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_PIC %s + +// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64el-unknown-linux-gnu --position-independent +// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,PIC64 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_PIC %s + +/// However using the large code model forces R_MIPS_64 since there is no R_MIPS_PC64 relocation: +// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64-unknown-linux-gnu --position-independent --large-code-model +// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s + +// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64el-unknown-linux-gnu --position-independent --large-code-model +// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s +// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s func: .cfi_startproc .cfi_endproc -// REL32: R_MIPS_32 -// REL64: R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE +// RELOCS: RELOCATION RECORDS FOR [.eh_frame]: +// ABS32-NEXT: R_MIPS_32 +// ABS64-NEXT: R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE +// PIC32-NEXT: R_MIPS_PC32 +// PIC64-NEXT: R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE +// RELOCS-EMPTY: // DWARF32: 00000000 00000010 ffffffff CIE -// DWARF32: Version: 1 -// DWARF32: Augmentation: "zR" -// DWARF32: Code alignment factor: 1 -// DWARF32: Data alignment factor: -4 -// DWARF32: Return address column: 31 -// DWARF32: Augmentation data: 0B -// ^^ fde pointer encoding: DW_EH_PE_sdata4 -// DWARF32: DW_CFA_def_cfa_register: reg29 +// DWARF32-NEXT: Version: 1 +// DWARF32-NEXT: Augmentation: "zR" +// DWARF32-NEXT: Code alignment factor: 1 +// DWARF32-NEXT: Data alignment factor: -4 +// DWARF32-NEXT: Return address column: 31 +// DWARF32_ABS-NEXT: Augmentation data: 0B +// ^^ fde pointer encoding: DW_EH_PE_sdata4 +// DWARF32_PIC-NEXT: Augmentation data: 1B +// ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4 +// DWARF32-EMPTY: +// DWARF32-NEXT: DW_CFA_def_cfa_register: reg29 // // DWARF32: 00000014 00000010 00000018 FDE cie=00000018 pc=00000000...00000000 -// DWARF32: DW_CFA_nop: -// DWARF32: DW_CFA_nop: -// DWARF32: DW_CFA_nop: +// DWARF32-NEXT: DW_CFA_nop: +// DWARF32-NEXT: DW_CFA_nop: +// DWARF32-NEXT: DW_CFA_nop: + // DWARF64: 00000000 00000010 ffffffff CIE -// DWARF64: Version: 1 -// DWARF64: Augmentation: "zR" -// DWARF64: Code alignment factor: 1 -// DWARF64: Data alignment factor: -8 -// ^^ GAS uses -4. Should be ok as long as -// all offsets we need are a multiple of 8. -// DWARF64: Return address column: 31 -// DWARF64: Augmentation data: 0C -// ^^ fde pointer encoding: DW_EH_PE_sdata8 -// DWARF64: DW_CFA_def_cfa_register: reg29 +// DWARF64-NEXT: Version: 1 +// DWARF64-NEXT: Augmentation: "zR" +// DWARF64-NEXT: Code alignment factor: 1 +// DWARF64-NEXT: Data alignment factor: -8 +// ^^ GAS uses -4. Should be ok as long as +// all offsets we need are a multiple of 8. +// DWARF64-NEXT: Return address column: 31 +// DWARF64_ABS-NEXT: Augmentation data: 0C +// ^^ fde pointer encoding: DW_EH_PE_sdata8 +// DWARF64_PIC: Augmentation data: 1B +// ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4 +// DWARF64-EMPTY: +// DWARF64-NEXT: DW_CFA_def_cfa_register: reg29 +// DWARF64_PIC-NEXT: DW_CFA_nop: // -// DWARF64: 00000014 00000018 00000018 FDE cie=00000018 pc=00000000...00000000 -// DWARF64: DW_CFA_nop: -// DWARF64: DW_CFA_nop: -// DWARF64: DW_CFA_nop: +// DWARF64_ABS: 00000014 00000018 00000018 FDE cie=00000018 pc=00000000...00000000 +// DWARF64_PIC: 00000014 00000010 00000018 FDE cie=00000018 pc=00000000...00000000 +// DWARF64-NEXT: DW_CFA_nop: +// DWARF64-NEXT: DW_CFA_nop: +// DWARF64-NEXT: DW_CFA_nop: