From 8a7dae903713e26bb3d328bdfd02662dc73c33da Mon Sep 17 00:00:00 2001 From: Bhoumik Patidar Date: Thu, 24 Sep 2026 02:45:18 +0530 Subject: [PATCH] Support i386 absolute relocations Add the relocation layer for i386 links: R_386_NONE, R_386_8, R_386_16, and R_386_32. Unlike x86-64, i386 uses Elf32_Rel rather than Elf64_Rela. The addend is stored in the field being relocated, so it must be read and sign-extended from that field width before evaluating S + A. Normalize the result to the 32-bit ELF address space before checking narrow fields and writing the result back. This preserves valid full-width 32-bit bit patterns, including addresses with bit 31 set, while rejecting values that cannot be encoded in 8- or 16-bit fields. Signed-off-by: Bhoumik Patidar --- lib/Target/X86/X86_32LDBackend.h | 2 +- lib/Target/X86/X86_32RelocationFunctions.h | 27 +++ lib/Target/X86/X86_32RelocationInfo.h | 59 +++++++ lib/Target/X86/X86_32RelocationTable.h | 70 ++++++++ lib/Target/X86/X86_32Relocator.cpp | 157 +++++++++++++++++- lib/Target/X86/X86_32Relocator.h | 2 + .../AbsoluteRelocation.test | 20 +++ .../AbsoluteRelocation/Inputs/absolute.s | 15 ++ .../AbsoluteRelocation/Inputs/absolute.t | 3 + .../AbsoluteRelocationHighAddress.test | 12 ++ .../Inputs/high-address.s | 5 + .../Inputs/high-address.t | 4 + .../AbsoluteRelocationOverflow.test | 11 ++ .../Inputs/overflow.s | 8 + .../Inputs/overflow.t | 3 + .../AbsoluteRelocationSignExtension.test | 15 ++ .../Inputs/signed.s | 13 ++ .../Inputs/signed.t | 3 + .../AbsoluteRelocationWrap.test | 15 ++ .../Inputs/absolute-wrap.s | 7 + .../Inputs/absolute-wrap.t | 4 + 21 files changed, 446 insertions(+), 9 deletions(-) create mode 100644 lib/Target/X86/X86_32RelocationFunctions.h create mode 100644 lib/Target/X86/X86_32RelocationInfo.h create mode 100644 lib/Target/X86/X86_32RelocationTable.h create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocation/AbsoluteRelocation.test create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.s create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.t create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/AbsoluteRelocationHighAddress.test create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.s create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.t create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/AbsoluteRelocationOverflow.test create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.s create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.t create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/AbsoluteRelocationSignExtension.test create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.s create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.t create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/AbsoluteRelocationWrap.test create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.s create mode 100644 test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.t diff --git a/lib/Target/X86/X86_32LDBackend.h b/lib/Target/X86/X86_32LDBackend.h index 4a4705bbe7..497b363862 100644 --- a/lib/Target/X86/X86_32LDBackend.h +++ b/lib/Target/X86/X86_32LDBackend.h @@ -36,7 +36,7 @@ class X86_32LDBackend : public GNULDBackend { } private: - size_t getRelEntrySize() override { return 0; } + size_t getRelEntrySize() override { return 8; } size_t getRelaEntrySize() override { return 0; } Relocator *m_pRelocator = nullptr; diff --git a/lib/Target/X86/X86_32RelocationFunctions.h b/lib/Target/X86/X86_32RelocationFunctions.h new file mode 100644 index 0000000000..3a2d3a87e6 --- /dev/null +++ b/lib/Target/X86/X86_32RelocationFunctions.h @@ -0,0 +1,27 @@ +//===- X86_32RelocationFunctions.h---------------------------------------===// +// Part of the eld Project, under the BSD License +// See https://github.com/qualcomm/eld/LICENSE.txt for license information. +// SPDX-License-Identifier: BSD-3-Clause +//===----------------------------------------------------------------------===// +#ifndef ELD_TARGET_X86_32_RELOCATION_FUNCTIONS_H +#define ELD_TARGET_X86_32_RELOCATION_FUNCTIONS_H + +#include "X86_32Relocator.h" + +namespace eld { +namespace x86_32 { + +using RelocationHandler = Relocator::Result (*)(Relocation &pReloc, + X86_32Relocator &pParent); + +// R_386_NONE. +Relocator::Result none(Relocation &pReloc, X86_32Relocator &pParent); +// R_386_8, R_386_16, and R_386_32: S + A. +Relocator::Result relocAbs(Relocation &pReloc, X86_32Relocator &pParent); +// Any relocation not implemented by the current i386 backend. +Relocator::Result unsupported(Relocation &pReloc, X86_32Relocator &pParent); + +} // namespace x86_32 +} // namespace eld + +#endif diff --git a/lib/Target/X86/X86_32RelocationInfo.h b/lib/Target/X86/X86_32RelocationInfo.h new file mode 100644 index 0000000000..e624b4db4d --- /dev/null +++ b/lib/Target/X86/X86_32RelocationInfo.h @@ -0,0 +1,59 @@ +//===- X86_32RelocationInfo.h--------------------------------------------===// +// Part of the eld Project, under the BSD License +// See https://github.com/qualcomm/eld/LICENSE.txt for license information. +// SPDX-License-Identifier: BSD-3-Clause +//===----------------------------------------------------------------------===// +// Basic ELD policy types for i386 ELF32 relocations. +// +// The descriptor table is defined in X86_32RelocationTable.h and is indexed by +// the ELF relocation number. +//===----------------------------------------------------------------------===// + +#ifndef ELD_TARGET_X86_32_RELOCATION_INFO_H +#define ELD_TARGET_X86_32_RELOCATION_INFO_H + +#include + +namespace eld { +namespace x86_32 { + +// The width, in bits, of the field an i386 relocation writes into. +enum class EncodingWidth : uint8_t { None, Bits8, Bits16, Bits32 }; + +// No range check is required for a full-width field. Narrow fields accept +// values representable as either signed or unsigned. +enum class RangeCheck { None, SignedOrUnsigned }; + +// Keep the table size tied to LLVM's canonical relocation list. The array may +// contain holes because ELF relocation values are not required to be dense. +inline constexpr uint32_t getRelocationTableSize() { + uint32_t Max = 0; +#define ELF_RELOC(RelocName, Value) \ + if (Value > Max) \ + Max = Value; +#include "llvm/BinaryFormat/ELFRelocs/i386.def" +#undef ELF_RELOC + return Max + 1; +} + +inline constexpr uint32_t RelocationTableSize = getRelocationTableSize(); + +// Number of bits in the field an i386 relocation writes. +inline constexpr unsigned getFieldBits(EncodingWidth Width) { + switch (Width) { + case EncodingWidth::Bits8: + return 8; + case EncodingWidth::Bits16: + return 16; + case EncodingWidth::Bits32: + return 32; + case EncodingWidth::None: + return 0; + } + return 0; +} + +} // namespace x86_32 +} // namespace eld + +#endif diff --git a/lib/Target/X86/X86_32RelocationTable.h b/lib/Target/X86/X86_32RelocationTable.h new file mode 100644 index 0000000000..361731cfd5 --- /dev/null +++ b/lib/Target/X86/X86_32RelocationTable.h @@ -0,0 +1,70 @@ +//===- X86_32RelocationTable.h--------------------------------------------===// +// Part of the eld Project, under the BSD License +// See https://github.com/qualcomm/eld/LICENSE.txt for license information. +// SPDX-License-Identifier: BSD-3-Clause +//===----------------------------------------------------------------------===// +// The i386 relocation descriptor table. +//===----------------------------------------------------------------------===// + +#ifndef ELD_TARGET_X86_32_RELOCATION_TABLE_H +#define ELD_TARGET_X86_32_RELOCATION_TABLE_H + +#include "X86_32RelocationFunctions.h" +#include "X86_32RelocationInfo.h" +#include "llvm/BinaryFormat/ELF.h" + +#include + +namespace eld { +namespace x86_32 { + +struct RelocationDescriptor { + const char *Name = nullptr; + EncodingWidth Width = EncodingWidth::None; + RangeCheck Range = RangeCheck::None; + RelocationHandler Handler = &unsupported; +}; + +// This list contains ELD-specific behavior. Relocation names and numeric +// values come from LLVM's i386.def and are populated separately below. +// clang-format off +#define X86_32_RELOC_OVERRIDES(Add) \ + Add(llvm::ELF::R_386_NONE, none, EncodingWidth::None, RangeCheck::None) \ + Add(llvm::ELF::R_386_32, relocAbs, EncodingWidth::Bits32, RangeCheck::None) \ + Add(llvm::ELF::R_386_16, relocAbs, EncodingWidth::Bits16, \ + RangeCheck::SignedOrUnsigned) \ + Add(llvm::ELF::R_386_8, relocAbs, EncodingWidth::Bits8, \ + RangeCheck::SignedOrUnsigned) +// clang-format on + +inline std::array +createRelocationDescriptors() { + std::array Entries{}; + + // LLVM's i386.def is the source of truth for public relocation names and + // values. Entries not present in that definition remain unnamed and + // unsupported. +#define ELF_RELOC(RelocName, Value) Entries[Value].Name = #RelocName; +#include "llvm/BinaryFormat/ELFRelocs/i386.def" +#undef ELF_RELOC + + // Add the ELD handler and encoding policy for each supported relocation. +#define ADD_X86_32_RELOC_OVERRIDE(Type, Function, FieldWidth, RangePolicy) \ + Entries[Type].Handler = &Function; \ + Entries[Type].Width = FieldWidth; \ + Entries[Type].Range = RangePolicy; + X86_32_RELOC_OVERRIDES(ADD_X86_32_RELOC_OVERRIDE) +#undef ADD_X86_32_RELOC_OVERRIDE + + return Entries; +} + +inline const std::array Relocs = + createRelocationDescriptors(); + +#undef X86_32_RELOC_OVERRIDES + +} // namespace x86_32 +} // namespace eld + +#endif diff --git a/lib/Target/X86/X86_32Relocator.cpp b/lib/Target/X86/X86_32Relocator.cpp index 569d872bbb..e0eb47d55f 100644 --- a/lib/Target/X86/X86_32Relocator.cpp +++ b/lib/Target/X86/X86_32Relocator.cpp @@ -3,28 +3,169 @@ // See https://github.com/qualcomm/eld/LICENSE.txt for license information. // SPDX-License-Identifier: BSD-3-Clause //===----------------------------------------------------------------------===// +// i386 uses Elf32_Rel records: there is no r_addend field, so the addend is +// read from (and the result is written back into) the relocation's target +// field. +//===----------------------------------------------------------------------===// #include "X86_32Relocator.h" +#include "X86_32RelocationTable.h" +#include "eld/Config/LinkerConfig.h" +#include "eld/Diagnostics/DiagnosticEngine.h" +#include "eld/SymbolResolver/LDSymbol.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Support/MathExtras.h" namespace eld { +namespace { + +bool isSupportedRelocation(Relocation::Type Type) { + return Type < x86_32::RelocationTableSize && + x86_32::Relocs[Type].Handler != &x86_32::unsupported; +} + +// i386 is SHT_REL: the addend is stored in the target field itself, sign +// extended from the width of the field it was read from. +Relocator::DWord getImplicitAddend(const Relocation &pReloc) { + const x86_32::RelocationDescriptor &Info = x86_32::Relocs[pReloc.type()]; + const unsigned Bits = x86_32::getFieldBits(Info.Width); + return llvm::SignExtend64(pReloc.target(), Bits) + pReloc.addend(); +} + +// Range-check the computed relocation value and, if it fits, encode it into +// the low bits of the relocation's target field. +Relocator::Result applyRelocationValue(Relocation &pReloc, uint64_t Value, + X86_32Relocator &Parent) { + const x86_32::RelocationDescriptor &Info = x86_32::Relocs[pReloc.type()]; + const unsigned Bits = x86_32::getFieldBits(Info.Width); + // ELF32 relocation expressions wrap at 32 bits before narrow-field checks. + const uint32_t Value32 = static_cast(Value); + const int64_t SignedValue = llvm::SignExtend64(Value32, 32); + if (Info.Range == x86_32::RangeCheck::SignedOrUnsigned) { + if (!llvm::isIntN(Bits, SignedValue) && + !llvm::isUIntN(Bits, static_cast(SignedValue))) { + pReloc.issueSignedOverflow(Parent, SignedValue, llvm::minIntN(Bits), + llvm::maxUIntN(Bits)); + return Relocator::Overflow; + } + } + + const uint32_t Mask = Bits == 32 ? 0xFFFFFFFFU : (1U << Bits) - 1; + pReloc.target() = + (static_cast(pReloc.target()) & ~Mask) | (Value32 & Mask); + return Relocator::OK; +} + +} // namespace + +//===--------------------------------------------------------------------===// +// X86_32Relocator +//===--------------------------------------------------------------------===// X86_32Relocator::X86_32Relocator(X86_32LDBackend &pParent, LinkerConfig &pConfig, Module &pModule) : Relocator(pConfig, pModule), m_Target(pParent) {} -Relocator::Result X86_32Relocator::applyRelocation(Relocation &) { - return Relocator::Unsupport; +Relocator::Result X86_32Relocator::applyRelocation(Relocation &pRelocation) { + const Relocation::Type Type = pRelocation.type(); + if (Type >= x86_32::RelocationTableSize) + return Relocator::Unknown; + + ResolveInfo *SymInfo = pRelocation.symInfo(); + if (SymInfo) { + LDSymbol *OutSymbol = SymInfo->outSymbol(); + if (OutSymbol && OutSymbol->hasFragRef()) { + ELFSection *Section = OutSymbol->fragRef()->frag()->getOwningSection(); + if (Section->isDiscard() || (Section->getOutputSection() && + Section->getOutputSection()->isDiscard())) { + std::lock_guard RelocGuard(m_RelocMutex); + issueUndefRef(pRelocation, *Section->getInputFile(), Section); + return Relocator::OK; + } + } + } + + return x86_32::Relocs[Type].Handler(pRelocation, *this); +} + +void X86_32Relocator::scanRelocation(Relocation &pReloc, eld::IRBuilder &, + ELFSection &pSection, + InputFile &pInputFile, CopyRelocs &) { + if (LinkerConfig::Object == config().codeGenType()) + return; + + if (!isSupportedRelocation(pReloc.type())) { + config().raise(Diag::unsupported_reloc) + << pReloc.type() << pSection.getDecoratedName(config().options()) + << pInputFile.getInput()->decoratedPath(); + return; + } + + ResolveInfo *SymInfo = pReloc.symInfo(); + assert(SymInfo != nullptr && + "ResolveInfo of relocation not set while scanRelocation"); + + if (m_Module.getPrinter()->traceReloc()) { + std::lock_guard RelocGuard(m_RelocMutex); + const std::string RelocName = getName(pReloc.type()); + if (config().options().traceReloc(RelocName)) + config().raise(Diag::reloc_trace) + << RelocName << SymInfo->name() + << pInputFile.getInput()->decoratedPath(); + } + + if (SymInfo->isUndef() || SymInfo->isBitCode()) { + std::lock_guard RelocGuard(m_RelocMutex); + if (m_Target.canIssueUndef(SymInfo)) { + if (SymInfo->visibility() != ResolveInfo::Default) + issueInvisibleRef(pReloc, pInputFile); + issueUndefRef(pReloc, pInputFile, &pSection); + } + } } -void X86_32Relocator::scanRelocation(Relocation &, eld::IRBuilder &, - ELFSection &, InputFile &, CopyRelocs &) {} +const char *X86_32Relocator::getName(Relocation::Type pType) const { + if (pType >= x86_32::RelocationTableSize || !x86_32::Relocs[pType].Name) + return "INVALID_RELOC"; + return x86_32::Relocs[pType].Name; +} + +Relocation::Size X86_32Relocator::getSize(Relocation::Type pType) const { + if (pType >= x86_32::RelocationTableSize) + return 0; + return x86_32::getFieldBits(x86_32::Relocs[pType].Width); +} -const char *X86_32Relocator::getName(Relocation::Type) const { - return ""; +uint32_t X86_32Relocator::getNumRelocs() const { + return x86_32::RelocationTableSize; } -Relocation::Size X86_32Relocator::getSize(Relocation::Type) const { return 0; } +//===--------------------------------------------------------------------===// +// Relocation handlers +//===--------------------------------------------------------------------===// +namespace x86_32 { -uint32_t X86_32Relocator::getNumRelocs() const { return 0; } +Relocator::Result none(Relocation &, X86_32Relocator &) { + return Relocator::OK; +} + +// R_386_8, R_386_16, R_386_32: S + A. +Relocator::Result relocAbs(Relocation &pReloc, X86_32Relocator &pParent) { + Relocator::Address Symbol = pReloc.symValue(pParent.module()); + const Relocator::DWord Addend = getImplicitAddend(pReloc); + ResolveInfo *SymInfo = pReloc.symInfo(); + + // A weak undefined symbol has value zero in a static executable. + if (SymInfo && SymInfo->isWeakUndef() && + pParent.config().codeGenType() == LinkerConfig::Exec) + Symbol = 0; + + return applyRelocationValue(pReloc, Symbol + Addend, pParent); +} + +Relocator::Result unsupported(Relocation &, X86_32Relocator &) { + return Relocator::Unsupport; +} +} // namespace x86_32 } // namespace eld diff --git a/lib/Target/X86/X86_32Relocator.h b/lib/Target/X86/X86_32Relocator.h index 11950e77e3..6736f3a499 100644 --- a/lib/Target/X86/X86_32Relocator.h +++ b/lib/Target/X86/X86_32Relocator.h @@ -11,6 +11,7 @@ #include "X86_32LDBackend.h" #include "eld/Target/Relocator.h" +#include "llvm/BinaryFormat/ELF.h" namespace eld { @@ -31,6 +32,7 @@ class X86_32Relocator : public Relocator { Size getSize(Relocation::Type) const override; uint32_t getNumRelocs() const override; + uint32_t relocType() const override { return llvm::ELF::SHT_REL; } private: X86_32LDBackend &m_Target; diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocation/AbsoluteRelocation.test b/test/X86/i386/standalone/Relocs/AbsoluteRelocation/AbsoluteRelocation.test new file mode 100644 index 0000000000..4f6826b5d2 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocation/AbsoluteRelocation.test @@ -0,0 +1,20 @@ +#---AbsoluteRelocation.test------------ i386 ELF32 relocations -------------# +#BEGIN_COMMENT +# Verify normal i386 absolute relocations use the addend stored in the target +# field and write the expected 8-, 16-, and 32-bit values. +#END_COMMENT +#START_TEST +RUN: %clang -c %p/Inputs/absolute.s -o %t.absolute.o +RUN: %link %linkopts -m elf_i386 -T %p/Inputs/absolute.t %t.absolute.o -o %t.absolute.out +RUN: %readelf -x .text %t.absolute.out | %filecheck %s --check-prefix=BYTES +RUN: %readelf -r %t.absolute.out | %filecheck %s --check-prefix=RELOCS + +# target is at address 8. The in-place addends are 1, 2, and 3. +BYTES: Hex dump of section '.text': +BYTES-NEXT: 0x00000000 090a000b 0000005a 00 + +RELOCS: R_386_8 +RELOCS-NEXT: R_386_16 +RELOCS-NEXT: R_386_32 +RELOCS-NEXT: R_386_NONE +#END_TEST diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.s b/test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.s new file mode 100644 index 0000000000..e3575dff9f --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.s @@ -0,0 +1,15 @@ +.section .text,"ax",@progbits +.globl _start +.type _start,@function +_start: + .byte 0x01 + .value 0x0002 + .long 0x00000003 + .byte 0x5a + .reloc 0, R_386_8, target + .reloc 1, R_386_16, target + .reloc 3, R_386_32, target + .reloc 7, R_386_NONE, target +target: + .byte 0 +.size _start, .-_start diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.t b/test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.t new file mode 100644 index 0000000000..fbed7313dd --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocation/Inputs/absolute.t @@ -0,0 +1,3 @@ +SECTIONS { + .text 0 : { *(.text) } +} diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/AbsoluteRelocationHighAddress.test b/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/AbsoluteRelocationHighAddress.test new file mode 100644 index 0000000000..e43d81fb16 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/AbsoluteRelocationHighAddress.test @@ -0,0 +1,12 @@ +#---AbsoluteRelocationHighAddress.test--- i386 ELF32 relocations ----------# +#BEGIN_COMMENT +# Verify R_386_32 accepts a valid full-width 32-bit address with bit 31 set. +#END_COMMENT +#START_TEST +RUN: %clang -c %p/Inputs/high-address.s -o %t.high-address.o +RUN: %link %linkopts -m elf_i386 -T %p/Inputs/high-address.t %t.high-address.o -o %t.high-address.out +RUN: %readelf -x .text %t.high-address.out | %filecheck %s --check-prefix=HIGH-ADDRESS + +HIGH-ADDRESS: Hex dump of section '.text': +HIGH-ADDRESS-NEXT: 0x00000000 0000ffff +#END_TEST diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.s b/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.s new file mode 100644 index 0000000000..4a61d8936d --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.s @@ -0,0 +1,5 @@ +.section .text,"ax",@progbits +.globl _start +_start: + .long 0 + .reloc 0, R_386_32, target diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.t b/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.t new file mode 100644 index 0000000000..2a1aa5a978 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationHighAddress/Inputs/high-address.t @@ -0,0 +1,4 @@ +SECTIONS { + .text 0 : { *(.text) } + target = 0xffff0000; +} diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/AbsoluteRelocationOverflow.test b/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/AbsoluteRelocationOverflow.test new file mode 100644 index 0000000000..a6dbfccff6 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/AbsoluteRelocationOverflow.test @@ -0,0 +1,11 @@ +#---AbsoluteRelocationOverflow.test------ i386 ELF32 relocations ----------# +#BEGIN_COMMENT +# Verify an absolute relocation is rejected when its value does not fit in +# the narrow relocation field. +#END_COMMENT +#START_TEST +RUN: %clang -c %p/Inputs/overflow.s -o %t.overflow.o +RUN: %not %link %linkopts -m elf_i386 -T %p/Inputs/overflow.t %t.overflow.o -o %t.overflow.out 2>&1 | %filecheck %s --check-prefix=OVERFLOW + +OVERFLOW: {{.*}}R_386_8{{.*}}out of range{{.*}} +#END_TEST diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.s b/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.s new file mode 100644 index 0000000000..6ff389f1f2 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.s @@ -0,0 +1,8 @@ +.section .text,"ax",@progbits +.globl _start +_start: + .byte 0 + .space 0xff + .reloc 0, R_386_8, target +target: + .byte 0 diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.t b/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.t new file mode 100644 index 0000000000..fbed7313dd --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationOverflow/Inputs/overflow.t @@ -0,0 +1,3 @@ +SECTIONS { + .text 0 : { *(.text) } +} diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/AbsoluteRelocationSignExtension.test b/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/AbsoluteRelocationSignExtension.test new file mode 100644 index 0000000000..6d2c1444c9 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/AbsoluteRelocationSignExtension.test @@ -0,0 +1,15 @@ +#---AbsoluteRelocationSignExtension.test-- i386 ELF32 relocations ----------# +#BEGIN_COMMENT +# Verify i386 SHT_REL addends are sign-extended from the relocation field +# width before the absolute relocation is calculated. +#END_COMMENT +#START_TEST +RUN: %clang -c %p/Inputs/signed.s -o %t.signed.o +RUN: %link %linkopts -m elf_i386 -T %p/Inputs/signed.t %t.signed.o -o %t.signed.out +RUN: %readelf -x .text %t.signed.out | %filecheck %s --check-prefix=SIGNED + +# The target is at address 0x83. The in-place addends are -0x80, -0x8000, +# and -1; this checks sign extension of Elf32_Rel addends. +SIGNED: Hex dump of section '.text': +SIGNED-NEXT: 0x0000007c 03838082 00000000 +#END_TEST diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.s b/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.s new file mode 100644 index 0000000000..1288d1bc43 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.s @@ -0,0 +1,13 @@ +.section .text,"ax",@progbits +.globl _start +.type _start,@function +_start: + .byte 0x80 + .value 0x8000 + .long 0xffffffff + .reloc 0, R_386_8, target + .reloc 1, R_386_16, target + .reloc 3, R_386_32, target +target: + .byte 0 +.size _start, .-_start diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.t b/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.t new file mode 100644 index 0000000000..74dd0550a0 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationSignExtension/Inputs/signed.t @@ -0,0 +1,3 @@ +SECTIONS { + .text 0x7c : { *(.text) } +} diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/AbsoluteRelocationWrap.test b/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/AbsoluteRelocationWrap.test new file mode 100644 index 0000000000..91e40e0d52 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/AbsoluteRelocationWrap.test @@ -0,0 +1,15 @@ +#---AbsoluteRelocationWrap.test----------- i386 ELF32 relocations ----------# +#BEGIN_COMMENT +# Verify absolute relocation results are normalized to the ELF32 address +# space before narrow-field checks. +#END_COMMENT +#START_TEST +RUN: %clang -c %p/Inputs/absolute-wrap.s -o %t.absolute-wrap.o +RUN: %link %linkopts -m elf_i386 -T %p/Inputs/absolute-wrap.t %t.absolute-wrap.o -o %t.absolute-wrap.out +RUN: %readelf -x .text %t.absolute-wrap.out | %filecheck %s --check-prefix=WRAP32 + +# Normalize the relocation result to ELF32 before checking +# narrow fields. Both values below therefore wrap to zero and are accepted. +WRAP32: Hex dump of section '.text': +WRAP32-NEXT: 0x00000000 000000 +#END_TEST diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.s b/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.s new file mode 100644 index 0000000000..4556adf99d --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.s @@ -0,0 +1,7 @@ +.section .text,"ax",@progbits +.globl _start +_start: + .byte 0x10 + .value 0x0010 + .reloc 0, R_386_8, target + .reloc 1, R_386_16, target diff --git a/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.t b/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.t new file mode 100644 index 0000000000..cac872e883 --- /dev/null +++ b/test/X86/i386/standalone/Relocs/AbsoluteRelocationWrap/Inputs/absolute-wrap.t @@ -0,0 +1,4 @@ +SECTIONS { + .text 0 : { *(.text) } + target = 0xfffffff0; +}