aboutsummaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/Arch/ARM.cpp2
-rw-r--r--lld/ELF/Driver.cpp18
-rw-r--r--lld/ELF/ScriptParser.cpp7
-rw-r--r--lld/ELF/SyntheticSections.cpp7
-rw-r--r--lld/ELF/SyntheticSections.h4
-rw-r--r--lld/ELF/Writer.cpp7
-rw-r--r--lld/MachO/Arch/X86_64.cpp2
-rw-r--r--lld/MachO/BPSectionOrderer.cpp4
-rw-r--r--lld/MachO/Driver.cpp28
-rw-r--r--lld/MachO/InputSection.cpp3
-rw-r--r--lld/MachO/Sections.cpp2
-rw-r--r--lld/test/ELF/aarch64-build-attributes.s10
-rw-r--r--lld/test/ELF/arm-wraparound-veneer.s102
-rw-r--r--lld/test/MachO/bp-section-orderer.s5
-rw-r--r--lld/test/MachO/invalid/bad-offsets.s45
15 files changed, 202 insertions, 44 deletions
diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
index 91a673f..6c4290f 100644
--- a/lld/ELF/Arch/ARM.cpp
+++ b/lld/ELF/Arch/ARM.cpp
@@ -472,7 +472,7 @@ bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
// Bit 0 == 1 denotes Thumb state, it is not part of the range.
dst &= ~0x1;
- int64_t offset = dst - src;
+ int64_t offset = llvm::SignExtend64<32>(dst - src);
switch (type) {
case R_ARM_PC24:
case R_ARM_PLT32:
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index e52d3a0..8647752 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -156,23 +156,23 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(Ctx &ctx,
std::pair<ELFKind, uint16_t> ret =
StringSwitch<std::pair<ELFKind, uint16_t>>(s)
- .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
- .Cases("aarch64elfb", "aarch64linuxb", {ELF64BEKind, EM_AARCH64})
- .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
- .Cases("armelfb", "armelfb_linux_eabi", {ELF32BEKind, EM_ARM})
+ .Cases({"aarch64elf", "aarch64linux"}, {ELF64LEKind, EM_AARCH64})
+ .Cases({"aarch64elfb", "aarch64linuxb"}, {ELF64BEKind, EM_AARCH64})
+ .Cases({"armelf", "armelf_linux_eabi"}, {ELF32LEKind, EM_ARM})
+ .Cases({"armelfb", "armelfb_linux_eabi"}, {ELF32BEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
- .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
- .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+ .Cases({"elf32btsmip", "elf32btsmipn32"}, {ELF32BEKind, EM_MIPS})
+ .Cases({"elf32ltsmip", "elf32ltsmipn32"}, {ELF32LEKind, EM_MIPS})
.Case("elf32lriscv", {ELF32LEKind, EM_RISCV})
- .Cases("elf32ppc", "elf32ppclinux", {ELF32BEKind, EM_PPC})
- .Cases("elf32lppc", "elf32lppclinux", {ELF32LEKind, EM_PPC})
+ .Cases({"elf32ppc", "elf32ppclinux"}, {ELF32BEKind, EM_PPC})
+ .Cases({"elf32lppc", "elf32lppclinux"}, {ELF32LEKind, EM_PPC})
.Case("elf32loongarch", {ELF32LEKind, EM_LOONGARCH})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
.Case("elf64lriscv", {ELF64LEKind, EM_RISCV})
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
.Case("elf64lppc", {ELF64LEKind, EM_PPC64})
- .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
+ .Cases({"elf_amd64", "elf_x86_64"}, {ELF64LEKind, EM_X86_64})
.Case("elf_i386", {ELF32LEKind, EM_386})
.Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
.Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9})
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 4b9c941..b61dc647 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -450,7 +450,7 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) {
.Case("elf64-powerpc", {ELF64BEKind, EM_PPC64})
.Case("elf64-powerpcle", {ELF64LEKind, EM_PPC64})
.Case("elf64-x86-64", {ELF64LEKind, EM_X86_64})
- .Cases("elf32-tradbigmips", "elf32-bigmips", {ELF32BEKind, EM_MIPS})
+ .Cases({"elf32-tradbigmips", "elf32-bigmips"}, {ELF32BEKind, EM_MIPS})
.Case("elf32-ntradbigmips", {ELF32BEKind, EM_MIPS})
.Case("elf32-tradlittlemips", {ELF32LEKind, EM_MIPS})
.Case("elf32-ntradlittlemips", {ELF32LEKind, EM_MIPS})
@@ -463,7 +463,8 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) {
.Case("elf32-loongarch", {ELF32LEKind, EM_LOONGARCH})
.Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH})
.Case("elf64-s390", {ELF64BEKind, EM_S390})
- .Cases("elf32-hexagon", "elf32-littlehexagon", {ELF32LEKind, EM_HEXAGON})
+ .Cases({"elf32-hexagon", "elf32-littlehexagon"},
+ {ELF32LEKind, EM_HEXAGON})
.Default({ELFNoneKind, EM_NONE});
}
@@ -745,7 +746,7 @@ StringMatcher ScriptParser::readFilePatterns() {
SortSectionPolicy ScriptParser::peekSortKind() {
return StringSwitch<SortSectionPolicy>(peek())
.Case("REVERSE", SortSectionPolicy::Reverse)
- .Cases("SORT", "SORT_BY_NAME", SortSectionPolicy::Name)
+ .Cases({"SORT", "SORT_BY_NAME"}, SortSectionPolicy::Name)
.Case("SORT_BY_ALIGNMENT", SortSectionPolicy::Alignment)
.Case("SORT_BY_INIT_PRIORITY", SortSectionPolicy::Priority)
.Case("SORT_NONE", SortSectionPolicy::None)
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index bbf4b29..a4150eb 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2749,14 +2749,13 @@ RelroPaddingSection::RelroPaddingSection(Ctx &ctx)
: SyntheticSection(ctx, ".relro_padding", SHT_NOBITS, SHF_ALLOC | SHF_WRITE,
1) {}
-RandomizePaddingSection::RandomizePaddingSection(Ctx &ctx, uint64_t size,
- OutputSection *parent)
- : SyntheticSection(ctx, ".randomize_padding", SHT_PROGBITS, SHF_ALLOC, 1),
+PaddingSection::PaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent)
+ : SyntheticSection(ctx, ".padding", SHT_PROGBITS, SHF_ALLOC, 1),
size(size) {
this->parent = parent;
}
-void RandomizePaddingSection::writeTo(uint8_t *buf) {
+void PaddingSection::writeTo(uint8_t *buf) {
std::array<uint8_t, 4> filler = getParent()->getFiller(ctx);
uint8_t *end = buf + size;
for (; buf + 4 <= end; buf += 4)
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index ac3ec63..38e6811 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -779,11 +779,11 @@ public:
void writeTo(uint8_t *buf) override {}
};
-class RandomizePaddingSection final : public SyntheticSection {
+class PaddingSection final : public SyntheticSection {
uint64_t size;
public:
- RandomizePaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent);
+ PaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent);
size_t getSize() const override { return size; }
void writeTo(uint8_t *buf) override;
};
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 4fa8039..083b4fb 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1495,15 +1495,14 @@ static void randomizeSectionPadding(Ctx &ctx) {
if (auto *isd = dyn_cast<InputSectionDescription>(bc)) {
SmallVector<InputSection *, 0> tmp;
if (os->ptLoad != curPtLoad) {
- tmp.push_back(make<RandomizePaddingSection>(
- ctx, g() % ctx.arg.maxPageSize, os));
+ tmp.push_back(
+ make<PaddingSection>(ctx, g() % ctx.arg.maxPageSize, os));
curPtLoad = os->ptLoad;
}
for (InputSection *isec : isd->sections) {
// Probability of inserting padding is 1 in 16.
if (g() % 16 == 0)
- tmp.push_back(
- make<RandomizePaddingSection>(ctx, isec->addralign, os));
+ tmp.push_back(make<PaddingSection>(ctx, isec->addralign, os));
tmp.push_back(isec);
}
isd->sections = std::move(tmp);
diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index a7c4b45..111c4d9 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -104,7 +104,7 @@ int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
uint64_t relocVA) const {
if (r.pcrel) {
- uint64_t pc = relocVA + (1 << r.length) + pcrelOffset(r.type);
+ uint64_t pc = relocVA + (1ull << r.length) + pcrelOffset(r.type);
value -= pc;
}
diff --git a/lld/MachO/BPSectionOrderer.cpp b/lld/MachO/BPSectionOrderer.cpp
index d50abc2..328c33e 100644
--- a/lld/MachO/BPSectionOrderer.cpp
+++ b/lld/MachO/BPSectionOrderer.cpp
@@ -118,6 +118,10 @@ DenseMap<const InputSection *, int> lld::macho::runBalancedPartitioning(
auto *isec = subsec.isec;
if (!isec || isec->data.empty() || !isec->data.data())
continue;
+ // CString section order is handled by
+ // {Deduplicated}CStringSection::finalizeContents()
+ if (isa<CStringInputSection>(isec) || isec->isFinal)
+ continue;
// ConcatInputSections are entirely live or dead, so the offset is
// irrelevant.
if (isa<ConcatInputSection>(isec) && !isec->isLive(0))
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 9b67db9..32b2099 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -841,18 +841,18 @@ static PlatformVersion parsePlatformVersion(const Arg *arg) {
// TODO(compnerd) see if we can generate this case list via XMACROS
platformVersion.platform =
StringSwitch<PlatformType>(lowerDash(platformStr))
- .Cases("macos", "1", PLATFORM_MACOS)
- .Cases("ios", "2", PLATFORM_IOS)
- .Cases("tvos", "3", PLATFORM_TVOS)
- .Cases("watchos", "4", PLATFORM_WATCHOS)
- .Cases("bridgeos", "5", PLATFORM_BRIDGEOS)
- .Cases("mac-catalyst", "6", PLATFORM_MACCATALYST)
- .Cases("ios-simulator", "7", PLATFORM_IOSSIMULATOR)
- .Cases("tvos-simulator", "8", PLATFORM_TVOSSIMULATOR)
- .Cases("watchos-simulator", "9", PLATFORM_WATCHOSSIMULATOR)
- .Cases("driverkit", "10", PLATFORM_DRIVERKIT)
- .Cases("xros", "11", PLATFORM_XROS)
- .Cases("xros-simulator", "12", PLATFORM_XROS_SIMULATOR)
+ .Cases({"macos", "1"}, PLATFORM_MACOS)
+ .Cases({"ios", "2"}, PLATFORM_IOS)
+ .Cases({"tvos", "3"}, PLATFORM_TVOS)
+ .Cases({"watchos", "4"}, PLATFORM_WATCHOS)
+ .Cases({"bridgeos", "5"}, PLATFORM_BRIDGEOS)
+ .Cases({"mac-catalyst", "6"}, PLATFORM_MACCATALYST)
+ .Cases({"ios-simulator", "7"}, PLATFORM_IOSSIMULATOR)
+ .Cases({"tvos-simulator", "8"}, PLATFORM_TVOSSIMULATOR)
+ .Cases({"watchos-simulator", "9"}, PLATFORM_WATCHOSSIMULATOR)
+ .Cases({"driverkit", "10"}, PLATFORM_DRIVERKIT)
+ .Cases({"xros", "11"}, PLATFORM_XROS)
+ .Cases({"xros-simulator", "12"}, PLATFORM_XROS_SIMULATOR)
.Default(PLATFORM_UNKNOWN);
if (platformVersion.platform == PLATFORM_UNKNOWN)
error(Twine("malformed platform: ") + platformStr);
@@ -948,7 +948,7 @@ getUndefinedSymbolTreatment(const ArgList &args) {
StringRef treatmentStr = args.getLastArgValue(OPT_undefined);
auto treatment =
StringSwitch<UndefinedSymbolTreatment>(treatmentStr)
- .Cases("error", "", UndefinedSymbolTreatment::error)
+ .Cases({"error", ""}, UndefinedSymbolTreatment::error)
.Case("warning", UndefinedSymbolTreatment::warning)
.Case("suppress", UndefinedSymbolTreatment::suppress)
.Case("dynamic_lookup", UndefinedSymbolTreatment::dynamic_lookup)
@@ -972,7 +972,7 @@ getUndefinedSymbolTreatment(const ArgList &args) {
static ICFLevel getICFLevel(const ArgList &args) {
StringRef icfLevelStr = args.getLastArgValue(OPT_icf_eq);
auto icfLevel = StringSwitch<ICFLevel>(icfLevelStr)
- .Cases("none", "", ICFLevel::none)
+ .Cases({"none", ""}, ICFLevel::none)
.Case("safe", ICFLevel::safe)
.Case("safe_thunks", ICFLevel::safe_thunks)
.Case("all", ICFLevel::all)
diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index b173e14..2b2d28e 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -348,6 +348,9 @@ WordLiteralInputSection::WordLiteralInputSection(const Section &section,
}
uint64_t WordLiteralInputSection::getOffset(uint64_t off) const {
+ if (off >= data.size())
+ fatal(toString(this) + ": offset is outside the section");
+
auto *osec = cast<WordLiteralSection>(parent);
const uintptr_t buf = reinterpret_cast<uintptr_t>(data.data());
switch (sectionType(getFlags())) {
diff --git a/lld/MachO/Sections.cpp b/lld/MachO/Sections.cpp
index a27d902..47169c7 100644
--- a/lld/MachO/Sections.cpp
+++ b/lld/MachO/Sections.cpp
@@ -27,7 +27,7 @@ bool isCodeSection(StringRef name, StringRef segName, uint32_t flags) {
if (segName == segment_names::text)
return StringSwitch<bool>(name)
- .Cases(section_names::textCoalNt, section_names::staticInit, true)
+ .Cases({section_names::textCoalNt, section_names::staticInit}, true)
.Default(false);
return false;
diff --git a/lld/test/ELF/aarch64-build-attributes.s b/lld/test/ELF/aarch64-build-attributes.s
index f2d5421..3d333bf 100644
--- a/lld/test/ELF/aarch64-build-attributes.s
+++ b/lld/test/ELF/aarch64-build-attributes.s
@@ -1,11 +1,11 @@
// REQUIRES: aarch64
// RUN: rm -rf %t && split-file %s %t && cd %t
-// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t1.o
-// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-gcs.s -o %t2.o
-// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-pac.s -o %t3.o
-// RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t.merged.o
-// RUN: llvm-readelf -n %t.merged.o | FileCheck %s --check-prefix=NOTE
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o 1.o
+// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-gcs.s -o 2.o
+// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-pac.s -o 3.o
+// RUN: ld.lld -r 1.o 2.o 3.o -o merged.o
+// RUN: llvm-readelf -n merged.o | FileCheck %s --check-prefix=NOTE
/// This test merges three object files with AArch64 build attributes.
/// All contain identical PAuth ABI info (platform/version), which must be preserved.
diff --git a/lld/test/ELF/arm-wraparound-veneer.s b/lld/test/ELF/arm-wraparound-veneer.s
new file mode 100644
index 0000000..74dd6f2
--- /dev/null
+++ b/lld/test/ELF/arm-wraparound-veneer.s
@@ -0,0 +1,102 @@
+// REQUIRES: arm
+// RUN: rm -rf %t && split-file %s %t && cd %t
+// RUN: llvm-mc -filetype=obj -triple=armv7-none-eabi code.s -o code.o
+// RUN: ld.lld -T unsigned1.ld code.o -o unsigned1.elf
+// RUN: llvm-objdump --triple=armv7 --no-show-raw-insn -d unsigned1.elf | FileCheck %s --check-prefix=UNSIGNED1
+// RUN: ld.lld -T unsigned2.ld code.o -o unsigned2.elf
+// RUN: llvm-objdump --triple=armv7 --no-show-raw-insn -d unsigned2.elf | FileCheck %s --check-prefix=UNSIGNED2
+// RUN: ld.lld -T signed1.ld code.o -o signed1.elf
+// RUN: llvm-objdump --triple=armv7 --no-show-raw-insn -d signed1.elf | FileCheck %s --check-prefix=SIGNED1
+// RUN: ld.lld -T signed2.ld code.o -o signed2.elf
+// RUN: llvm-objdump --triple=armv7 --no-show-raw-insn -d signed2.elf | FileCheck %s --check-prefix=SIGNED2
+
+/// The aim of this test is to ensure that a BL instruction near one end of the
+/// address space can reach a function at the extreme other end, directly,
+/// using a branch offset that makes the address wrap round. We check this at
+/// both the unsigned wraparound point (one address near 0 and the other near
+/// 0xFFFFFFFF) and the signed wraparound point (addresses either side of
+/// 0x80000000), crossing the boundary in both directions. In all four cases we
+/// expect a direct branch with no veneer.
+
+// UNSIGNED1: Disassembly of section .text.lowaddr:
+// UNSIGNED1: <func>:
+// UNSIGNED1: 10000: bx lr
+//
+// UNSIGNED1: Disassembly of section .text.highaddr:
+// UNSIGNED1: <_start>:
+// UNSIGNED1: ffff0000: bl 0x10000
+// UNSIGNED1-NEXT: bx lr
+
+// UNSIGNED2: Disassembly of section .text.lowaddr:
+// UNSIGNED2: <_start>:
+// UNSIGNED2: 10000: bl 0xffff0000
+// UNSIGNED2-NEXT: bx lr
+//
+// UNSIGNED2: Disassembly of section .text.highaddr:
+// UNSIGNED2: <func>:
+// UNSIGNED2: ffff0000: bx lr
+
+// SIGNED1: Disassembly of section .text.posaddr:
+// SIGNED1: <_start>:
+// SIGNED1: 7fff0000: bl 0x80010000
+// SIGNED1-NEXT: bx lr
+//
+// SIGNED1: Disassembly of section .text.negaddr:
+// SIGNED1: <func>:
+// SIGNED1: 80010000: bx lr
+
+// SIGNED2: Disassembly of section .text.posaddr:
+// SIGNED2: <func>:
+// SIGNED2: 7fff0000: bx lr
+//
+// SIGNED2: Disassembly of section .text.negaddr:
+// SIGNED2: <_start>:
+// SIGNED2: 80010000: bl 0x7fff0000
+// SIGNED2-NEXT: bx lr
+
+//--- code.s
+
+ .section .text.callee, "ax", %progbits
+ .global func
+ .type func, %function
+func:
+ bx lr
+
+ .section .text.caller, "ax", %progbits
+ .global _start
+ .type _start, %function
+_start:
+ bl func
+ bx lr
+
+//--- unsigned1.ld
+
+ENTRY(_start)
+SECTIONS {
+ .text.lowaddr 0x00010000 : AT(0x00010000) { *(.text.callee) }
+ .text.highaddr 0xffff0000 : AT(0xffff0000) { *(.text.caller) }
+}
+
+//--- unsigned2.ld
+
+ENTRY(_start)
+SECTIONS {
+ .text.lowaddr 0x00010000 : AT(0x00010000) { *(.text.caller) }
+ .text.highaddr 0xffff0000 : AT(0xffff0000) { *(.text.callee) }
+}
+
+//--- signed1.ld
+
+ENTRY(_start)
+SECTIONS {
+ .text.posaddr 0x7fff0000 : AT(0x7fff0000) { *(.text.caller) }
+ .text.negaddr 0x80010000 : AT(0x80010000) { *(.text.callee) }
+}
+
+//--- signed2.ld
+
+ENTRY(_start)
+SECTIONS {
+ .text.posaddr 0x7fff0000 : AT(0x7fff0000) { *(.text.callee) }
+ .text.negaddr 0x80010000 : AT(0x80010000) { *(.text.caller) }
+}
diff --git a/lld/test/MachO/bp-section-orderer.s b/lld/test/MachO/bp-section-orderer.s
index 90924e5..d7de90d 100644
--- a/lld/test/MachO/bp-section-orderer.s
+++ b/lld/test/MachO/bp-section-orderer.s
@@ -106,6 +106,11 @@ r3:
r4:
.quad s2
+# cstrings are ignored by runBalancedPartitioning()
+.cstring
+cstr:
+ .asciz "this is cstr"
+
.bss
bss0:
.zero 10
diff --git a/lld/test/MachO/invalid/bad-offsets.s b/lld/test/MachO/invalid/bad-offsets.s
new file mode 100644
index 0000000..e1244ee
--- /dev/null
+++ b/lld/test/MachO/invalid/bad-offsets.s
@@ -0,0 +1,45 @@
+## Test that we properly detect and report out-of-bounds offsets in literal sections.
+## We're intentionally testing fatal errors (for malformed input files), and
+## fatal errors aren't supported for testing when main is run twice.
+# XFAIL: main-run-twice
+
+# REQUIRES: x86
+# RUN: rm -rf %t; split-file %s %t
+
+## Test WordLiteralInputSection bounds checking
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/word-literal.s -o %t/word-literal.o
+# RUN: not %lld -dylib %t/word-literal.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=WORD
+
+## Test CStringInputSection bounds checking
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/cstring.s -o %t/cstring.o
+# RUN: not %lld -dylib %t/cstring.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CSTRING
+
+# WORD: error: {{.*}}word-literal.o:(__literal4): offset is outside the section
+# CSTRING: error: {{.*}}cstring.o:(__cstring): offset is outside the section
+
+#--- word-literal.s
+.section __TEXT,__literal4,4byte_literals
+L_literal:
+ .long 0x01020304
+
+.text
+.globl _main
+_main:
+ # We use a subtractor expression to force a section relocation. Symbol relocations
+ # don't trigger the error.
+ .long L_literal - _main + 4
+
+.subsections_via_symbols
+
+#--- cstring.s
+## Create a cstring section with a reference that points past the end
+.cstring
+L_str:
+ .asciz "foo"
+
+.text
+.globl _main
+_main:
+ .long L_str - _main + 4
+
+.subsections_via_symbols \ No newline at end of file