Skip to content

Commit 894f742

Browse files
committed
[MIPS][ELF] Use PC-relative relocations in .eh_frame when possible
When compiling position-independent executables, we now use DW_EH_PE_pcrel | DW_EH_PE_sdata4. However, the MIPS ABI does not define a 64-bit PC-relative ELF relocation so we cannot use sdata8 for the large code model case. When using the large code model, we fall back to the previous behaviour of generating absolute relocations. With this change clang-generated .o files can be linked by LLD without having to pass -Wl,-z,notext (which creates text relocations). This is simpler than the approach used by ld.bfd, which rewrites the .eh_frame section to convert absolute relocations into relative references. I saw in D13104 that apparently ld.bfd did not accept pc-relative relocations for MIPS ouput at some point. However, I also checked that recent ld.bfd can process the clang-generated .o files so this no longer seems true. Reviewed By: atanasyan Differential Revision: https://reviews.llvm.org/D72228
1 parent 26d2ace commit 894f742

File tree

5 files changed

+148
-41
lines changed

5 files changed

+148
-41
lines changed

lld/test/ELF/mips-eh_frame-pic.s

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# REQUIRES: mips
2+
## Check that we can link a shared library containing an eh_frame section without
3+
## -z notext. This was not possible LLVM started emitting values using the
4+
## DW_EH_PE_pcrel | DW_EH_PE_sdata4 encoding.
5+
6+
## It should not be possible to link code compiled without -fPIC:
7+
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-nopic.o
8+
# RUN: llvm-dwarfdump --eh-frame %t-nopic.o | FileCheck %s --check-prefix=ABS64-EH-FRAME
9+
# RUN: llvm-readobj -r %t-nopic.o | FileCheck %s --check-prefixes=RELOCS,ABS64-RELOCS
10+
# RUN: not ld.lld -shared %t-nopic.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOPIC-ERR
11+
## Note: ld.bfd can link this file because it rewrites the .eh_frame section to use
12+
## relative addressing.
13+
# NOPIC-ERR: ld.lld: error: can't create dynamic relocation R_MIPS_64 against local symbol in readonly segment
14+
15+
## For -fPIC, .eh_frame should contain DW_EH_PE_pcrel | DW_EH_PE_sdata4 values:
16+
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux --position-independent %s -o %t-pic.o
17+
# RUN: llvm-readobj -r %t-pic.o | FileCheck %s --check-prefixes=RELOCS,PIC64-RELOCS
18+
# RUN: ld.lld -shared %t-pic.o -o %t-pic.so
19+
# RUN: llvm-dwarfdump --eh-frame %t-pic.so | FileCheck %s --check-prefix=PIC-EH-FRAME
20+
21+
## Also check MIPS32:
22+
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-nopic32.o
23+
# RUN: llvm-dwarfdump --eh-frame %t-nopic32.o | FileCheck %s --check-prefix=ABS32-EH-FRAME
24+
# RUN: llvm-readobj -r %t-nopic32.o | FileCheck %s --check-prefixes=RELOCS,ABS32-RELOCS
25+
# RUN: not ld.lld -shared %t-nopic32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOPIC32-ERR
26+
## Note: ld.bfd can link this file because it rewrites the .eh_frame section to use
27+
## relative addressing.
28+
# NOPIC32-ERR: ld.lld: error: can't create dynamic relocation R_MIPS_32 against local symbol in readonly segment
29+
30+
## For -fPIC, .eh_frame should contain DW_EH_PE_pcrel | DW_EH_PE_sdata4 values:
31+
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux --position-independent %s -o %t-pic32.o
32+
# RUN: llvm-readobj -r %t-pic32.o | FileCheck %s --check-prefixes=RELOCS,PIC32-RELOCS
33+
# RUN: ld.lld -shared %t-pic32.o -o %t-pic32.so
34+
# RUN: llvm-dwarfdump --eh-frame %t-pic32.so | FileCheck %s --check-prefix=PIC-EH-FRAME
35+
36+
# RELOCS: .rel{{a?}}.eh_frame {
37+
# ABS32-RELOCS-NEXT: 0x1C R_MIPS_32 .text 0x0
38+
# ABS64-RELOCS-NEXT: 0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0
39+
# PIC64-RELOCS-NEXT: 0x1C R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE - 0x0
40+
# PIC32-RELOCS-NEXT: 0x1C R_MIPS_PC32 - 0x0
41+
# RELOCS-NEXT: }
42+
43+
# ABS64-EH-FRAME: Augmentation data: 0C
44+
## ^^ fde pointer encoding: DW_EH_PE_sdata8
45+
# ABS32-EH-FRAME: Augmentation data: 0B
46+
## ^^ fde pointer encoding: DW_EH_PE_sdata4
47+
# PIC-EH-FRAME: Augmentation data: 1B
48+
## ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4
49+
## Note: ld.bfd converts the R_MIPS_64 relocs to DW_EH_PE_pcrel | DW_EH_PE_sdata8
50+
## for N64 ABI (and DW_EH_PE_pcrel | DW_EH_PE_sdata4 for MIPS32)
51+
52+
.ent func
53+
.global func
54+
func:
55+
.cfi_startproc
56+
nop
57+
.cfi_endproc
58+
.end func

llvm/lib/MC/MCObjectFileInfo.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -303,9 +303,14 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
303303
case Triple::mipsel:
304304
case Triple::mips64:
305305
case Triple::mips64el:
306-
FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4
307-
? dwarf::DW_EH_PE_sdata4
308-
: dwarf::DW_EH_PE_sdata8;
306+
// We cannot use DW_EH_PE_sdata8 for the large PositionIndependent case
307+
// since there is no R_MIPS_PC64 relocation (only a 32-bit version).
308+
if (PositionIndependent && !Large)
309+
FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
310+
else
311+
FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4
312+
? dwarf::DW_EH_PE_sdata4
313+
: dwarf::DW_EH_PE_sdata8;
309314
break;
310315
case Triple::ppc64:
311316
case Triple::ppc64le:

llvm/lib/Object/RelocationResolver.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ static bool supportsMips64(uint64_t Type) {
105105
case ELF::R_MIPS_32:
106106
case ELF::R_MIPS_64:
107107
case ELF::R_MIPS_TLS_DTPREL64:
108+
case ELF::R_MIPS_PC32:
108109
return true;
109110
default:
110111
return false;
@@ -119,6 +120,8 @@ static uint64_t resolveMips64(RelocationRef R, uint64_t S, uint64_t A) {
119120
return S + getELFAddend(R);
120121
case ELF::R_MIPS_TLS_DTPREL64:
121122
return S + getELFAddend(R) - 0x8000;
123+
case ELF::R_MIPS_PC32:
124+
return S + getELFAddend(R) - R.getOffset();
122125
default:
123126
llvm_unreachable("Invalid relocation type");
124127
}

llvm/test/DebugInfo/Mips/eh_frame.ll

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=static -O3 -filetype=obj -o - %s | \
2-
; RUN: llvm-readelf -r | FileCheck %s --check-prefix=CHECK-READELF
2+
; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=CHECK-READELF,CHECK-READELF-STATIC
33
; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=pic -O3 -filetype=obj -o - %s | \
4-
; RUN: llvm-readelf -r | FileCheck %s --check-prefix=CHECK-READELF
4+
; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=CHECK-READELF,CHECK-READELF-PIC
55
; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=static -O3 -filetype=obj -o - %s | \
66
; RUN: llvm-objdump -s -j .gcc_except_table - | FileCheck %s --check-prefix=CHECK-EXCEPT-TABLE-STATIC
77
; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=pic -O3 -filetype=obj -o - %s | \
88
; RUN: llvm-objdump -s -j .gcc_except_table - | FileCheck %s --check-prefix=CHECK-EXCEPT-TABLE-PIC
99

1010
; CHECK-READELF: .rel.eh_frame
1111
; CHECK-READELF: DW.ref.__gxx_personality_v0
12-
; CHECK-READELF-NEXT: .text
12+
; CHECK-READELF-STATIC-NEXT: R_MIPS_32 00000000 .text
13+
; CHECK-READELF-PIC-NEXT: R_MIPS_PC32
1314
; CHECK-READELF-NEXT: .gcc_except_table
1415

1516
; CHECK-EXCEPT-TABLE-STATIC: 0000 ff9b1501 0c011500 00150e23 01231e00 ...........#.#..

llvm/test/MC/Mips/eh-frame.s

+75-35
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,96 @@
11
// Test the bits of .eh_frame on mips that are already implemented correctly.
22

33
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips-unknown-linux-gnu
4-
// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefix=REL32 %s
5-
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF32 %s
4+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,ABS32 %s
5+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_ABS %s
66

77
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mipsel-unknown-linux-gnu
8-
// RUN: llvm-objdump -r -section=.rel.eh_frame %t.o | FileCheck --check-prefix=REL32 %s
9-
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF32 %s
8+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,ABS32 %s
9+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_ABS %s
1010

1111
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64-unknown-linux-gnu
12-
// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefix=REL64 %s
13-
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF64 %s
12+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s
13+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s
1414

1515
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64el-unknown-linux-gnu
16-
// RUN: llvm-objdump -r -section=.rela.eh_frame %t.o | FileCheck --check-prefix=REL64 %s
17-
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefix=DWARF64 %s
16+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s
17+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s
18+
19+
/// Check that position-indenpendent code use PC-relative relocations:
20+
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips-unknown-linux-gnu --position-independent
21+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,PIC32 %s
22+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_PIC %s
23+
24+
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mipsel-unknown-linux-gnu --position-independent
25+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,PIC32 %s
26+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF32,DWARF32_PIC %s
27+
28+
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64-unknown-linux-gnu --position-independent
29+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,PIC64 %s
30+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_PIC %s
31+
32+
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64el-unknown-linux-gnu --position-independent
33+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,PIC64 %s
34+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_PIC %s
35+
36+
/// However using the large code model forces R_MIPS_64 since there is no R_MIPS_PC64 relocation:
37+
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64-unknown-linux-gnu --position-independent --large-code-model
38+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s
39+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s
40+
41+
// RUN: llvm-mc -filetype=obj %s -o %t.o -triple mips64el-unknown-linux-gnu --position-independent --large-code-model
42+
// RUN: llvm-readobj -r %t.o | FileCheck --check-prefixes=RELOCS,ABS64 %s
43+
// RUN: llvm-dwarfdump -eh-frame %t.o | FileCheck --check-prefixes=DWARF64,DWARF64_ABS %s
1844

1945
func:
2046
.cfi_startproc
2147
.cfi_endproc
2248

23-
// REL32: R_MIPS_32
24-
// REL64: R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE
49+
// RELOCS: Relocations [
50+
// RELOCS: Section ({{.+}}) .rel{{a?}}.eh_frame {
51+
// ABS32-NEXT: R_MIPS_32
52+
// ABS64-NEXT: R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE
53+
// PIC32-NEXT: R_MIPS_PC32
54+
// PIC64-NEXT: R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE
55+
// RELOCS-NEXT: }
2556

2657
// DWARF32: 00000000 00000010 ffffffff CIE
27-
// DWARF32: Version: 1
28-
// DWARF32: Augmentation: "zR"
29-
// DWARF32: Code alignment factor: 1
30-
// DWARF32: Data alignment factor: -4
31-
// DWARF32: Return address column: 31
32-
// DWARF32: Augmentation data: 0B
33-
// ^^ fde pointer encoding: DW_EH_PE_sdata4
34-
// DWARF32: DW_CFA_def_cfa_register: reg29
58+
// DWARF32-NEXT: Version: 1
59+
// DWARF32-NEXT: Augmentation: "zR"
60+
// DWARF32-NEXT: Code alignment factor: 1
61+
// DWARF32-NEXT: Data alignment factor: -4
62+
// DWARF32-NEXT: Return address column: 31
63+
// DWARF32_ABS-NEXT: Augmentation data: 0B
64+
// ^^ fde pointer encoding: DW_EH_PE_sdata4
65+
// DWARF32_PIC-NEXT: Augmentation data: 1B
66+
// ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4
67+
// DWARF32-EMPTY:
68+
// DWARF32-NEXT: DW_CFA_def_cfa_register: reg29
3569
//
3670
// DWARF32: 00000014 00000010 00000018 FDE cie=00000018 pc=00000000...00000000
37-
// DWARF32: DW_CFA_nop:
38-
// DWARF32: DW_CFA_nop:
39-
// DWARF32: DW_CFA_nop:
71+
// DWARF32-NEXT: DW_CFA_nop:
72+
// DWARF32-NEXT: DW_CFA_nop:
73+
// DWARF32-NEXT: DW_CFA_nop:
74+
4075

4176
// DWARF64: 00000000 00000010 ffffffff CIE
42-
// DWARF64: Version: 1
43-
// DWARF64: Augmentation: "zR"
44-
// DWARF64: Code alignment factor: 1
45-
// DWARF64: Data alignment factor: -8
46-
// ^^ GAS uses -4. Should be ok as long as
47-
// all offsets we need are a multiple of 8.
48-
// DWARF64: Return address column: 31
49-
// DWARF64: Augmentation data: 0C
50-
// ^^ fde pointer encoding: DW_EH_PE_sdata8
51-
// DWARF64: DW_CFA_def_cfa_register: reg29
77+
// DWARF64-NEXT: Version: 1
78+
// DWARF64-NEXT: Augmentation: "zR"
79+
// DWARF64-NEXT: Code alignment factor: 1
80+
// DWARF64-NEXT: Data alignment factor: -8
81+
// ^^ GAS uses -4. Should be ok as long as
82+
// all offsets we need are a multiple of 8.
83+
// DWARF64-NEXT: Return address column: 31
84+
// DWARF64_ABS-NEXT: Augmentation data: 0C
85+
// ^^ fde pointer encoding: DW_EH_PE_sdata8
86+
// DWARF64_PIC: Augmentation data: 1B
87+
// ^^ fde pointer encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4
88+
// DWARF64-EMPTY:
89+
// DWARF64-NEXT: DW_CFA_def_cfa_register: reg29
90+
// DWARF64_PIC-NEXT: DW_CFA_nop:
5291
//
53-
// DWARF64: 00000014 00000018 00000018 FDE cie=00000018 pc=00000000...00000000
54-
// DWARF64: DW_CFA_nop:
55-
// DWARF64: DW_CFA_nop:
56-
// DWARF64: DW_CFA_nop:
92+
// DWARF64_ABS: 00000014 00000018 00000018 FDE cie=00000018 pc=00000000...00000000
93+
// DWARF64_PIC: 00000014 00000010 00000018 FDE cie=00000018 pc=00000000...00000000
94+
// DWARF64-NEXT: DW_CFA_nop:
95+
// DWARF64-NEXT: DW_CFA_nop:
96+
// DWARF64-NEXT: DW_CFA_nop:

0 commit comments

Comments
 (0)