mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 19:49:36 +00:00
[ELF][MIPS] Fix calculation of GP relative relocations in case of relocatable output
Some MIPS relocations depend on "gp" value. By default, this value has 0x7ff0 offset from a .got section. But relocatable files produced by a compiler or a linker might redefine this default value and we have to use it for a calculation of the relocation result. When we generate EXE or DSO it's trivial. Generating a relocatable output is more difficult case because the linker does calculate relocations in this case and cannot store individual "gp" values used by each input object file. As a workaround we add the "gp" value to the relocation addend. This fixes https://llvm.org/pr31149 Differential revision: https://reviews.llvm.org/D45972 llvm-svn: 331772
This commit is contained in:
parent
c7113cc9e4
commit
0560050668
@ -376,17 +376,32 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RelTy::IsRela) {
|
||||
P->r_addend =
|
||||
Sym.getVA(getAddend<ELFT>(Rel)) - Section->getOutputSection()->Addr;
|
||||
} else if (Config->Relocatable) {
|
||||
const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
|
||||
Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset,
|
||||
Target->getImplicitAddend(BufLoc, Type),
|
||||
&Sym});
|
||||
}
|
||||
}
|
||||
int64_t Addend = getAddend<ELFT>(Rel);
|
||||
const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
|
||||
if (!RelTy::IsRela)
|
||||
Addend = Target->getImplicitAddend(BufLoc, Type);
|
||||
|
||||
if (Config->EMachine == EM_MIPS && Config->Relocatable &&
|
||||
Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) {
|
||||
// Some MIPS relocations depend on "gp" value. By default,
|
||||
// this value has 0x7ff0 offset from a .got section. But
|
||||
// relocatable files produced by a complier or a linker
|
||||
// might redefine this default value and we must use it
|
||||
// for a calculation of the relocation result. When we
|
||||
// generate EXE or DSO it's trivial. Generating a relocatable
|
||||
// output is more difficult case because the linker does
|
||||
// not calculate relocations in this mode and loses
|
||||
// individual "gp" values used by each input object file.
|
||||
// As a workaround we add the "gp" value to the relocation
|
||||
// addend and save it back to the file.
|
||||
Addend += Sec->getFile<ELFT>()->MipsGp0;
|
||||
}
|
||||
|
||||
if (RelTy::IsRela)
|
||||
P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr;
|
||||
else if (Config->Relocatable)
|
||||
Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,8 +184,6 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
|
||||
|
||||
auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
|
||||
if (Opt->kind == ODK_REGINFO) {
|
||||
if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
|
||||
error(Filename + ": unsupported non-zero ri_gp_value");
|
||||
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
|
||||
Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
|
||||
break;
|
||||
@ -236,10 +234,8 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
|
||||
error(toString(Sec->File) + ": invalid size of .reginfo section");
|
||||
return nullptr;
|
||||
}
|
||||
auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
|
||||
if (Config->Relocatable && R->ri_gp_value)
|
||||
error(toString(Sec->File) + ": unsupported non-zero ri_gp_value");
|
||||
|
||||
auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
|
||||
Reginfo.ri_gprmask |= R->ri_gprmask;
|
||||
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
|
||||
};
|
||||
|
BIN
lld/test/ELF/Inputs/mips-micro-gp0-non-zero.o
Normal file
BIN
lld/test/ELF/Inputs/mips-micro-gp0-non-zero.o
Normal file
Binary file not shown.
BIN
lld/test/ELF/Inputs/mips-n64-gp0-non-zero.o
Normal file
BIN
lld/test/ELF/Inputs/mips-n64-gp0-non-zero.o
Normal file
Binary file not shown.
@ -1,8 +1,4 @@
|
||||
# Check that relocatable object produced by LLD has zero gp0 value.
|
||||
# Also check an error message if input object file has non-zero gp0 value
|
||||
# and the linker generates a relocatable object.
|
||||
# mips-gp0-non-zero.o is a relocatable object produced from the asm code
|
||||
# below and linked by GNU bfd linker.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
|
||||
# RUN: ld.lld -r -o %t-rel.o %t.o
|
||||
@ -12,9 +8,6 @@
|
||||
# RUN: llvm-readobj -mips-reginfo %t.so | FileCheck --check-prefix=DSO %s
|
||||
# RUN: llvm-objdump -s -t %t.so | FileCheck --check-prefix=DUMP %s
|
||||
|
||||
# RUN: not ld.lld -r -o %t-rel.o %S/Inputs/mips-gp0-non-zero.o 2>&1 \
|
||||
# RUN: | FileCheck --check-prefix=ERR %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
# REL: GP: 0x0
|
||||
@ -31,8 +24,6 @@
|
||||
# DUMP: 00010004 .text 00000000 foo
|
||||
# DUMP: 00027ff0 .got 00000000 .hidden _gp
|
||||
|
||||
# ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value
|
||||
|
||||
.text
|
||||
.global __start
|
||||
__start:
|
||||
|
66
lld/test/ELF/mips-non-zero-gp0.s
Normal file
66
lld/test/ELF/mips-non-zero-gp0.s
Normal file
@ -0,0 +1,66 @@
|
||||
# REQUIRES: mips
|
||||
|
||||
# Check addend adjustment in case of generating a relocatable object
|
||||
# if some input files have non-zero GP0 value.
|
||||
|
||||
# We have to use GNU as and ld.bfd 2.28 to generate relocatable object
|
||||
# files with non-zero GP0 value using the following command lines:
|
||||
#
|
||||
# as -mips32 -o test.o \
|
||||
# && ld.bfd -m elf32btsmip -r test.o -o mips-gp0-non-zero.o
|
||||
# as -mips64 -mmicromips -o test.o \
|
||||
# && ld.bfd -m elf64btsmip -r test.o -o mips-micro-gp0-non-zero.o
|
||||
# as -mips64 -o test.o \
|
||||
# && ld.bfd -m elf64btsmip -r test.o -o mips-n64-gp0-non-zero.o
|
||||
|
||||
# Source code for mips-gp0-non-zero.o:
|
||||
# .text
|
||||
# .global __start
|
||||
# __start:
|
||||
# lw $t0,%call16(__start)($gp)
|
||||
# foo:
|
||||
# nop
|
||||
# bar:
|
||||
# nop
|
||||
#
|
||||
# .section .rodata, "a"
|
||||
# v:
|
||||
# .gpword foo
|
||||
# .gpword bar
|
||||
|
||||
# Source code for mips-n64-gp0-non-zero.o and mips-micro-gp0-non-zero.o:
|
||||
# .text
|
||||
# .global __start
|
||||
# __start:
|
||||
# foo:
|
||||
# lui $gp,%hi(%neg(%gp_rel(foo)))
|
||||
|
||||
# RUN: ld.lld -r -o %t-32.r %S/Inputs/mips-gp0-non-zero.o
|
||||
# RUN: llvm-readobj -mips-reginfo %t-32.r | FileCheck --check-prefix=GPVAL %s
|
||||
# RUN: llvm-objdump -s %t-32.r | FileCheck --check-prefix=ADDEND32 %s
|
||||
|
||||
# RUN: ld.lld -r -o %t-64.r %S/Inputs/mips-n64-gp0-non-zero.o
|
||||
# RUN: llvm-readobj -mips-options %t-64.r | FileCheck --check-prefix=GPVAL %s
|
||||
# RUN: llvm-readobj -r %S/Inputs/mips-n64-gp0-non-zero.o %t-64.r \
|
||||
# RUN: | FileCheck --check-prefix=ADDEND64 %s
|
||||
|
||||
# RUN: ld.lld -r -o %t-micro.r %S/Inputs/mips-micro-gp0-non-zero.o
|
||||
# RUN: llvm-readobj -mips-options %t-micro.r | FileCheck --check-prefix=GPVAL %s
|
||||
# RUN: llvm-readobj -r %S/Inputs/mips-micro-gp0-non-zero.o %t-micro.r \
|
||||
# RUN: | FileCheck --check-prefix=ADDENDMM %s
|
||||
|
||||
# GPVAL: GP: 0x0
|
||||
|
||||
# ADDEND32: Contents of section .rodata:
|
||||
# ADDEND32-NEXT: 0000 00007ff4 00007ff8
|
||||
# ^ 4+GP0 ^ 8+GP0
|
||||
|
||||
# ADDEND64: File: {{.*}}/Inputs/mips-n64-gp0-non-zero.o
|
||||
# ADDEND64: .text 0xFFFFFFFFFFFF8011
|
||||
# ADDEND64: File: {{.*}}/mips-non-zero-gp0.s.tmp-64.r
|
||||
# ADDEND64: .text 0x0
|
||||
|
||||
# ADDENDMM: File: {{.*}}/Inputs/mips-micro-gp0-non-zero.o
|
||||
# ADDENDMM: .text 0xFFFFFFFFFFFF8012
|
||||
# ADDENDMM: File: {{.*}}/mips-non-zero-gp0.s.tmp-micro.r
|
||||
# ADDENDMM: .text 0x1
|
Loading…
Reference in New Issue
Block a user