Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_CONFIG_H #define LLD_ELF_CONFIG_H +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" @@ -240,6 +241,12 @@ // The only instance of Configuration struct. extern Configuration *Config; +static inline void errorOrWarn(const Twine &Msg) { + if (!Config->NoinhibitExec) + error(Msg); + else + warn(Msg); +} } // namespace elf } // namespace lld Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -534,13 +534,6 @@ InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, &SS, 0}); } -static void errorOrWarn(const Twine &Msg) { - if (!Config->NoinhibitExec) - error(Msg); - else - warn(Msg); -} - // MIPS has an odd notion of "paired" relocations to calculate addends. // For example, if a relocation is of R_MIPS_HI16, there must be a // R_MIPS_LO16 relocation after that, and an addend is calculated using Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -62,6 +62,7 @@ void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); + void checkNoOverlappingSections(); void fixSectionAlignments(); void openFile(); void writeTrapInstr(); @@ -454,6 +455,8 @@ Sec->Addr = 0; } + checkNoOverlappingSections(); + // It does not make sense try to open the file if we have error already. if (errorCount()) return; @@ -1903,6 +1906,103 @@ } } +static std::string rangeToString(uint64_t Addr, uint64_t Len) { + if (Len == 0) + return ""; + return "[0x" + utohexstr(Addr) + " -> 0x" + + utohexstr(Addr + Len - 1) + "]"; +} + +// Check whether sections overlap for a specific address range (file offsets, +// load and virtual adresses). +// +// This is a helper function called by Writer::checkNoOverlappingSections(). +template +static void checkForSectionOverlap(ArrayRef AllSections, + StringRef Kind, Getter GetStart, + Predicate ShouldSkip) { + std::vector Sections; + // By removing all zero-size sections we can simplify the check for overlap to + // just checking whether the section range contains the other section's start + // address. Additionally, it also slightly speeds up the checking since we + // don't bother checking for overlap with sections that can never overlap. + for (OutputSection *Sec : AllSections) + if (Sec->Size > 0 && !ShouldSkip(Sec)) + Sections.push_back(Sec); + + // Instead of comparing every OutputSection with every other output section + // we sort the sections by address (file offset or load/virtual address). This + // way we find all overlapping sections but only need one comparision with the + // next section in the common non-overlapping case. The only time we end up + // doing more than one iteration of the following nested loop is if there are + // overlapping sections. + std::sort(Sections.begin(), Sections.end(), + [=](const OutputSection *A, const OutputSection *B) { + return GetStart(A) < GetStart(B); + }); + for (size_t i = 0; i < Sections.size(); ++i) { + OutputSection *Sec = Sections[i]; + uint64_t Start = GetStart(Sec); + for (auto *Other : ArrayRef(Sections).slice(i + 1)) { + // Since the sections are storted by start address we only need to check + // whether the other sections starts before the end of Sec. If this is + // not the case we can break out of this loop since all following sections + // will also start after the end of Sec. + if (Start + Sec->Size <= GetStart(Other)) + break; + errorOrWarn("section " + Sec->Name + " " + Kind + + " range overlaps with " + Other->Name + "\n>>> " + Sec->Name + + " range is " + rangeToString(Start, Sec->Size) + "\n>>> " + + Other->Name + " range is " + + rangeToString(GetStart(Other), Other->Size)); + } + } +} + +// Check for overlapping sections +// +// In this function we check that none of the output sections have overlapping +// file offsets. For SHF_ALLOC sections we also check that the load address +// ranges and the virtual address ranges don't overlap +template void Writer::checkNoOverlappingSections() { + // First check for overlapping file offsets. In this case we need to skip + // Any section marked as SHT_NOBITS. These sections don't actually occupy + // space in the file so Sec->Offset + Sec->Size can overlap with others. + // If --oformat binary is specified only add SHF_ALLOC sections are added to + // the output file so we skip any non-allocated sections in that case. + checkForSectionOverlap( + OutputSections, "file", [](const OutputSection *Sec) { return Sec->Offset; }, + [](const OutputSection *Sec) { + return Sec->Type == SHT_NOBITS || + (Config->OFormatBinary && (Sec->Flags & SHF_ALLOC) == 0); + }); + + // When linking with -r there is no need to check for overlapping virtual/load + // addresses since those addresses will only be assigned when the final + // executable/shared object is created. + if (Config->Relocatable) + return; + + // Checking for overlapping virtual and load addresses only needs to take + // into account SHF_ALLOC sections since since others will not be loaded. + // Furthermore, we also need to skip SHF_TLS sections since these will be + // mapped to other addresses at runtime and can therefore have overlapping + // ranges in the file. + auto SkipNonAllocSections = [](const OutputSection *Sec) { + return (Sec->Flags & SHF_ALLOC) == 0 || (Sec->Flags & SHF_TLS); + }; + checkForSectionOverlap(OutputSections, "virtual address", + [](const OutputSection *Sec) { return Sec->Addr; }, + SkipNonAllocSections); + + // Finally, check that the load addresses don't overlap. This will usually be + // the same as the virtual addresses but can be different when using a linker + // script with AT(). + checkForSectionOverlap(OutputSections, "load address", + [](const OutputSection *Sec) { return Sec->getLMA(); }, + SkipNonAllocSections); +} + // The entry point address is chosen in the following ways. // // 1. the '-e' entry command-line option; Index: lld/trunk/test/ELF/arm-thumb-interwork-thunk.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-interwork-thunk.s +++ lld/trunk/test/ELF/arm-thumb-interwork-thunk.s @@ -8,7 +8,7 @@ // RUN: .thumb_caller : { *(.thumb_caller) } \ // RUN: .R_ARM_JUMP24_callee_2 : { *(.R_ARM_JUMP24_callee_high) } \ // RUN: .R_ARM_THM_JUMP_callee_2 : { *(.R_ARM_THM_JUMP_callee_high) } \ -// RUN: .got.plt 0x1894 : { } } " > %t.script +// RUN: .got.plt 0x18b4 : { } } " > %t.script // RUN: ld.lld --script %t.script %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-ABS-THUMB %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-ABS-ARM %s @@ -368,11 +368,11 @@ // CHECK-PI-ARM-PLT-NEXT: 183c: 00 f0 9c e5 ldr pc, [r12] // CHECK-PI-ARM-PLT-NEXT: 1840: 7c 00 00 00 -// CHECK-DSO-REL: 0x18A0 R_ARM_JUMP_SLOT arm_caller -// CHECK-DSO-REL-NEXT: 0x18A4 R_ARM_JUMP_SLOT thumb_caller -// CHECK-DSO-REL-NEXT: 0x18A8 R_ARM_JUMP_SLOT thumb_callee1 -// CHECK-DSO-REL-NEXT: 0x18AC R_ARM_JUMP_SLOT thumb_callee2 -// CHECK-DSO-REL-NEXT: 0x18B0 R_ARM_JUMP_SLOT thumb_callee3 -// CHECK-DSO-REL-NEXT: 0x18B4 R_ARM_JUMP_SLOT arm_callee1 -// CHECK-DSO-REL-NEXT: 0x18B8 R_ARM_JUMP_SLOT arm_callee2 -// CHECK-DSO-REL-NEXT: 0x18BC R_ARM_JUMP_SLOT arm_callee3 +// CHECK-DSO-REL: 0x18C0 R_ARM_JUMP_SLOT arm_caller +// CHECK-DSO-REL-NEXT: 0x18C4 R_ARM_JUMP_SLOT thumb_caller +// CHECK-DSO-REL-NEXT: 0x18C8 R_ARM_JUMP_SLOT thumb_callee1 +// CHECK-DSO-REL-NEXT: 0x18CC R_ARM_JUMP_SLOT thumb_callee2 +// CHECK-DSO-REL-NEXT: 0x18D0 R_ARM_JUMP_SLOT thumb_callee3 +// CHECK-DSO-REL-NEXT: 0x18D4 R_ARM_JUMP_SLOT arm_callee1 +// CHECK-DSO-REL-NEXT: 0x18D8 R_ARM_JUMP_SLOT arm_callee2 +// CHECK-DSO-REL-NEXT: 0x18DC R_ARM_JUMP_SLOT arm_callee3 Index: lld/trunk/test/ELF/linkerscript/overlapping-sections.s =================================================================== --- lld/trunk/test/ELF/linkerscript/overlapping-sections.s +++ lld/trunk/test/ELF/linkerscript/overlapping-sections.s @@ -0,0 +1,169 @@ +# TODO: maybe this should be converted to an x86 test to get more buildbot coverage +# REQUIRES: mips +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o + +# RUN: echo "SECTIONS { \ +# RUN: .sec1 0x8000 : { sec1_start = .; *(.first_sec) sec1_end = .;} \ +# RUN: .sec2 0x8800 : { sec2_start = .; *(.second_sec) sec2_end = .;} \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: llvm-readobj -sections -program-headers %t.so | FileCheck %s -check-prefix GOOD + +# GOOD: Name: .sec1 +# GOOD-NEXT: Type: SHT_PROGBITS (0x1) +# GOOD-NEXT: Flags [ (0x3) +# GOOD-NEXT: SHF_ALLOC (0x2) +# GOOD-NEXT: SHF_WRITE (0x1) +# GOOD-NEXT: ] +# GOOD-NEXT: Address: 0x8000 +# GOOD-NEXT: Offset: 0x18000 +# GOOD-NEXT: Size: 256 + +# GOOD: Name: .sec2 +# GOOD-NEXT: Type: SHT_PROGBITS (0x1) +# GOOD-NEXT: Flags [ (0x3) +# GOOD-NEXT: SHF_ALLOC (0x2) +# GOOD-NEXT: SHF_WRITE (0x1) +# GOOD-NEXT: ] +# GOOD-NEXT: Address: 0x8800 +# GOOD-NEXT: Offset: 0x18800 +# GOOD-NEXT: Size: 256 + +# GOOD: ProgramHeaders [ +# GOOD-NEXT: ProgramHeader { +# GOOD-NEXT: Type: PT_LOAD (0x1) +# GOOD-NEXT: Offset: 0x10000 +# GOOD-NEXT: VirtualAddress: 0x0 +# GOOD-NEXT: PhysicalAddress: 0x0 +# GOOD-NEXT: FileSize: 481 +# GOOD-NEXT: MemSize: 481 +# GOOD-NEXT: Flags [ (0x5) +# GOOD-NEXT: PF_R (0x4) +# GOOD-NEXT: PF_X (0x1) +# GOOD-NEXT: ] +# GOOD-NEXT: Alignment: 65536 +# GOOD-NEXT: } +# GOOD-NEXT: ProgramHeader { +# GOOD-NEXT: Type: PT_LOAD (0x1) +# GOOD-NEXT: Offset: 0x18000 +# GOOD-NEXT: VirtualAddress: 0x8000 +# GOOD-NEXT: PhysicalAddress: 0x8000 +# GOOD-NEXT: FileSize: 2320 +# GOOD-NEXT: MemSize: 2320 +# GOOD-NEXT: Flags [ (0x6) +# GOOD-NEXT: PF_R (0x4) +# GOOD-NEXT: PF_W (0x2) +# GOOD-NEXT: ] +# GOOD-NEXT: Alignment: 65536 +# GOOD-NEXT: } + +# RUN: echo "SECTIONS { \ +# RUN: .sec1 0x8000 : AT(0x8000) { sec1_start = .; *(.first_sec) sec1_end = .;} \ +# RUN: .sec2 0x8800 : AT(0x8080) { sec2_start = .; *(.second_sec) sec2_end = .;} \ +# RUN: }" > %t-lma.script +# RUN: not ld.lld -o %t.so --script %t-lma.script %t.o -shared 2>&1 | FileCheck %s -check-prefix LMA-OVERLAP-ERR +# LMA-OVERLAP-ERR: error: section .sec1 load address range overlaps with .sec2 +# LMA-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000 -> 0x80FF] +# LMA-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8080 -> 0x817F] + +# check that we create the expected binary with --noinhibit-exec: +# RUN: ld.lld -o %t.so --script %t-lma.script %t.o -shared --noinhibit-exec + +# Verify that the .sec2 was indeed placed in a PT_LOAD where the PhysAddr +# overlaps with where .sec1 is loaded: +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-LMA +# BAD-LMA-LABEL: Section Headers: +# BAD-LMA: .sec1 PROGBITS 0000000000008000 018000 000100 00 WA 0 0 1 +# BAD-LMA: .sec2 PROGBITS 0000000000008800 018800 000100 00 WA 0 0 1 +# BAD-LMA-LABEL: Program Headers: +# BAD-LMA-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# BAD-LMA-NEXT: LOAD 0x010000 0x0000000000000000 0x0000000000000000 0x0001e1 0x0001e1 R E 0x10000 +# BAD-LMA-NEXT: LOAD 0x018000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x10000 +# BAD-LMA-NEXT: LOAD 0x018800 0x0000000000008800 0x0000000000008080 0x000110 0x000110 RW 0x10000 +# BAD-LMA-LABEL: Section to Segment mapping: +# BAD-LMA: 01 .sec1 +# BAD-LMA: 02 .sec2 .data .got + + +# Now try a script where the virtual memory addresses overlap but ensure that the +# load addresses don't: +# RUN: echo "SECTIONS { \ +# RUN: .sec1 0x8000 : AT(0x8000) { sec1_start = .; *(.first_sec) sec1_end = .;} \ +# RUN: .sec2 0x8020 : AT(0x8800) { sec2_start = .; *(.second_sec) sec2_end = .;} \ +# RUN: }" > %t-vaddr.script +# RUN: not ld.lld -o %t.so --script %t-vaddr.script %t.o -shared 2>&1 | FileCheck %s -check-prefix VADDR-OVERLAP-ERR +# VADDR-OVERLAP-ERR: error: section .sec1 virtual address range overlaps with .sec2 +# VADDR-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000 -> 0x80FF] +# VADDR-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8020 -> 0x811F] + +# Check that the expected binary was created with --noinhibit-exec: +# RUN: ld.lld -o %t.so --script %t-vaddr.script %t.o -shared --noinhibit-exec +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-VADDR +# BAD-VADDR-LABEL: Section Headers: +# BAD-VADDR: .sec1 PROGBITS 0000000000008000 018000 000100 00 WA 0 0 1 +# BAD-VADDR: .sec2 PROGBITS 0000000000008020 028020 000100 00 WA 0 0 1 +# BAD-VADDR-LABEL: Program Headers: +# BAD-VADDR-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# BAD-VADDR-NEXT: LOAD 0x010000 0x0000000000000000 0x0000000000000000 0x0001e1 0x0001e1 R E 0x10000 +# BAD-VADDR-NEXT: LOAD 0x018000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x10000 +# BAD-VADDR-NEXT: LOAD 0x028020 0x0000000000008020 0x0000000000008800 0x000110 0x000110 RW 0x10000 +# BAD-VADDR-LABEL: Section to Segment mapping: +# BAD-VADDR: 01 .sec1 +# BAD-VADDR: 02 .sec2 .data .got + +# Finally check the case where both LMA and vaddr overlap + +# RUN: echo "SECTIONS { \ +# RUN: .sec1 0x8000 : { sec1_start = .; *(.first_sec) sec1_end = .;} \ +# RUN: .sec2 0x8040 : { sec2_start = .; *(.second_sec) sec2_end = .;} \ +# RUN: }" > %t-both-overlap.script + +# RUN: not ld.lld -o %t.so --script %t-both-overlap.script %t.o -shared 2>&1 | FileCheck %s -check-prefix BOTH-OVERLAP-ERR + +# BOTH-OVERLAP-ERR: error: section .sec1 file range overlaps with .sec2 +# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x18000 -> 0x180FF] +# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x18040 -> 0x1813F] +# BOTH-OVERLAP-ERR: error: section .sec1 virtual address range overlaps with .sec2 +# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000 -> 0x80FF] +# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8040 -> 0x813F] +# BOTH-OVERLAP-ERR: error: section .sec1 load address range overlaps with .sec2 +# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000 -> 0x80FF] +# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8040 -> 0x813F] + +# RUN: ld.lld -o %t.so --script %t-both-overlap.script %t.o -shared --noinhibit-exec +# Note: I case everything overlaps we create a binary with overlapping file +# offsets. ld.bfd seems to place .sec1 to file offset 18000 and .sec2 +# at 18100 so that only virtual addr and LMA overlap +# However, in order to create such a broken binary the user has to ignore a +# fatal error by passing --noinhibit-exec, so this behaviour is fine. + +# RUN: llvm-objdump -s %t.so | FileCheck %s -check-prefix BROKEN-OUTPUT-FILE +# BROKEN-OUTPUT-FILE-LABEL: Contents of section .sec1: +# BROKEN-OUTPUT-FILE-NEXT: 8000 01010101 01010101 01010101 01010101 ................ +# BROKEN-OUTPUT-FILE-NEXT: 8010 01010101 01010101 01010101 01010101 ................ +# BROKEN-OUTPUT-FILE-NEXT: 8020 01010101 01010101 01010101 01010101 ................ +# BROKEN-OUTPUT-FILE-NEXT: 8030 01010101 01010101 01010101 01010101 ................ +# Starting here the contents of .sec2 overwrites .sec1: +# BROKEN-OUTPUT-FILE-NEXT: 8040 02020202 02020202 02020202 02020202 ................ + +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-BOTH +# BAD-BOTH-LABEL: Section Headers: +# BAD-BOTH: .sec1 PROGBITS 0000000000008000 018000 000100 00 WA 0 0 1 +# BAD-BOTH: .sec2 PROGBITS 0000000000008040 018040 000100 00 WA 0 0 1 +# BAD-BOTH-LABEL: Program Headers: +# BAD-BOTH-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# BAD-BOTH-NEXT: LOAD 0x010000 0x0000000000000000 0x0000000000000000 0x0001e1 0x0001e1 R E 0x10000 +# BAD-BOTH-NEXT: LOAD 0x018000 0x0000000000008000 0x0000000000008000 0x000150 0x000150 RW 0x10000 +# BAD-BOTH-LABEL: Section to Segment mapping: +# BAD-BOTH: 01 .sec1 .sec2 .data .got + + +.section .first_sec,"aw",@progbits +.rept 0x100 +.byte 1 +.endr + +.section .second_sec,"aw",@progbits +.rept 0x100 +.byte 2 +.endr