diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -154,6 +154,7 @@ bool demangle = true; bool dependentLibraries; bool disableVerify; + bool dwarf32BeforeDwarf64; bool ehFrameHdr; bool emitLLVM; bool emitRelocs; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -351,6 +351,9 @@ error("-r and --export-dynamic may not be used together"); } + if (config->dwarf32BeforeDwarf64 && !config->is64) + error("--dwarf32-before-dwarf64 is only supported on 64-bit targets"); + if (config->executeOnly) { if (config->emachine != EM_AARCH64) error("-execute-only is only supported on AArch64 targets"); @@ -948,6 +951,8 @@ errorHandler().errorHandlingScript = args.getLastArgValue(OPT_error_handling_script); + config->dwarf32BeforeDwarf64 = args.hasFlag( + OPT_dwarf32_before_dwarf64, OPT_no_dwarf32_before_dwarf64, false); config->executeOnly = args.hasFlag(OPT_execute_only, OPT_no_execute_only, false); config->exportDynamic = diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -146,6 +146,10 @@ def discard_none: F<"discard-none">, HelpText<"Keep all symbols in the symbol table">; +defm dwarf32_before_dwarf64: BB<"dwarf32-before-dwarf64", + "DWARF32 sections before DWARF64 sections", + "Do not place DWARF32 sections before DWARF64 sections (default)">; + defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">; defm dynamic_list : Eq<"dynamic-list", diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -157,6 +157,34 @@ entsize = 0; } +template +static void +partitionDwarf32AndDwarf64Aux(std::vector §ions) { + auto notDWARF64 = [](const InputSection *sec) { + if (sec->numRelocations == 0) + return true; + if (sec->areRelocsRela) { + auto &r = *static_cast(sec->firstRelocation); + return r.getType(config->isMips64EL) != target->symbolicRel; + } else { + auto &r = *static_cast(sec->firstRelocation); + return r.getType(config->isMips64EL) != target->symbolicRel; + } + }; + std::stable_partition(sections.begin(), sections.end(), notDWARF64); +} + +static void partitionDwarf32AndDwarf64(std::vector §ions) { + switch (config->ekind) { + case ELF64LEKind: + return partitionDwarf32AndDwarf64Aux(sections); + case ELF64BEKind: + return partitionDwarf32AndDwarf64Aux(sections); + default: + llvm_unreachable("32-bit is unsupported"); + } +} + // This function scans over the InputSectionBase list sectionBases to create // InputSectionDescription::sections. // @@ -215,6 +243,10 @@ // Some input sections may be removed from the list after ICF. for (InputSection *s : cmd->sections) commitSection(s); + + if (config->dwarf32BeforeDwarf64 && (flags & SHF_ALLOC) == 0 && + name.startswith(".debug_")) + partitionDwarf32AndDwarf64(cmd->sections); } for (auto *ms : mergeSections) ms->finalizeContents(); diff --git a/lld/test/ELF/dwarf32-before-dwarf64.s b/lld/test/ELF/dwarf32-before-dwarf64.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/dwarf32-before-dwarf64.s @@ -0,0 +1,126 @@ +# REQUIRES: ppc +## Test --dwarf32-before-dwarf64 can order DWARF32 input sections before DWARF64 +## input sections to mitigate out-of-range relocations from DWARF32 input sections. + +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=ppc64le %t/asm -o %tle.o + +## By default sections are combined in input order. +# RUN: ld.lld %tle.o -o %tle +# RUN: llvm-objdump -s %tle | FileCheck %s --check-prefix=LE +# RUN: ld.lld --dwarf32-before-dwarf64 --no-dwarf32-before-dwarf64 %tle.o -o %tle +# RUN: llvm-objdump -s %tle | FileCheck %s --check-prefix=LE + +## --dwarf32-before-dwarf64 orders DWARF32 before DWARF64. +# RUN: ld.lld --dwarf32-before-dwarf64 %tle.o -o %tle +# RUN: llvm-objdump -s %tle | FileCheck %s --check-prefix=LE-SORT + +## Test big-endian. +# RUN: llvm-mc -filetype=obj -triple=ppc64 %t/asm -o %tbe.o +# RUN: ld.lld --dwarf32-before-dwarf64 %tbe.o -o %tbe +# RUN: llvm-objdump -s %tbe | FileCheck %s --check-prefix=BE-SORT + +# LE: Contents of section .debug_info: +# LE-NEXT: 0000 01000000 00000000 00000000 58010110 +# LE-NEXT: 0010 00000000 02000000 00000000 00000000 +# LE-NEXT: 0020 58010110 00000000 03000000 04000000 +# LE-NEXT: 0030 00000000 58010110 00000000 +## .debug_info offsets of unique,1 and unique,3: 0x0 and 0x28. +# LE: Contents of section .debug_aranges: +# LE-NEXT: 0000 00000000 00000000 28000000 +# LE: Contents of section .nondebug: +# LE-NEXT: 0000 01000000 00000000 00000000 02000000 +# LE-NEXT: 0010 00000000 + +# LE-SORT: Contents of section .debug_info: +# LE-SORT-NEXT: 0000 03000000 04000000 00000000 58010110 +# LE-SORT-NEXT: 0010 00000000 01000000 00000000 00000000 +# LE-SORT-NEXT: 0020 58010110 00000000 02000000 00000000 +# LE-SORT-NEXT: 0030 00000000 58010110 00000000 + +## .debug_info offsets of unique,3 and unique,1: 0x0 and 0x14. +# LE-SORT: Contents of section .debug_aranges: +# LE-SORT-NEXT: 0000 00000000 14000000 00000000 +## Non-debug sections +# LE-SORT: Contents of section .nondebug: +# LE-SORT-NEXT: 0000 01000000 14000000 00000000 02000000 +# LE-SORT-NEXT: 0010 14000000 + +# BE-SORT: Contents of section .debug_info: +# BE-SORT-NEXT: 0000 00000003 00000004 00000000 00000000 +# BE-SORT-NEXT: 0010 10010158 00000001 00000000 00000000 +# BE-SORT-NEXT: 0020 00000000 10010158 00000002 00000000 +# BE-SORT-NEXT: 0030 00000000 00000000 10010158 + + +## --dwarf32-before-dwarf64 applies to the input section description *(.debug_info). +## This effectively makes DWARF32/DWARF64 a more significant key than +## (SORT*,--sort-section,input order) in the conceptual radix sort. +# RUN: ld.lld --dwarf32-before-dwarf64 -T %t/lds --allow-multiple-definition %tle.o %tle.o -o %tscript +# RUN: llvm-objdump -s %tscript | FileCheck %s --check-prefix=SCRIPT + +# SCRIPT: Contents of section .debug_info: +# SCRIPT-NEXT: 0000 03000000 04000000 00000000 00000000 +# SCRIPT-NEXT: 0010 00000000 03000000 04000000 00000000 +# SCRIPT-NEXT: 0020 04000000 00000000 01000000 00000000 +# SCRIPT-NEXT: 0030 00000000 00000000 00000000 02000000 +# SCRIPT-NEXT: 0040 00000000 00000000 00000000 00000000 +# SCRIPT-NEXT: 0050 01000000 00000000 00000000 04000000 +# SCRIPT-NEXT: 0060 00000000 02000000 00000000 00000000 +# SCRIPT-NEXT: 0070 04000000 00000000 + +# RUN: llvm-mc -filetype=obj -triple=ppc /dev/null -o %t32.o +# RUN: not ld.lld --dwarf32-before-dwarf64 %t32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=32BIT + +# 32BIT: error: --dwarf32-before-dwarf64 is only supported on 64-bit targets + +#--- asm +.globl _start +_start: + blr + +.section .debug_abbrev + +## We use fake contents for simplicity. In practice, the first relocation being +## the 64-bit absolute relocation type is a good indicator of DWARF64. Subsequent +## relocations may have text section references which are always 64-bit, so they +## cannot be used. + +## For these .debug_info sections, the first relocations of unique,1 and unique,2 +## are 64-bit absolute relocations and we consider them DWARF64. +.section .debug_info,"",@progbits,unique,1 +.Lcu_begin1: + .long 1 + .quad .debug_abbrev + .quad .text +.section .debug_info,"",@progbits,unique,2 + .long 2 + .quad .debug_abbrev + .quad .text +## No relocation, arbitrarily treated as a DWARF32. +.section .debug_info,"",@progbits,unique,3 +.Lcu_begin3: + .long 3 +.section .debug_info,"",@progbits,unique,4 + .long 4 + .long .debug_abbrev + .quad .text + +## Test an arbitrary different .debug_*. +.section .debug_aranges,"",@progbits,unique,1 + .quad .Lcu_begin1 +.section .debug_aranges,"",@progbits,unique,3 + .long .Lcu_begin3 + +## Test that non-.debug_* sections are not ordered. +.section .nondebug,"",@progbits,unique,1 + .long 1 + .quad .Lcu_begin1 +.section .nondebug,"",@progbits,unique,2 + .long 2 + .long .Lcu_begin1 + +#--- lds +SECTIONS { + .debug_info 0 : { *(.debug_info) } +}