diff options
| author | Fangrui Song <maskray@google.com> | 2019-06-26 08:09:08 +0000 |
|---|---|---|
| committer | Fangrui Song <maskray@google.com> | 2019-06-26 08:09:08 +0000 |
| commit | ba51fd5664e3e15fbc1d350acdb56b4d8fc52ebc (patch) | |
| tree | 85971b95475bea6bf976f1037ea986042d2c0f84 | |
| parent | 8bfe0fc1d9b52337baceb89ac39fb58498b17d71 (diff) | |
| download | bcm5719-llvm-ba51fd5664e3e15fbc1d350acdb56b4d8fc52ebc.tar.gz bcm5719-llvm-ba51fd5664e3e15fbc1d350acdb56b4d8fc52ebc.zip | |
Reland D61583 [ELF] Error on relocations to STT_SECTION symbols if the sections were discarded
This restores r361830 "[ELF] Error on relocations to STT_SECTION symbols if the sections were discarded"
and dependent commits (r362218, r362497) which were reverted by r364321, with a fix of a --gdb-index issue.
.rela.debug_ranges contains relocations of range list entries:
// start address of a range list entry
// old: 0; after r361830: 0
00000000000033a0 R_X86_64_64 .text._ZN2v88internal7Isolate7factoryEv + 0
// end address of a range list entry
// old: 0xe; after r361830: 0
00000000000033a8 R_X86_64_64 .text._ZN2v88internal7Isolate7factoryEv + e
If both start and end addresses of a range list entry resolve to 0,
DWARFDebugRangeList::isEndOfListEntry() will return true, then the
.debug_range decoding loop will terminate prematurely:
while (true) {
decode StartAddress
decode EndAddress
if (Entry.isEndOfListEntry()) // prematurely
break;
Entries.push_back(Entry);
}
In lld/ELF/SyntheticSections.cpp, readAddressAreas() will read
incomplete address ranges and the resulting .gdb_index will be
incomplete. For files that gdb hasn't loaded their debug info, gdb uses
.gdb_index to map addresses to CUs. The absent entries make gdb fail to
symbolize some addresses.
To address this issue, we simply allow relocations to undefined symbols
in DWARF.cpp:findAux() and let RelocationResolver resolve them.
This patch should fix:
[1] http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20190603/659848.html
[2] https://bugs.chromium.org/p/chromium/issues/detail?id=978067
llvm-svn: 364391
| -rw-r--r-- | lld/ELF/DWARF.cpp | 27 | ||||
| -rw-r--r-- | lld/ELF/InputFiles.cpp | 3 | ||||
| -rw-r--r-- | lld/ELF/InputSection.cpp | 20 | ||||
| -rw-r--r-- | lld/ELF/Relocations.cpp | 14 | ||||
| -rw-r--r-- | lld/ELF/Symbols.cpp | 8 | ||||
| -rw-r--r-- | lld/test/ELF/Inputs/comdat-discarded-reloc.s | 12 | ||||
| -rw-r--r-- | lld/test/ELF/comdat-discarded-error.s | 12 | ||||
| -rw-r--r-- | lld/test/ELF/comdat-discarded-gdb-index.s | 63 | ||||
| -rw-r--r-- | lld/test/ELF/comdat-discarded-reloc.s | 39 | ||||
| -rw-r--r-- | lld/test/ELF/comdat.s | 4 | ||||
| -rw-r--r-- | lld/test/ELF/gdb-index-ranges-discarded.s | 51 | ||||
| -rw-r--r-- | lld/test/ELF/invalid-undef-section-symbol.test | 26 | ||||
| -rw-r--r-- | lld/test/ELF/relocatable-eh-frame.s | 19 | ||||
| -rw-r--r-- | lld/test/ELF/undef-broken-debug.test | 8 |
14 files changed, 212 insertions, 94 deletions
diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp index 6b90a038e87..9266320765a 100644 --- a/lld/ELF/DWARF.cpp +++ b/lld/ELF/DWARF.cpp @@ -92,21 +92,20 @@ LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos, const typename ELFT::Sym &Sym = File->template getELFSyms<ELFT>()[SymIndex]; uint32_t SecIndex = File->getSectionIndex(Sym); - // Broken debug info can point to a non-Defined symbol. - auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel)); - if (!DR) { - RelType Type = Rel.getType(Config->IsMips64EL); - if (Type != Target->NoneRel) - error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" + - llvm::utohexstr(Rel.r_offset) + " has unsupported target"); - return None; - } - uint64_t Val = DR->Value; + // An undefined symbol may be a symbol defined in a discarded section. We + // shall still resolve it. This is important for --gdb-index: the end address + // offset of an entry in .debug_ranges is relocated. If it is not resolved, + // its zero value will terminate the decoding of .debug_ranges prematurely. + Symbol &S = File->getRelocTargetSym(Rel); + uint64_t Val = 0; + if (auto *DR = dyn_cast<Defined>(&S)) { + Val = DR->Value; - // FIXME: We should be consistent about always adding the file - // offset or not. - if (DR->Section->Flags & ELF::SHF_ALLOC) - Val += cast<InputSection>(DR->Section)->getOffsetInFile(); + // FIXME: We should be consistent about always adding the file + // offset or not. + if (DR->Section->Flags & ELF::SHF_ALLOC) + Val += cast<InputSection>(DR->Section)->getOffsetInFile(); + } DataRefImpl D; D.p = getAddend<ELFT>(Rel); diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 0c36ef141ae..d1a72f0adc4 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1080,6 +1080,9 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() { if (ESym.st_shndx == SHN_UNDEF) this->Symbols[I] = make<Undefined>(this, Name, Binding, StOther, Type); + else if (Sec == &InputSection::Discarded) + this->Symbols[I] = make<Undefined>(this, Name, Binding, StOther, Type, + /*DiscardedSecIdx=*/SecIdx); else this->Symbols[I] = make<Defined>(this, Name, Binding, StOther, Type, Value, Size, Sec); diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 3e8d093e6d2..d077c017ca7 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -412,7 +412,8 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { for (const RelTy &Rel : Rels) { RelType Type = Rel.getType(Config->IsMips64EL); - Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); + const ObjFile<ELFT> *File = getFile<ELFT>(); + Symbol &Sym = File->getRelocTargetSym(Rel); auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); Buf += sizeof(RelTy); @@ -435,10 +436,23 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { // .eh_frame is horribly special and can reference discarded sections. To // avoid having to parse and recreate .eh_frame, we just replace any // relocation in it pointing to discarded sections with R_*_NONE, which - // hopefully creates a frame that is ignored at runtime. + // hopefully creates a frame that is ignored at runtime. Also, don't warn + // on .gcc_except_table and debug sections. + // + // See the comment in maybeReportUndefined for PPC64 .toc . auto *D = dyn_cast<Defined>(&Sym); if (!D) { - error("STT_SECTION symbol should be defined"); + if (!Sec->Name.startswith(".debug") && + !Sec->Name.startswith(".zdebug") && Sec->Name != ".eh_frame" && + Sec->Name != ".gcc_except_table" && Sec->Name != ".toc") { + uint32_t SecIdx = cast<Undefined>(Sym).DiscardedSecIdx; + Elf_Shdr_Impl<ELFT> Sec = + CHECK(File->getObj().sections(), File)[SecIdx]; + warn("relocation refers to a discarded section: " + + CHECK(File->getObj().getSectionName(&Sec), File) + + "\n>>> referenced by " + getObjMsg(P->r_offset)); + } + P->setSymbolAndType(0, 0, false); continue; } SectionBase *Section = D->Section->Repl; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 639a3c5555e..8b8a3b1d4f9 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -653,9 +653,17 @@ static std::string maybeReportDiscarded(Undefined &Sym) { return ""; ArrayRef<Elf_Shdr_Impl<ELFT>> ObjSections = CHECK(File->getObj().sections(), File); - std::string Msg = - "relocation refers to a symbol in a discarded section: " + toString(Sym) + - "\n>>> defined in " + toString(File); + + std::string Msg; + if (Sym.Type == ELF::STT_SECTION) { + Msg = "relocation refers to a discarded section: "; + Msg += CHECK( + File->getObj().getSectionName(&ObjSections[Sym.DiscardedSecIdx]), File); + } else { + Msg = "relocation refers to a symbol in a discarded section: " + + toString(Sym); + } + Msg += "\n>>> defined in " + toString(File); Elf_Shdr_Impl<ELFT> ELFSec = ObjSections[Sym.DiscardedSecIdx - 1]; if (ELFSec.sh_type != SHT_GROUP) diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 5300aafaff8..9a4de4faf10 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -48,17 +48,11 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { auto &D = cast<Defined>(Sym); SectionBase *IS = D.Section; - // According to the ELF spec reference to a local symbol from outside - // the group are not allowed. Unfortunately .eh_frame breaks that rule - // and must be treated specially. For now we just replace the symbol with - // 0. - if (IS == &InputSection::Discarded) - return 0; - // This is an absolute symbol. if (!IS) return D.Value; + assert(IS != &InputSection::Discarded); IS = IS->Repl; uint64_t Offset = D.Value; diff --git a/lld/test/ELF/Inputs/comdat-discarded-reloc.s b/lld/test/ELF/Inputs/comdat-discarded-reloc.s index 9526f5ac95c..d89575f27e9 100644 --- a/lld/test/ELF/Inputs/comdat-discarded-reloc.s +++ b/lld/test/ELF/Inputs/comdat-discarded-reloc.s @@ -1,6 +1,8 @@ -.section .text.bar1,"aG",@progbits,group,comdat +.global bar, _start -.section .text.bar2 -.global bar -bar: - .quad .text.bar1 +.section .text.foo,"aG",@progbits,group,comdat + +.section .text +_start: + .quad .text.foo + .quad bar diff --git a/lld/test/ELF/comdat-discarded-error.s b/lld/test/ELF/comdat-discarded-error.s index afefdaf02c8..d5aa4aa68df 100644 --- a/lld/test/ELF/comdat-discarded-error.s +++ b/lld/test/ELF/comdat-discarded-error.s @@ -5,7 +5,7 @@ # RUN: echo '.section .text.foo,"axG",@progbits,foo,comdat; .globl bar; bar:' |\ # RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t3.o -# RUN: not ld.lld %t1.o %t2.o %t3.o -o /dev/null 2>&1 | FileCheck %s +# RUN: not ld.lld %t2.o %t3.o %t1.o -o /dev/null 2>&1 | FileCheck %s # CHECK: error: relocation refers to a symbol in a discarded section: bar # CHECK-NEXT: >>> defined in {{.*}}3.o @@ -13,6 +13,16 @@ # CHECK-NEXT: >>> prevailing definition is in {{.*}}2.o # CHECK-NEXT: >>> referenced by {{.*}}1.o:(.text+0x1) +# CHECK: error: relocation refers to a discarded section: .text.foo +# CHECK-NEXT: >>> defined in {{.*}}1.o +# CHECK-NEXT: >>> section group signature: foo +# CHECK-NEXT: >>> prevailing definition is in {{.*}}2.o +# CHECK-NEXT: >>> referenced by {{.*}}1.o:(.data+0x0) + .globl _start _start: jmp bar + +.section .text.foo,"axG",@progbits,foo,comdat +.data + .quad .text.foo diff --git a/lld/test/ELF/comdat-discarded-gdb-index.s b/lld/test/ELF/comdat-discarded-gdb-index.s new file mode 100644 index 00000000000..43505960498 --- /dev/null +++ b/lld/test/ELF/comdat-discarded-gdb-index.s @@ -0,0 +1,63 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: ld.lld --gdb-index %t.o %t.o -o %t + +## .debug_info has a relocation to .text.foo . The second %t.o is discarded. +## Check we don't error on the relocation. +# CHECK: .rela.debug_info { +# CHECK-NEXT: 0xC R_X86_64_64 .text.foo 0x0 + +.section .text.foo,"axG",@progbits,foo,comdat +.globl foo +.Lfunc_begin0: +foo: + ret +.Lfunc_end0: + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long .Lcu_end0 - .Lcu_begin0 - 4 + .short 4 # DWARF version number + .long 0 # Offset Into Abbrev. Section + .byte 4 # Address Size +.Ldie0: + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0 - .Lfunc_begin0 # DW_AT_high_pc + .byte 2 # Abbrev [2] DW_TAG_subprogram + .asciz "foo" # DW_AT_name + .byte 0 +.Lcu_end0: + +.section .debug_gnu_pubnames,"",@progbits + .long .LpubNames_end0 - .LpubNames_begin0 +.LpubNames_begin0: + .short 2 # Version + .long .Lcu_begin0 # CU Offset + .long .Lcu_end0 - .Lcu_begin0 + .long .Ldie0 - .Lcu_begin0 + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "foo" # External Name + .long 0 +.LpubNames_end0: diff --git a/lld/test/ELF/comdat-discarded-reloc.s b/lld/test/ELF/comdat-discarded-reloc.s index d23baf386e9..4d50ab10e51 100644 --- a/lld/test/ELF/comdat-discarded-reloc.s +++ b/lld/test/ELF/comdat-discarded-reloc.s @@ -1,17 +1,42 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat-discarded-reloc.s -o %t2.o -# RUN: ld.lld -gc-sections %t.o %t2.o -o %t +# RUN: ld.lld -gc-sections --noinhibit-exec %t2.o %t.o -o /dev/null +# RUN: ld.lld -r %t2.o %t.o -o %t 2>&1 | FileCheck --check-prefix=WARN %s +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s ## ELF spec doesn't allow a relocation to point to a deduplicated ## COMDAT section. Unfortunately this happens in practice (e.g. .eh_frame) ## Test case checks we do not crash. -.global bar, _start +# WARN: warning: relocation refers to a discarded section: .text.bar1 +# WARN-NEXT: >>> referenced by {{.*}}.o:(.rela.text.bar2+0x0) +# WARN-NOT: warning -.section .text.foo,"aG",@progbits,group,comdat +# RELOC: .rela.eh_frame { +# RELOC-NEXT: R_X86_64_NONE +# RELOC-NEXT: } +# RELOC-NEXT: .rela.debug_foo { +# RELOC-NEXT: R_X86_64_NONE +# RELOC-NEXT: } +# RELOC-NEXT: .rela.gcc_except_table { +# RELOC-NEXT: R_X86_64_NONE +# RELOC-NEXT: } -.section .text -_start: - .quad .text.foo - .quad bar +.section .text.bar1,"aG",@progbits,group,comdat + +## .text.bar1 in this file is discarded. Warn on the relocation. +.section .text.bar2,"ax" +.globl bar +bar: + .quad .text.bar1 + +## Don't warn on .eh_frame, .debug*, .zdebug*, or .gcc_except_table +.section .eh_frame,"a" + .quad .text.bar1 + +.section .debug_foo + .quad .text.bar1 + +.section .gcc_except_table,"a" + .quad .text.bar1 diff --git a/lld/test/ELF/comdat.s b/lld/test/ELF/comdat.s index 86103e5d9eb..9e3f5a81d30 100644 --- a/lld/test/ELF/comdat.s +++ b/lld/test/ELF/comdat.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o -// RUN: ld.lld -shared %t.o %t.o %t2.o -o %t +// RUN: ld.lld -shared %t.o %t2.o -o %t // RUN: llvm-objdump -d %t | FileCheck %s // RUN: llvm-readobj -S --symbols %t | FileCheck --check-prefix=READ %s @@ -31,9 +31,7 @@ foo: // CHECK-EMPTY: // CHECK-NEXT: bar: // 0x1000 - 0x1001 - 5 = -6 -// 0 - 0x1006 - 5 = -4107 // CHECK-NEXT: 1001: {{.*}} callq -6 -// CHECK-NEXT: 1006: {{.*}} callq -4107 .section .text3,"axG",@progbits,zed,comdat,unique,0 diff --git a/lld/test/ELF/gdb-index-ranges-discarded.s b/lld/test/ELF/gdb-index-ranges-discarded.s new file mode 100644 index 00000000000..2d5ce15736f --- /dev/null +++ b/lld/test/ELF/gdb-index-ranges-discarded.s @@ -0,0 +1,51 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: ld.lld --gdb-index -e main %t.o -o %t +# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s + +# CHECK: .gdb_index contents: +# CHECK: Address area offset = 0x28, has 1 entries: +# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0 + +## .debug_ranges contains 2 entries. .Lfunc_end0 is defined in the discarded +## .text.foo. Test we resolve it to a non-zero value, otherwise the address area +## of .gdb_index will not included [.Lfunc_begin1, .Lfunc_end1). + +.section .text.foo,"aex",@progbits +.Lfunc_begin0: + ret +.Lfunc_end0: + +.section .text.bar,"ax",@progbits +.Lfunc_begin1: + ret +.Lfunc_end1: + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long .Lcu_end0 - .Lcu_begin0 - 4 + .short 4 # DWARF version number + .long 0 # Offset Into Abbrev. Section + .byte 8 # Address Size +.Ldie0: + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long 0 # DW_AT_ranges +.Lcu_end0: + +.section .debug_ranges,"",@progbits + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad 0 + .quad 0 diff --git a/lld/test/ELF/invalid-undef-section-symbol.test b/lld/test/ELF/invalid-undef-section-symbol.test deleted file mode 100644 index 1d66885eadf..00000000000 --- a/lld/test/ELF/invalid-undef-section-symbol.test +++ /dev/null @@ -1,26 +0,0 @@ -# RUN: yaml2obj %s -o %t.o -# RUN: not ld.lld -r %t.o -o /dev/null 2>&1 | FileCheck %s - -# We used to crash at this. -# CHECK: STT_SECTION symbol should be defined - ---- !ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_X86_64 -Sections: - - Name: .text - Type: SHT_PROGBITS - - Name: .rela.text - Type: SHT_RELA - AddressAlign: 0x0000000000000008 - Info: .text - Relocations: - - Offset: 0x0000000000000000 - Symbol: .text - Type: R_X86_64_NONE -Symbols: - - Name: .text - Type: STT_SECTION diff --git a/lld/test/ELF/relocatable-eh-frame.s b/lld/test/ELF/relocatable-eh-frame.s deleted file mode 100644 index dee906acb87..00000000000 --- a/lld/test/ELF/relocatable-eh-frame.s +++ /dev/null @@ -1,19 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: ld.lld -r %t.o %t.o -o %t -# RUN: llvm-readobj -r %t | FileCheck %s -# RUN: ld.lld %t -o %t.so -shared -# RUN: llvm-objdump -h %t.so | FileCheck --check-prefix=DSO %s - -# DSO: .eh_frame 00000034 - -# CHECK: Relocations [ -# CHECK-NEXT: Section ({{.*}}) .rela.eh_frame { -# CHECK-NEXT: 0x20 R_X86_64_PC32 .foo 0x0 -# CHECK-NEXT: 0x50 R_X86_64_NONE - 0x0 -# CHECK-NEXT: } -# CHECK-NEXT: ] - -.section .foo,"aG",@progbits,bar,comdat -.cfi_startproc -.cfi_endproc diff --git a/lld/test/ELF/undef-broken-debug.test b/lld/test/ELF/undef-broken-debug.test index 2ca8494a180..76449a59b73 100644 --- a/lld/test/ELF/undef-broken-debug.test +++ b/lld/test/ELF/undef-broken-debug.test @@ -1,12 +1,8 @@ # REQUIRES: x86 # RUN: yaml2obj %s -o %t.o -# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o -o /dev/null -# The debug info has a broken relocation. Check that we don't crash -# and still report the undefined symbol. - -# CHECK: error: {{.*}}.o: relocation R_X86_64_64 at 0x29 has unsupported target -# CHECK: error: undefined symbol: bar +# The debug info has a broken relocation. Check that we don't crash. # We used to dereference null Target in DWARF.cpp:findAux while reporting a duplicate symbol error, # because Target wasn't initialized yet. |

