https://github.com/Sockke created https://github.com/llvm/llvm-project/pull/206690
This is a follow-up discussion to the earlier issue https://discourse.llvm.org/t/lld-support-dwarf64-debug-info-sorting/56906, proposing a new section type, SHT_DWARF64, as the basis for lld DWARF32/DWARF64 debug section ordering. >From 95c543bea55da90142e3058d305367fb62d9c6b0 Mon Sep 17 00:00:00 2001 From: Sockke <[email protected]> Date: Thu, 25 Jun 2026 20:38:41 +0800 Subject: [PATCH 1/2] [llvm] add SHT_DWARF64 section support --- .../CodeGen/debug-info-dwarf64-section-type.c | 11 +++++++ clang/test/Misc/cc1as-debug-format.s | 4 +++ clang/tools/driver/cc1as_main.cpp | 2 ++ llvm/include/llvm/BinaryFormat/ELF.h | 1 + llvm/include/llvm/MC/MCObjectFileInfo.h | 1 + llvm/include/llvm/MC/MCSectionELF.h | 1 + llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 2 ++ llvm/lib/MC/MCAsmInfoELF.cpp | 2 ++ llvm/lib/MC/MCObjectFileInfo.cpp | 29 +++++++++++++++++-- llvm/lib/MC/MCParser/ELFAsmParser.cpp | 2 ++ llvm/lib/Object/ELF.cpp | 1 + llvm/lib/ObjectYAML/ELFYAML.cpp | 1 + llvm/test/DebugInfo/X86/debug-info-dwarf64.ll | 6 ++++ .../test/DebugInfo/X86/debug-names-dwarf64.ll | 4 +++ llvm/test/MC/AsmParser/llvm_section_types.s | 5 ++++ .../test/tools/yaml2obj/ELF/section-type.yaml | 5 +++- llvm/tools/llvm-mc/llvm-mc.cpp | 2 ++ 17 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 clang/test/CodeGen/debug-info-dwarf64-section-type.c diff --git a/clang/test/CodeGen/debug-info-dwarf64-section-type.c b/clang/test/CodeGen/debug-info-dwarf64-section-type.c new file mode 100644 index 0000000000000..6cf75530bbe7b --- /dev/null +++ b/clang/test/CodeGen/debug-info-dwarf64-section-type.c @@ -0,0 +1,11 @@ +// REQUIRES: x86-registered-target +// RUN: %clang_cc1 -triple x86_64-linux-gnu -debug-info-kind=limited \ +// RUN: -dwarf-version=5 -gdwarf64 -emit-obj %s -o %t +// RUN: llvm-readobj --sections %t | FileCheck %s + +// CHECK: Name: .debug_info +// CHECK-NEXT: Type: SHT_DWARF64 +// CHECK: Name: .debug_str +// CHECK-NEXT: Type: SHT_DWARF64 + +int x; diff --git a/clang/test/Misc/cc1as-debug-format.s b/clang/test/Misc/cc1as-debug-format.s index 0376351a93c77..b331c252ca27f 100644 --- a/clang/test/Misc/cc1as-debug-format.s +++ b/clang/test/Misc/cc1as-debug-format.s @@ -5,6 +5,7 @@ /// -gdwarf64 causes generating DWARF64 debug info. // RUN: %clang -cc1as -triple x86_64-pc-linux-gnu -filetype obj -gdwarf64 -debug-info-kind=limited -dwarf-version=4 %s -o %t // RUN: llvm-dwarfdump -all %t | FileCheck %s --check-prefixes=CHECK,DWARF64 +// RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=SECTIONS /// -gdwarf32 is also handled and produces DWARF32 debug info. // RUN: %clang -cc1as -triple x86_64-pc-linux-gnu -filetype obj -gdwarf32 -debug-info-kind=limited -dwarf-version=4 %s -o %t // RUN: llvm-dwarfdump -all %t | FileCheck %s --check-prefixes=CHECK,DWARF32 @@ -20,5 +21,8 @@ // DWARF32-NEXT: format: DWARF32 // DWARF64-NEXT: format: DWARF64 +// SECTIONS: Name: .debug_info +// SECTIONS-NEXT: Type: SHT_DWARF64 + .text nop diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index 077cd69ce4e2c..b1942fd7c3a8d 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -545,6 +545,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, if (!Opts.MainFileName.empty()) Ctx.setMainFileName(StringRef(Opts.MainFileName)); Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32); + if (Opts.Dwarf64 && Opts.GenDwarfForAssembly) + MOFI->setELFDwarf64Sections(); Ctx.setDwarfVersion(Opts.DwarfVersion); if (Opts.GenDwarfForAssembly) Ctx.setGenDwarfRootFile(Opts.InputFile, diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 5b9ed6100f20f..b471e8344804d 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1192,6 +1192,7 @@ enum : unsigned { SHT_LLVM_JT_SIZES = 0x6fff4c0d, // LLVM jump tables sizes. SHT_LLVM_CFI_JUMP_TABLE = 0x6fff4c0e, // LLVM CFI jump table. SHT_LLVM_CALL_GRAPH = 0x6fff4c0f, // LLVM Call Graph Section. + SHT_DWARF64 = 0x6fff4c10, // DWARF64 debugging section. // Android's experimental support for SHT_RELR sections. // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512 SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets. diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h index 379c4e9094531..30becf612dac2 100644 --- a/llvm/include/llvm/MC/MCObjectFileInfo.h +++ b/llvm/include/llvm/MC/MCObjectFileInfo.h @@ -253,6 +253,7 @@ class LLVM_ABI MCObjectFileInfo { public: void initMCObjectFileInfo(MCContext &MCCtx, bool PIC, bool LargeCodeModel = false); + void setELFDwarf64Sections(); virtual ~MCObjectFileInfo(); MCContext &getContext() const { return *Ctx; } diff --git a/llvm/include/llvm/MC/MCSectionELF.h b/llvm/include/llvm/MC/MCSectionELF.h index f089dd9ea5af8..d3a010afb0300 100644 --- a/llvm/include/llvm/MC/MCSectionELF.h +++ b/llvm/include/llvm/MC/MCSectionELF.h @@ -73,6 +73,7 @@ class MCSectionELF final : public MCSection { unsigned getType() const { return Type; } unsigned getFlags() const { return Flags; } unsigned getEntrySize() const { return EntrySize; } + void setType(unsigned T) { Type = T; } void setFlags(unsigned F) { Flags = F; } const MCSymbolELF *getGroup() const { return Group.getPointer(); } bool isComdat() const { return Group.getInt(); } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 64b6b27346575..b748adc218253 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -442,6 +442,8 @@ DwarfDebug::DwarfDebug(AsmPrinter *A) Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); Asm->OutStreamer->getContext().setDwarfFormat(Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32); + if (Dwarf64 && TT.isOSBinFormatELF()) + Asm->TM.getObjFileLowering()->setELFDwarf64Sections(); } // Define out of line so we don't have to include DwarfUnit.h in DwarfDebug.h. diff --git a/llvm/lib/MC/MCAsmInfoELF.cpp b/llvm/lib/MC/MCAsmInfoELF.cpp index 34cea68896234..fb7b4799d02ff 100644 --- a/llvm/lib/MC/MCAsmInfoELF.cpp +++ b/llvm/lib/MC/MCAsmInfoELF.cpp @@ -200,6 +200,8 @@ void MCAsmInfoELF::printSwitchToSection(const MCSection &Section, OS << "llvm_cfi_jump_table"; else if (Sec.Type == ELF::SHT_LLVM_CALL_GRAPH) OS << "llvm_call_graph"; + else if (Sec.Type == ELF::SHT_DWARF64) + OS << "dwarf64"; else OS << "0x" << Twine::utohexstr(Sec.Type); diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp index b4b660c104868..f0bedd42d1241 100644 --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -63,6 +63,26 @@ static bool useCompactUnwind(const Triple &T) { return false; } +void MCObjectFileInfo::setELFDwarf64Sections() { + if (Ctx->getObjectFileType() != MCContext::IsELF) + return; + + for (MCSection *Sec : + {DwarfAbbrevSection, DwarfInfoSection, DwarfLineSection, + DwarfLineStrSection, DwarfFrameSection, DwarfPubNamesSection, + DwarfPubTypesSection, DwarfGnuPubNamesSection, + DwarfGnuPubTypesSection, DwarfStrSection, DwarfLocSection, + DwarfARangesSection, DwarfRangesSection, DwarfMacinfoSection, + DwarfMacroSection, DwarfDebugNamesSection, DwarfStrOffSection, + DwarfAddrSection, DwarfRnglistsSection, DwarfLoclistsSection, + DwarfInfoDWOSection, DwarfTypesDWOSection, DwarfAbbrevDWOSection, + DwarfStrDWOSection, DwarfLineDWOSection, DwarfLocDWOSection, + DwarfStrOffDWOSection, DwarfRnglistsDWOSection, + DwarfMacinfoDWOSection, DwarfMacroDWOSection, + DwarfLoclistsDWOSection, DwarfCUIndexSection, DwarfTUIndexSection}) + static_cast<MCSectionELF *>(Sec)->setType(ELF::SHT_DWARF64); +} + void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { EHFrameSection = Ctx->getMachOSection( "__TEXT", "__eh_frame", @@ -1220,9 +1240,12 @@ void MCObjectFileInfo::initMCObjectFileInfo(MCContext &MCCtx, bool PIC, MCSection *MCObjectFileInfo::getDwarfComdatSection(const char *Name, uint64_t Hash) const { switch (Ctx->getTargetTriple().getObjectFormat()) { - case Triple::ELF: - return Ctx->getELFSection(Name, ELF::SHT_PROGBITS, ELF::SHF_GROUP, 0, - utostr(Hash), /*IsComdat=*/true); + case Triple::ELF: { + unsigned Type = + static_cast<const MCSectionELF *>(DwarfInfoSection)->getType(); + return Ctx->getELFSection(Name, Type, ELF::SHF_GROUP, 0, utostr(Hash), + /*IsComdat=*/true); + } case Triple::Wasm: return Ctx->getWasmSection(Name, SectionKind::getMetadata(), 0, utostr(Hash), MCSection::NonUniqueID); diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp index d7adf17793af6..db62b224f6659 100644 --- a/llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -638,6 +638,8 @@ bool ELFAsmParser::parseSectionArguments(bool IsPush, SMLoc loc) { Type = ELF::SHT_LLVM_CFI_JUMP_TABLE; else if (TypeName == "llvm_call_graph") Type = ELF::SHT_LLVM_CALL_GRAPH; + else if (TypeName == "dwarf64") + Type = ELF::SHT_DWARF64; else if (TypeName.getAsInteger(0, Type)) return TokError("unknown section type"); } diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index f159fd82e7117..781d14d8c1acf 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -336,6 +336,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_JT_SIZES) STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CFI_JUMP_TABLE) STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH); + STRINGIFY_ENUM_CASE(ELF, SHT_DWARF64); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_SFRAME); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 0d742e34b4b22..2036b054b34ca 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -680,6 +680,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration( ECase(SHT_LLVM_OFFLOADING); ECase(SHT_LLVM_LTO); ECase(SHT_LLVM_CALL_GRAPH); + ECase(SHT_DWARF64); ECase(SHT_GNU_SFRAME); ECase(SHT_GNU_ATTRIBUTES); ECase(SHT_GNU_HASH); diff --git a/llvm/test/DebugInfo/X86/debug-info-dwarf64.ll b/llvm/test/DebugInfo/X86/debug-info-dwarf64.ll index 7f988b43a9fd4..5cf0841db827e 100644 --- a/llvm/test/DebugInfo/X86/debug-info-dwarf64.ll +++ b/llvm/test/DebugInfo/X86/debug-info-dwarf64.ll @@ -7,6 +7,7 @@ ; RUN: llc -mtriple=x86_64 -dwarf-version=4 -dwarf64 -filetype=obj %s -o %t4 ; RUN: llvm-dwarfdump -debug-abbrev -debug-info -v %t4 | \ ; RUN: FileCheck %s --check-prefixes=CHECK,DWARFv4 +; RUN: llvm-readobj --sections %t4 | FileCheck %s --check-prefix=SECTIONS ; CHECK: .debug_abbrev contents: ; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_yes @@ -37,6 +38,11 @@ ; CHECK: DW_TAG_base_type [3] ; CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x{{([[:xdigit:]]{16})}}] = "int") +; SECTIONS: Name: .debug_info +; SECTIONS-NEXT: Type: SHT_DWARF64 +; SECTIONS: Name: .debug_str +; SECTIONS-NEXT: Type: SHT_DWARF64 + ; IR generated and reduced from: ; $ cat foo.c ; int foo; diff --git a/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll b/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll index 32b0dcac77bce..1d6df75958680 100644 --- a/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll +++ b/llvm/test/DebugInfo/X86/debug-names-dwarf64.ll @@ -3,6 +3,7 @@ ; RUN: llc -mtriple=x86_64 -dwarf64 -accel-tables=Dwarf -dwarf-version=5 -filetype=obj %s -o %t ; RUN: llvm-dwarfdump -debug-info -debug-names %t | FileCheck %s ; RUN: llvm-dwarfdump -debug-names -verify %t | FileCheck --check-prefix=VERIFY %s +; RUN: llvm-readobj --sections %t | FileCheck --check-prefix=SECTIONS %s ; CHECK: .debug_info contents: ; CHECK-NEXT: 0x00000000: Compile Unit: {{.+}}, format = DWARF64, @@ -104,6 +105,9 @@ ; VERIFY: No errors. +; SECTIONS: Name: .debug_names +; SECTIONS-NEXT: Type: SHT_DWARF64 + ; IR generated and reduced from: ; $ cat foo.c ; int foo; diff --git a/llvm/test/MC/AsmParser/llvm_section_types.s b/llvm/test/MC/AsmParser/llvm_section_types.s index 83e5db0256647..09d4b41007eb6 100644 --- a/llvm/test/MC/AsmParser/llvm_section_types.s +++ b/llvm/test/MC/AsmParser/llvm_section_types.s @@ -29,6 +29,9 @@ # ASM: .section .section9,"",@llvm_cfi_jump_table,1 .section .section9,"",@llvm_cfi_jump_table,1 .byte 1 +# ASM: .section .section10,"",@dwarf64 +.section .section10,"",@dwarf64 +.byte 1 # CHECK: Name: .section1 # CHECK-NEXT: Type: SHT_LLVM_BB_ADDR_MAP @@ -49,3 +52,5 @@ # CHECK: Name: .section9 # CHECK-NEXT: Type: SHT_LLVM_CFI_JUMP_TABLE # CHECK: EntrySize: 1 +# CHECK: Name: .section10 +# CHECK-NEXT: Type: SHT_DWARF64 diff --git a/llvm/test/tools/yaml2obj/ELF/section-type.yaml b/llvm/test/tools/yaml2obj/ELF/section-type.yaml index 6f5f42aceafed..5deebb2b983d8 100644 --- a/llvm/test/tools/yaml2obj/ELF/section-type.yaml +++ b/llvm/test/tools/yaml2obj/ELF/section-type.yaml @@ -5,6 +5,8 @@ # CHECK: Type: SHT_PROGBITS # CHECK: Name: machine-specific # CHECK: Type: SHT_X86_64_UNWIND +# CHECK: Name: dwarf64 +# CHECK: Type: SHT_DWARF64 # CHECK: Name: hex # CHECK: Type: Unknown (0xABCD) # CHECK: Name: decimal @@ -21,6 +23,8 @@ Sections: Type: SHT_PROGBITS - Name: machine-specific Type: SHT_X86_64_UNWIND + - Name: dwarf64 + Type: SHT_DWARF64 - Name: hex Type: 0xabcd - Name: decimal @@ -40,4 +44,3 @@ FileHeader: Sections: - Name: .foo Type: [[SECTION_TYPE]] - diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp index 903f82e6855ba..db5bd06683908 100644 --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -529,6 +529,8 @@ int main(int argc, char **argv) { return 1; } Ctx.setDwarfFormat(dwarf::DWARF64); + if (GenDwarfForAssembly) + MOFI->setELFDwarf64Sections(); } if (!DwarfDebugFlags.empty()) Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags)); >From 24909c8949dd8a8fbbcb37bc262989714e6f81b9 Mon Sep 17 00:00:00 2001 From: Sockke <[email protected]> Date: Thu, 25 Jun 2026 20:39:25 +0800 Subject: [PATCH 2/2] [lld] sort DWARF32 before DWARF64 debug sections --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 51 +++++++++++++ lld/ELF/InputFiles.cpp | 1 + lld/ELF/Options.td | 3 + lld/ELF/OutputSections.cpp | 7 +- lld/docs/ReleaseNotes.rst | 3 + lld/docs/ld.lld.1 | 2 + lld/test/ELF/dwarf32-before-dwarf64.test | 91 ++++++++++++++++++++++++ 8 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 lld/test/ELF/dwarf32-before-dwarf64.test diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 12b16ded61fca..e505d7b0ff28b 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -420,6 +420,7 @@ struct Config { bool undefinedVersion; bool unique; bool useAndroidRelrTags = false; + bool dwarf32BeforeDwarf64; bool warnBackrefs; llvm::SmallVector<llvm::GlobPattern, 0> warnBackrefsExclude; bool warnCommon; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 7ec7dfcae6bca..26d22c76ee78e 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -65,6 +65,7 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> #include <cstdlib> #include <tuple> #include <utility> @@ -1572,6 +1573,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { ctx.arg.singleXoRx = !args.hasFlag(OPT_xosegment, OPT_no_xosegment, false); ctx.arg.soName = args.getLastArgValue(OPT_soname); ctx.arg.sortSection = getSortSection(ctx, args); + ctx.arg.dwarf32BeforeDwarf64 = args.hasArg(OPT_dwarf32_before_dwarf64); ctx.arg.splitStackAdjustSize = args::getInteger(args, OPT_split_stack_adjust_size, 16384); ctx.arg.zSectionHeader = @@ -1937,6 +1939,9 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { if (ctx.arg.nmagic || ctx.arg.omagic || ctx.arg.relocatable) ctx.arg.zRelro = false; + if (ctx.arg.dwarf32BeforeDwarf64 && ctx.arg.relocatable) + ErrAlways(ctx) << "--dwarf32-before-dwarf64 is not supported with -r"; + std::tie(ctx.arg.buildId, ctx.arg.buildIdVector) = getBuildId(ctx, args); if (getZFlag(args, "pack-relative-relocs", "nopack-relative-relocs", false)) { @@ -3233,6 +3238,49 @@ static void postParseObjectFile(ELFFileBase *file) { } } +static void +partitionDwarf32AndDwarf64(ArrayRef<InputSectionDescription *> isds) { + SmallVector<InputSectionBase *, 0> sections; + for (InputSectionDescription *isd : isds) + sections.append(isd->sectionBases.begin(), isd->sectionBases.end()); + if (sections.empty()) + return; + + std::stable_partition(sections.begin(), sections.end(), + [](InputSectionBase *sec) { + return sec->type != SHT_DWARF64; + }); + + auto it = sections.begin(); + for (InputSectionDescription *isd : isds) { + size_t size = isd->sectionBases.size(); + std::copy(it, it + size, isd->sectionBases.begin()); + it += size; + } +} + +static void partitionDwarf32AndDwarf64(Ctx &ctx) { + for (SectionCommand *cmd : ctx.script->sectionCommands) { + auto *osd = dyn_cast<OutputDesc>(cmd); + if (!osd || !osd->osec.name.starts_with(".debug_")) + continue; + + SmallVector<InputSectionDescription *, 0> isds; + auto flush = [&] { + partitionDwarf32AndDwarf64(isds); + isds.clear(); + }; + for (SectionCommand *subCmd : osd->osec.commands) { + if (auto *isd = dyn_cast<InputSectionDescription>(subCmd)) { + isds.push_back(isd); + continue; + } + flush(); + } + flush(); + } +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { @@ -3557,6 +3605,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { ctx.script->addOrphanSections(); } + if (ctx.arg.dwarf32BeforeDwarf64) + partitionDwarf32AndDwarf64(ctx); + { llvm::TimeTraceScope timeScope("Merge/finalize input sections"); diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 2f544f0fe0958..1634dc3b6047c 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -846,6 +846,7 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats, case SHT_CREL: case SHT_NULL: break; + case SHT_DWARF64: case SHT_PROGBITS: case SHT_NOTE: case SHT_NOBITS: diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 64c42eb49607d..bbc41664dc6b1 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -71,6 +71,9 @@ defm compress_debug_sections: Eq<"compress-debug-sections", "Compress DWARF debug sections">, MetaVarName<"[none,zlib,zstd]">; +def dwarf32_before_dwarf64: F<"dwarf32-before-dwarf64">, + HelpText<"Place DWARF32 debug input sections before DWARF64 debug input sections">; + defm compress_sections: EEq<"compress-sections", "Compress output sections that match the glob and do not have the SHF_ALLOC flag. " "The sections remain uncompressed if compressed content would be larger. " diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index eb1d8af5f375b..7fa94da2feca9 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -90,7 +90,7 @@ uint64_t OutputSection::getLMA() const { static bool canMergeToProgbits(Ctx &ctx, unsigned type) { return type == SHT_NOBITS || type == SHT_PROGBITS || type == SHT_INIT_ARRAY || type == SHT_PREINIT_ARRAY || type == SHT_FINI_ARRAY || - type == SHT_NOTE || + type == SHT_NOTE || type == SHT_DWARF64 || (type == SHT_X86_64_UNWIND && ctx.arg.emachine == EM_X86_64) || type == SHT_LLVM_CFI_JUMP_TABLE; } @@ -233,8 +233,11 @@ void OutputSection::finalizeInputSections() { // section. // // SHF_STRINGS section with different alignments should not be merged. + // Keep DWARF32 and DWARF64 debug sections in separate buckets. return sec->flags == ms->flags && sec->entsize == ms->entsize && - (sec->addralign == ms->addralign || !(sec->flags & SHF_STRINGS)); + (!s->name.starts_with(".debug_") || sec->type == ms->type) && + (sec->addralign == ms->addralign || + !(sec->flags & SHF_STRINGS)); }); if (i == mergeSections.end()) { MergeSyntheticSection *syn = createMergeSynthetic( diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index 058173413e41a..e79752b7c46de 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -29,6 +29,9 @@ Non-comprehensive list of changes in this release ELF Improvements ---------------- +* Added ``--dwarf32-before-dwarf64`` to place DWARF32 debug input sections + before DWARF64 debug input sections marked with ``SHT_DWARF64``. + * Added ``--bp-compression-sort-section=<glob>[=<layout_priority>[=<match_priority>]]``, replacing the old coarse ``--bp-compression-sort`` modes with a way to split input sections into multiple compression groups, run balanced partitioning diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 index 70541cf786f64..aededaf395bd4 100644 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -206,6 +206,8 @@ Delete all local symbols. Delete temporary local symbols. .It Fl -discard-none Keep all symbols in the symbol table. +.It Fl -dwarf32-before-dwarf64 +Place DWARF32 debug input sections before DWARF64 debug input sections. .It Fl -dynamic-linker Ns = Ns Ar value Specify the dynamic linker to be used for a dynamically linked executable. This is recorded in an ELF segment of type diff --git a/lld/test/ELF/dwarf32-before-dwarf64.test b/lld/test/ELF/dwarf32-before-dwarf64.test new file mode 100644 index 0000000000000..df81c902e5475 --- /dev/null +++ b/lld/test/ELF/dwarf32-before-dwarf64.test @@ -0,0 +1,91 @@ +# REQUIRES: x86 + +# RUN: yaml2obj %s --docnum=1 -o %t.d64.o +# RUN: yaml2obj %s --docnum=2 -o %t.d32.o +# RUN: ld.lld -shared %t.d64.o %t.d32.o -o %t.default +# RUN: llvm-readelf --hex-dump=.debug_info %t.default | FileCheck %s --check-prefix=DEFAULT +# RUN: llvm-readobj --sections %t.default | FileCheck %s --check-prefix=MIXED-TYPE + +# DEFAULT: Hex dump of section '.debug_info': +# DEFAULT-NEXT: 0x00000000 64363441 64333242 + +# MIXED-TYPE: Name: .debug_info +# MIXED-TYPE-NEXT: Type: SHT_PROGBITS + +# RUN: ld.lld -shared --dwarf32-before-dwarf64 %t.d64.o %t.d32.o -o %t.sorted +# RUN: llvm-readelf --hex-dump=.debug_info %t.sorted | FileCheck %s --check-prefix=SORTED + +# SORTED: Hex dump of section '.debug_info': +# SORTED-NEXT: 0x00000000 64333242 64363441 + +# RUN: ld.lld -shared --dwarf32-before-dwarf64 %t.d64.o -o %t.all64 +# RUN: llvm-readobj --sections %t.all64 | FileCheck %s --check-prefix=ALL64 + +# ALL64: Name: .debug_info +# ALL64-NEXT: Type: SHT_DWARF64 + +# RUN: echo 'SECTIONS { .debug_info 0 : { %t.d64.o(.debug_info) %t.d32.o(.debug_info) } }' > %t.script +# RUN: ld.lld --dwarf32-before-dwarf64 -T %t.script %t.d64.o %t.d32.o -o %t.script.out +# RUN: llvm-readelf --hex-dump=.debug_info %t.script.out | FileCheck %s --check-prefix=SORTED + +# RUN: yaml2obj %s --docnum=3 -o %t.d64str.o +# RUN: yaml2obj %s --docnum=4 -o %t.d32str.o +# RUN: ld.lld -shared --dwarf32-before-dwarf64 %t.d64str.o %t.d32str.o -o %t.str +# RUN: llvm-readelf --hex-dump=.debug_str %t.str | FileCheck %s --check-prefix=STR + +# STR: Hex dump of section '.debug_str': +# STR-NEXT: 0x00000000 64333200 64363400 + +# RUN: not ld.lld -r --dwarf32-before-dwarf64 %t.d64.o %t.d32.o -o %t.reloc 2>&1 | FileCheck %s --check-prefix=RELOCATABLE + +# RELOCATABLE: error: --dwarf32-before-dwarf64 is not supported with -r + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .debug_info + Type: SHT_DWARF64 + Content: "64363441" + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .debug_info + Type: SHT_PROGBITS + Content: "64333242" + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_DWARF64 + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 1 + EntSize: 1 + Content: "64363400" + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 1 + EntSize: 1 + Content: "64333200" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
