[clang] [lld] [llvm] [DebugInfo][LLD] Use SHT_DWARF64 for lld DWARF32/DWARF64 debug section ordering (PR #206690)
Liu Ke via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 30 02:32:24 PDT 2026
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 <liuke.gehry at bytedance.com>
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,"", at llvm_cfi_jump_table,1
.section .section9,"", at llvm_cfi_jump_table,1
.byte 1
+# ASM: .section .section10,"", at dwarf64
+.section .section10,"", at 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 <liuke.gehry at bytedance.com>
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"
More information about the cfe-commits
mailing list