Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -449,9 +449,9 @@ case R_RELAX_TLS_GD_TO_IE_ABS: return Body.getGotVA() + A; case R_GOTONLY_PC: - return InX::Got->getVA() + A - P; + return InX::Got->getVA() + A; case R_GOTONLY_PC_FROM_END: - return InX::Got->getVA() + A - P + InX::Got->getSize(); + return InX::Got->getVA() + A + InX::Got->getSize(); case R_GOTREL: return Body.getVA(A) - InX::Got->getVA(); case R_GOTREL_FROM_END: @@ -463,10 +463,10 @@ return Body.getGotOffset() + A; case R_GOT_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: - return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P); + return getAArch64Page(Body.getGotVA() + A); case R_GOT_PC: case R_RELAX_TLS_GD_TO_IE: - return Body.getGotVA() + A - P; + return Body.getGotVA() + A; case R_HINT: case R_NONE: case R_TLSDESC_CALL: @@ -480,7 +480,7 @@ // is _gp_disp symbol. In that case we should use the following // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - uint64_t V = InX::MipsGot->getGp() + A - P; + uint64_t V = InX::MipsGot->getGp() + A; if (Type == R_MIPS_LO16) V += 4; return V; @@ -511,36 +511,32 @@ Dest = getAArch64Page(A); else Dest = getAArch64Page(Body.getVA(A)); - return Dest - getAArch64Page(P); + return Dest; } - case R_PC: { - uint64_t Dest; + case R_PC: if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) { // On ARM and AArch64 a branch to an undefined weak resolves to the // next instruction, otherwise the place. if (Config->EMachine == EM_ARM) - Dest = getARMUndefinedRelativeWeakVA(Type, A, P); - else if (Config->EMachine == EM_AARCH64) - Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P); - else - Dest = Body.getVA(A); - } else { - Dest = Body.getVA(A); + return getARMUndefinedRelativeWeakVA(Type, A, P); + if (Config->EMachine == EM_AARCH64) + return getAArch64UndefinedRelativeWeakVA(Type, A, P); } - return Dest - P; - } + if (Config->EMachine == EM_386 && Type == R_386_PC16) + return Body.getVA(A) + 2; + return Body.getVA(A); case R_PLT: return Body.getPltVA() + A; case R_PLT_PC: case R_PPC_PLT_OPD: - return Body.getPltVA() + A - P; + return Body.getPltVA() + A; case R_PPC_OPD: { uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol // address of zero. That could overflow, but the code must be unreachable, // so don't bother doing anything at all. if (!SymVA) - return 0; + return P; if (Out::Opd) { // If this is a local call, and we currently have the address of a // function-descriptor, get the underlying code address instead. @@ -550,12 +546,12 @@ if (InOpd) SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]); } - return SymVA - P; + return SymVA; } case R_PPC_TOC: return getPPC64TocBase() + A; case R_RELAX_GOT_PC: - return Body.getVA(A) - P; + return Body.getVA(A); case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_LD_TO_LE: @@ -579,20 +575,138 @@ case R_TLSDESC: return InX::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: - return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A) - - getAArch64Page(P); + return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A); case R_TLSGD: return InX::Got->getGlobalDynOffset(Body) + A - InX::Got->getSize(); case R_TLSGD_PC: - return InX::Got->getGlobalDynAddr(Body) + A - P; + return InX::Got->getGlobalDynAddr(Body) + A; case R_TLSLD: return InX::Got->getTlsIndexOff() + A - InX::Got->getSize(); case R_TLSLD_PC: - return InX::Got->getTlsIndexVA() + A - P; + return InX::Got->getTlsIndexVA() + A; + } + llvm_unreachable("Invalid expression"); +} + +static uint64_t adjustIfPC(uint32_t Type, int64_t T, uint64_t P, + const SymbolBody &Body, RelExpr Expr) { + switch (Expr) { + case R_GOTONLY_PC: + case R_GOTONLY_PC_FROM_END: + case R_GOT_PC: + case R_RELAX_TLS_GD_TO_IE: + case R_MIPS_GOT_GP_PC: + case R_PLT_PC: + case R_PPC_PLT_OPD: + case R_RELAX_GOT_PC: + case R_TLSGD_PC: + case R_TLSLD_PC: + case R_PPC_OPD: + return T - P; + case R_PC: + if (Config->EMachine == EM_386 && Type == R_386_PC16) + return T - P - 2; + return T - P; + case R_RELAX_TLS_GD_TO_IE_PAGE_PC: + case R_GOT_PAGE_PC: + case R_PAGE_PC: + case R_PLT_PAGE_PC: + case R_TLSDESC_PAGE: + return T - getAArch64Page(P); + case R_ABS: + case R_RELAX_GOT_PC_NOPIC: + case R_ARM_SBREL: + case R_GOT: + case R_RELAX_TLS_GD_TO_IE_ABS: + case R_GOTREL: + case R_GOTREL_FROM_END: + case R_GOT_FROM_END: + case R_RELAX_TLS_GD_TO_IE_END: + case R_GOT_OFF: + case R_HINT: + case R_NONE: + case R_TLSDESC_CALL: + case R_MIPS_GOTREL: + case R_MIPS_GOT_GP: + case R_MIPS_GOT_LOCAL_PAGE: + case R_MIPS_GOT_OFF: + case R_MIPS_GOT_OFF32: + case R_MIPS_TLSGD: + case R_MIPS_TLSLD: + case R_PLT: + case R_PPC_TOC: + case R_RELAX_TLS_GD_TO_LE: + case R_RELAX_TLS_IE_TO_LE: + case R_RELAX_TLS_LD_TO_LE: + case R_TLS: + case R_RELAX_TLS_GD_TO_LE_NEG: + case R_NEG_TLS: + case R_SIZE: + case R_TLSDESC: + case R_TLSGD: + case R_TLSLD: + return T; } llvm_unreachable("Invalid expression"); } +template static std::string getErrorLoc(const uint8_t *Loc) { + for (InputSectionBase *D : InputSections) { + auto *IS = dyn_cast_or_null(D); + if (!IS || !IS->getParent()) + continue; + + uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff; + if (ISLoc <= Loc && Loc < ISLoc + IS->getSize()) + return IS->template getLocation(Loc - ISLoc) + ": "; + } + return ""; +} + +static std::string getErrorLocation(const uint8_t *Loc) { + switch (Config->EKind) { + case ELF32LEKind: + return getErrorLoc(Loc); + case ELF32BEKind: + return getErrorLoc(Loc); + case ELF64LEKind: + return getErrorLoc(Loc); + case ELF64BEKind: + return getErrorLoc(Loc); + default: + llvm_unreachable("unknown ELF type"); + } +} + +static void checkInt(uint8_t *Loc, unsigned N, uint64_t V, uint32_t Type) { + if (!isIntN(N, V)) + error(getErrorLocation(Loc) + "relocation " + toString(Type) + + " out of range"); +} + +static void checkUInt(uint8_t *Loc, unsigned N, uint64_t V, uint32_t Type) { + if (!isUIntN(N, V)) + error(getErrorLocation(Loc) + "relocation " + toString(Type) + + " out of range"); +} + +static uint64_t getRelocValue(uint8_t *Loc, uint32_t Type, int64_t A, + uint64_t P, const SymbolBody &Body, + RelExpr Expr) { + uint64_t Dest = getRelocTargetVA(Type, A, P, Body, Expr); + uint64_t Value = adjustIfPC(Type, Dest, P, Body, Expr); + RelOverflow RO = Target->getRelOverflow(Type); + switch (RO.Kind) { + case RelOverflow::FinalValue: + checkInt(Loc, RO.NumBits, Value, Type); + break; + case RelOverflow::TargetValue: + checkUInt(Loc, RO.NumBits, Dest, Type); + break; + } + return Value; +} + // This function applies relocations to sections without SHF_ALLOC bit. // Such sections are never mapped to memory at runtime. Debug sections are // an example. Relocations in non-alloc sections are much easier to @@ -623,7 +737,7 @@ uint64_t SymVA = 0; if (!Sym.isTls() || Out::TlsPhdr) SymVA = SignExtend64( - getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); + getRelocValue(BufLoc, Type, Addend, AddrLoc, Sym, R_ABS)); Target->relocateOne(BufLoc, Type, SymVA); } } @@ -664,7 +778,7 @@ uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; uint64_t TargetVA = SignExtend64( - getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); + getRelocValue(BufLoc, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); switch (Expr) { case R_RELAX_GOT_PC: Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -21,6 +21,11 @@ class InputFile; class SymbolBody; +struct RelOverflow { + unsigned NumBits; + enum { FinalValue, TargetValue } Kind; +}; + class TargetInfo { public: virtual bool isPicRel(uint32_t Type) const { return true; } @@ -53,6 +58,7 @@ const InputFile *File, const SymbolBody &S) const; virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const = 0; + virtual RelOverflow getRelOverflow(uint32_t Type) const = 0; virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0; virtual ~TargetInfo(); Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -121,6 +121,7 @@ X86TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; uint32_t getDynRel(uint32_t Type) const override; @@ -144,6 +145,7 @@ X86_64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; @@ -171,6 +173,7 @@ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; }; class PPC64TargetInfo final : public TargetInfo { @@ -178,6 +181,7 @@ PPC64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; @@ -188,6 +192,7 @@ AArch64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; @@ -208,6 +213,7 @@ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; }; class ARMTargetInfo final : public TargetInfo { @@ -215,6 +221,7 @@ ARMTargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; @@ -235,6 +242,7 @@ MipsTargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; + RelOverflow getRelOverflow(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; @@ -407,6 +415,15 @@ } } +RelOverflow X86TargetInfo::getRelOverflow(uint32_t Type) const { + switch (Type) { + case R_386_PC16: + return {16, RelOverflow::TargetValue}; + } + error("unknown relocation type: " + toString(Type)); + llvm_unreachable("unknown reloc"); +} + RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { switch (Expr) { @@ -537,7 +554,6 @@ write16le(Loc, Val); break; case R_386_PC16: - checkInt<16>(Loc, Val, Type); write16le(Loc, Val); break; default: @@ -704,6 +720,11 @@ } template +RelOverflow X86_64TargetInfo::getRelOverflow(uint32_t Type) const { + llvm_unreachable("foo"); +} + +template void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const { // The first entry holds the value of _DYNAMIC. It is not clear why that is // required, but it is documented in the psabi and the glibc dynamic linker @@ -1091,6 +1112,10 @@ } } +RelOverflow PPCTargetInfo::getRelOverflow(uint32_t Type) const { + llvm_unreachable("foo"); +} + RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { @@ -1141,6 +1166,10 @@ return TocVA + PPC64TocOffset; } +RelOverflow PPC64TargetInfo::getRelOverflow(uint32_t Type) const { + llvm_unreachable("foo"); +} + RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { @@ -1290,6 +1319,10 @@ TcbSize = 16; } +RelOverflow AArch64TargetInfo::getRelOverflow(uint32_t Type) const { + llvm_unreachable("foo"); +} + RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { @@ -1629,6 +1662,10 @@ } } +RelOverflow AMDGPUTargetInfo::getRelOverflow(uint32_t Type) const { + llvm_unreachable("foo"); +} + RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { @@ -1667,6 +1704,10 @@ NeedsThunks = true; } +RelOverflow ARMTargetInfo::getRelOverflow(uint32_t Type) const { + llvm_unreachable("foo"); +} + RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { @@ -2060,6 +2101,11 @@ } template +RelOverflow MipsTargetInfo::getRelOverflow(uint32_t Type) const { + llvm_unreachable("foo"); +} + +template RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. Index: test/ELF/i386-reloc-large-addend.s =================================================================== --- /dev/null +++ test/ELF/i386-reloc-large-addend.s @@ -0,0 +1,15 @@ +// RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj + +// RUN: echo ".global foo; foo = 0x1" > %t1.s +// RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj + +// RUN: ld.lld -Ttext 0x7000 %t.o %t1.o -o %t +// RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t | FileCheck %s + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: _start: +// CHECK-NEXT: 7000: e9 fe 1f jmp 8190 +// 0x1 + 0x9000 - 0x7003 == 8190 + .global _start +_start: +jmp foo + 0x9000 Index: test/ELF/i386-reloc-range.s =================================================================== --- test/ELF/i386-reloc-range.s +++ test/ELF/i386-reloc-range.s @@ -1,8 +1,8 @@ // RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj -// RUN: echo ".global foo; foo = 0x8202" > %t1.s +// RUN: echo ".global foo; foo = 0xffff" > %t1.s // RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj -// RUN: echo ".global foo; foo = 0x8203" > %t2.s +// RUN: echo ".global foo; foo = 0x10000" > %t2.s // RUN: llvm-mc %t2.s -o %t2.o -triple i386-pc-linux -filetype=obj // RUN: ld.lld -Ttext 0x200 %t.o %t1.o -o %t1 @@ -10,8 +10,8 @@ // CHECK: Disassembly of section .text: // CHECK-NEXT: _start: -// CHECK-NEXT: 200: e9 ff 7f jmp 32767 -// 0x8202 - 0x203 == 32767 +// CHECK-NEXT: 200: {{.*}} jmp -516 +// 0xffff - 0x203 == 0xfdfc == -516 // RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o %t2 2>&1 | FileCheck --check-prefix=ERR %s