forked from OSchip/llvm-project
[ELF] Use more specific method to calculate DT_PLTRELSZ
The DT_PLTRELSZ dynamic tag is calculated using the size of the OutputSection containing the In.RelaPlt InputSection. This will work for the default no linker script case and the majority of linker scripts. Unfortunately it doesn't work for some 'almost' sensible linker scripts. It is permitted by ELF to have a single OutputSection containing both In.RelaDyn, In.RelaPlt and In.RelaIPlt. It is also permissible for the range of memory [DT_RELA, DT_RELA + DT_RELASZ) and the range [DT_JMPREL, DT_JMPREL + DT_JMPRELSZ) to overlap as long as the the latter range is at the end. To support this type of linker script use the specific InputSection sizes. Fixes pr39678 Differential Revision: https://reviews.llvm.org/D54759 llvm-svn: 347736
This commit is contained in:
parent
06acb3a236
commit
7dc5af75ae
|
@ -1255,6 +1255,18 @@ void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) {
|
|||
Entries.push_back({Tag, [=] { return Sym->getVA(); }});
|
||||
}
|
||||
|
||||
// A Linker script may assign the RELA relocation sections to the same
|
||||
// output section. When this occurs we cannot just use the OutputSection
|
||||
// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
|
||||
// overlap with the [DT_RELA, DT_RELA + DT_RELASZ).
|
||||
static uint64_t addPltRelSz() {
|
||||
size_t Size = In.RelaPlt->getSize();
|
||||
if (In.RelaIplt->getParent() == In.RelaPlt->getParent() &&
|
||||
In.RelaIplt->Name == In.RelaPlt->Name)
|
||||
Size += In.RelaIplt->getSize();
|
||||
return Size;
|
||||
}
|
||||
|
||||
// Add remaining entries to complete .dynamic contents.
|
||||
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
// Set DT_FLAGS and DT_FLAGS_1.
|
||||
|
@ -1335,7 +1347,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
|||
// .rel[a].plt section.
|
||||
if (In.RelaPlt->getParent()->Live) {
|
||||
addInSec(DT_JMPREL, In.RelaPlt);
|
||||
addSize(DT_PLTRELSZ, In.RelaPlt->getParent());
|
||||
Entries.push_back({DT_PLTRELSZ, addPltRelSz});
|
||||
switch (Config->EMachine) {
|
||||
case EM_MIPS:
|
||||
addInSec(DT_MIPS_PLTGOT, In.GotPlt);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// REQUIRES: AArch64
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/shared.s -o %t-lib.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o
|
||||
// RUN: ld.lld %t-lib.o --shared -o %t.so
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: .text : { *(.text) } \
|
||||
// RUN: .rela.dyn : { *(.rela.dyn) *(.rela.plt) } \
|
||||
// RUN: } " > %t.script
|
||||
// RUN: ld.lld %t.o -o %t.axf %t.so --script %t.script
|
||||
// RUN: llvm-readobj --section-headers --dynamic-table %t.axf | FileCheck %s
|
||||
|
||||
// The linker script above combines the .rela.dyn and .rela.plt into a single
|
||||
// table. ELF is clear that the DT_PLTRELSZ should match the subset of
|
||||
// relocations that is associated with the PLT. It is less clear about what
|
||||
// the value of DT_RELASZ should be. ELF implies that it should be the size
|
||||
// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
|
||||
// glibc permits this as long as .rela.plt comes after .rela.dyn in the
|
||||
// combined table. In the ARM case irelative relocations do not count as PLT
|
||||
// relocs. In the AArch64 case irelative relocations count as PLT relocs.
|
||||
|
||||
.text
|
||||
.globl indirect
|
||||
.type indirect,@gnu_indirect_function
|
||||
indirect:
|
||||
ret
|
||||
|
||||
.globl bar // from Inputs/shared.s
|
||||
|
||||
.text
|
||||
.globl _start
|
||||
.type _start,@function
|
||||
main:
|
||||
bl indirect
|
||||
bl bar
|
||||
adrp x8, :got:indirect
|
||||
ldr x8, [x8, :got_lo12:indirect]
|
||||
adrp x8, :got:bar
|
||||
ldr x8, [x8, :got_lo12:bar]
|
||||
ret
|
||||
|
||||
// CHECK: Name: .rela.dyn
|
||||
// CHECK-NEXT: Type: SHT_RELA
|
||||
// CHECK-NEXT: Flags [
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address:
|
||||
// CHECK-NEXT: Offset:
|
||||
// CHECK-NEXT: Size: 72
|
||||
|
||||
// CHECK: 0x0000000000000008 RELASZ 72
|
||||
// CHECK: 0x0000000000000002 PLTRELSZ 48
|
|
@ -0,0 +1,41 @@
|
|||
// REQUIRES: AArch64
|
||||
// RUN: llvm-mc --triple=aarch64-linux-gnu -filetype=obj -o %t.o %s
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: .text : { *(.text) } \
|
||||
// RUN: .rela.dyn : { *(.rela.dyn) *(.rela.plt) } \
|
||||
// RUN: } " > %t.script
|
||||
// RUN: ld.lld %t.o -o %t.so --shared --script %t.script
|
||||
// RUN: llvm-readobj --section-headers --dynamic-table %t.so | FileCheck %s
|
||||
|
||||
// The linker script above combines the .rela.dyn and .rela.plt into a single
|
||||
// table. ELF is clear that the DT_PLTRELSZ should match the subset of
|
||||
// relocations that is associated with the PLT. It is less clear about what
|
||||
// the value of DT_RELASZ should be. ELF implies that it should be the size
|
||||
// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
|
||||
// glibc permits this as long as .rela.plt comes after .rela.dyn in the
|
||||
// combined table.
|
||||
.text
|
||||
.globl func
|
||||
.type func, %function
|
||||
.globl foo
|
||||
.type foo, %object
|
||||
|
||||
.globl _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
bl func
|
||||
adrp x8, :got:foo
|
||||
ldr x8, [x8, :got_lo12:foo]
|
||||
ret
|
||||
|
||||
// CHECK: Name: .rela.dyn
|
||||
// CHECK-NEXT: Type: SHT_RELA
|
||||
// CHECK-NEXT: Flags [
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address:
|
||||
// CHECK-NEXT: Offset:
|
||||
// CHECK-NEXT: Size: 48
|
||||
|
||||
// CHECK: 0x0000000000000008 RELASZ 48
|
||||
// CHECK: 0x0000000000000002 PLTRELSZ 24
|
|
@ -0,0 +1,49 @@
|
|||
// REQUIRES: arm
|
||||
// RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-linux-gnueabihf %p/Inputs/arm-shared.s -o %t-lib.o
|
||||
// RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-linux-gnueabihf %s -o %t.o
|
||||
// RUN: ld.lld %t-lib.o --shared -o %t.so
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: .text : { *(.text) } \
|
||||
// RUN: .rela.dyn : { *(.rel.dyn) *(.rel.plt) } \
|
||||
// RUN: } " > %t.script
|
||||
// RUN: ld.lld %t.o -o %t.axf %t.so --script %t.script
|
||||
// RUN: llvm-readobj --section-headers --dynamic-table %t.axf | FileCheck %s
|
||||
|
||||
// The linker script above combines the .rela.dyn and .rela.plt into a single
|
||||
// table. ELF is clear that the DT_PLTRELSZ should match the subset of
|
||||
// relocations that is associated with the PLT. It is less clear about what
|
||||
// the value of DT_RELASZ should be. ELF implies that it should be the size
|
||||
// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
|
||||
// glibc permits this as long as .rela.plt comes after .rela.dyn in the
|
||||
// combined table. In the ARM case irelative relocations do not count as PLT
|
||||
// relocs.
|
||||
|
||||
.text
|
||||
.globl indirect
|
||||
.type indirect,%gnu_indirect_function
|
||||
indirect:
|
||||
bx lr
|
||||
|
||||
.globl bar2 // from Inputs/arm-shared.s
|
||||
|
||||
.text
|
||||
.globl _start
|
||||
.type _start,%function
|
||||
main:
|
||||
bl indirect
|
||||
bl bar2
|
||||
.word indirect(got)
|
||||
.word bar2(got)
|
||||
bx lr
|
||||
|
||||
// CHECK: Name: .rela.dyn
|
||||
// CHECK-NEXT: Type: SHT_REL
|
||||
// CHECK-NEXT: Flags [
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address:
|
||||
// CHECK-NEXT: Offset:
|
||||
// CHECK-NEXT: Size: 24
|
||||
|
||||
// CHECK: 0x00000012 RELSZ 24 (bytes)
|
||||
// CHECK: 0x00000002 PLTRELSZ 8 (bytes)
|
|
@ -0,0 +1,40 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc --triple=x86_64-pc-linux -filetype=obj -o %t.o %s
|
||||
# RUN: echo "SECTIONS { \
|
||||
# RUN: .text : { *(.text) } \
|
||||
# RUN: .rela.dyn : { *(.rela.dyn) *(.rela.plt) } \
|
||||
# RUN: } " > %t.script
|
||||
# RUN: ld.lld %t.o -o %t.so --shared --script %t.script
|
||||
# RUN: llvm-readobj --section-headers --dynamic-table %t.so | FileCheck %s
|
||||
|
||||
// The linker script above combines the .rela.dyn and .rela.plt into a single
|
||||
// table. ELF is clear that the DT_PLTRELSZ should match the subset of
|
||||
// relocations that is associated with the PLT. It is less clear about what
|
||||
// the value of DT_RELASZ should be. ELF implies that it should be the size
|
||||
// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
|
||||
// glibc permits this as long as .rela.plt comes after .rela.dyn in the
|
||||
// combined table.
|
||||
|
||||
.text
|
||||
.globl func
|
||||
.type func, %function
|
||||
.globl foo
|
||||
.type foo, %object
|
||||
|
||||
.globl _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
call func@plt
|
||||
movq func@GOTPCREL (%rip), %rax
|
||||
|
||||
# CHECK: Name: .rela.dyn
|
||||
# CHECK-NEXT: Type: SHT_RELA
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 48
|
||||
|
||||
# CHECK: 0x0000000000000008 RELASZ 48
|
||||
# CHECK: 0x0000000000000002 PLTRELSZ 24
|
Loading…
Reference in New Issue