diff --git a/llvm/test/tools/llvm-objdump/X86/disassemble-same-section-addr.test b/llvm/test/tools/llvm-objdump/X86/disassemble-same-section-addr.test --- a/llvm/test/tools/llvm-objdump/X86/disassemble-same-section-addr.test +++ b/llvm/test/tools/llvm-objdump/X86/disassemble-same-section-addr.test @@ -4,14 +4,29 @@ ## the section. The test uses YAML for the input, as we need a fully linked ELF ## to reproduce the original failure. -# RUN: yaml2obj %s -o %t1 -D SECTION=.second -# RUN: llvm-objdump -d %t1 | FileCheck %s -# RUN: yaml2obj %s -o %t2 -D SECTION=.first -## FIXME: this case should print "" too. -# RUN: llvm-objdump -d %t2 | FileCheck %s --check-prefix=FAIL +## Two empty sections, one with symbol in, one without. +# RUN: yaml2obj %s --docnum=1 -o %t1 -D SIZE1=0 -D SIZE2=0 -D SECTION=.second +# RUN: llvm-objdump -d %t1 | FileCheck %s --check-prefix=TARGET +# RUN: yaml2obj %s --docnum=1 -o %t2 -D SIZE1=0 -D SIZE2=0 -D SECTION=.first +# RUN: llvm-objdump -d %t2 | FileCheck %s --check-prefix=TARGET -# CHECK: callq 0x5 -# FAIL: callq 0x5{{$}} +## Two sections, one empty with symbol, other non-empty, without symbol. +# RUN: yaml2obj %s --docnum=1 -o %t3 -D SIZE1=1 -D SIZE2=0 -D SECTION=.second +# RUN: llvm-objdump -d %t3 | FileCheck %s --check-prefix=TARGET +# RUN: yaml2obj %s --docnum=1 -o %t4 -D SIZE1=0 -D SIZE2=1 -D SECTION=.first +# RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=TARGET + +## Fall back to absolute symbol if no symbol found in candidate sections. +# RUN: yaml2obj %s --docnum=1 -o %t5 -D SIZE1=1 -D SIZE2=0 -D SECTION=.caller +# RUN: llvm-objdump -d %t5 | FileCheck %s --check-prefix=ABSOLUTE + +## Print no target if no symbol found. +# RUN: llvm-objcopy -N absolute %t5 %t6 +# RUN: llvm-objdump -d %t6 | FileCheck %s --check-prefix=FAIL + +# TARGET: callq 0x5 +# ABSOLUTE: callq 0x5 +# FAIL: callq 0x5{{$}} --- !ELF FileHeader: @@ -29,11 +44,66 @@ Type: SHT_PROGBITS Flags: [SHF_ALLOC, SHF_EXECINSTR] Address: 0x5 + Size: [[SIZE1]] - Name: .second Type: SHT_PROGBITS Flags: [SHF_ALLOC, SHF_EXECINSTR] Address: 0x5 + Size: [[SIZE2]] Symbols: - Name: target Section: [[SECTION]] Value: 0x5 + - Name: absolute + Index: 0xFFF1 + Value: 0x0 + +## Two empty sections, both with symbols. +# RUN: yaml2obj %s --docnum=2 -o %t7 -D SIZE1=0 -D SIZE2=0 -D SYMVAL1=0x5 -D SYMVAL2=0x5 +# RUN: llvm-objdump -d %t7 | FileCheck %s --check-prefix=SECOND + +## Two sections, both with symbols, one empty, the other not. +# RUN: yaml2obj %s --docnum=2 -o %t8 -D SIZE1=1 -D SIZE2=0 -D SYMVAL1=0x5 -D SYMVAL2=0x5 +# RUN: llvm-objdump -d %t8 | FileCheck %s --check-prefix=FIRST +# RUN: yaml2obj %s --docnum=2 -o %t9 -D SIZE1=0 -D SIZE2=1 -D SYMVAL1=0x5 -D SYMVAL2=0x5 +# RUN: llvm-objdump -d %t9 | FileCheck %s --check-prefix=SECOND + +## Two sections, both with symbols, one empty, other not, symbol in non-empty +## section has too high value. +# RUN: yaml2obj %s --docnum=2 -o %t10 -D SIZE1=1 -D SIZE2=0 -D SYMVAL1=0x6 -D SYMVAL2=0x5 +# RUN: llvm-objdump -d %t10 | FileCheck %s --check-prefix=SECOND +# RUN: yaml2obj %s --docnum=2 -o %t11 -D SIZE1=0 -D SIZE2=1 -D SYMVAL1=0x5 -D SYMVAL2=0x6 +# RUN: llvm-objdump -d %t11 | FileCheck %s --check-prefix=FIRST + +# FIRST: callq 0x5 +# SECOND: callq 0x5 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .caller + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Address: 0x0 + Content: e800000000 # Call instruction to next address. + - Name: .first + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Address: 0x5 + Size: [[SIZE1]] + - Name: .second + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Address: 0x5 + Size: [[SIZE2]] +Symbols: + - Name: first + Section: .first + Value: [[SYMVAL1]] + - Name: second + Section: .second + Value: [[SYMVAL2]] diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -1244,12 +1244,17 @@ addPltEntries(Obj, AllSymbols, Saver); // Create a mapping from virtual address to section. An empty section can - // cause more than one section at the same address. Use a stable sort to - // stabilize the output. + // cause more than one section at the same address. Sort such sections to be + // before same-addressed non-empty sections so that symbol lookups prefer the + // non-empty section. std::vector> SectionAddresses; for (SectionRef Sec : Obj->sections()) SectionAddresses.emplace_back(Sec.getAddress(), Sec); - llvm::stable_sort(SectionAddresses, llvm::less_first()); + llvm::stable_sort(SectionAddresses, [](const auto &LHS, const auto &RHS) { + return LHS.first < RHS.first || + (LHS.first == RHS.first && + LHS.second.getSize() < RHS.second.getSize()); + }); // Linked executables (.exe and .dll files) typically don't include a real // symbol table but they might contain an export table. @@ -1525,41 +1530,48 @@ // through a relocation. // // In a non-relocatable object, the target may be in any section. + // In that case, locate the section(s) containing the target address + // and find the symbol in one of those, if possible. // // N.B. We don't walk the relocations in the relocatable case yet. - auto *TargetSectionSymbols = &Symbols; + std::vector TargetSectionSymbols; if (!Obj->isRelocatableObject()) { - auto It = partition_point( + auto It = llvm::partition_point( SectionAddresses, [=](const std::pair &O) { return O.first <= Target; }); - if (It != SectionAddresses.begin()) { + uint64_t TargetSecAddr = 0; + while (It != SectionAddresses.begin()) { --It; - TargetSectionSymbols = &AllSymbols[It->second]; - } else { - TargetSectionSymbols = &AbsoluteSymbols; + if (TargetSecAddr == 0) + TargetSecAddr = It->first; + if (It->first != TargetSecAddr) + break; + TargetSectionSymbols.push_back(&AllSymbols[It->second]); } + } else { + TargetSectionSymbols.push_back(&Symbols); } - - // Find the last symbol in the section whose offset is less than - // or equal to the target. If there isn't a section that contains - // the target, find the nearest preceding absolute symbol. - auto TargetSym = partition_point( - *TargetSectionSymbols, - [=](const SymbolInfoTy &O) { - return O.Addr <= Target; - }); - if (TargetSym == TargetSectionSymbols->begin()) { - TargetSectionSymbols = &AbsoluteSymbols; - TargetSym = partition_point( - AbsoluteSymbols, - [=](const SymbolInfoTy &O) { - return O.Addr <= Target; - }); + TargetSectionSymbols.push_back(&AbsoluteSymbols); + + // Find the last symbol in the first candidate section whose offset + // is less than or equal to the target. If there are no such + // symbols, try in the next section and so on, before finally using + // the nearest preceding absolute symbol (if any), if there are no + // other valid symbols. + const SymbolInfoTy *TargetSym = nullptr; + for (const SectionSymbolsTy * TargetSymbols : TargetSectionSymbols) { + auto Partition = llvm::partition_point( + *TargetSymbols, + [=](const SymbolInfoTy &O) { return O.Addr <= Target; }); + if (Partition != TargetSymbols->begin()) { + TargetSym = &*(Partition - 1); + break; + } } - if (TargetSym != TargetSectionSymbols->begin()) { - --TargetSym; + + if(TargetSym != nullptr) { uint64_t TargetAddress = TargetSym->Addr; StringRef TargetName = TargetSym->Name; outs() << " <" << TargetName;