From dc4df5da886e09d36577b3302952bc91b5e7e154 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 22 Mar 2026 20:22:44 -0700 Subject: [PATCH] [ELF] Always separate relative relocations regardless of -z combreloc (#187964) Remove the combreloc guard from addReloc and mergeRels so that relative relocations are always routed to relativeRelocs, even with -z nocombreloc or --pack-dyn-relocs=android. Update AndroidPackedRelocationSection::updateAllocSize to iterate both relativeRelocs and relocs. --- lld/ELF/SyntheticSections.cpp | 31 ++++++++++++++++--------------- lld/ELF/SyntheticSections.h | 2 +- lld/test/ELF/combreloc.s | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 38d9eeacf0cf..8157365f89b3 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1519,9 +1519,11 @@ void RelocationBaseSection::mergeRels() { void RelocationBaseSection::finalizeContents() { mergeRels(); - // Cache the count for DT_RELACOUNT. This must not change after - // DynamicSection::finalizeContents sizes the .dynamic section. - numRelativeRelocs = relativeRelocs.size(); + // Cache the count for DT_RELACOUNT. DynamicSection::computeContents + // uses ctx.arg.zCombreloc (not the per-section combreloc) to decide whether + // to emit DT_RELACOUNT, so this must match. + if (combreloc) + numRelativeRelocs = relativeRelocs.size(); SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get(); // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE @@ -1685,23 +1687,22 @@ bool AndroidPackedRelocationSection::updateAllocSize(Ctx &ctx) { // The format header includes the number of relocations and the initial // offset (we set this to zero because the first relocation group will // perform the initial adjustment). - add(relocs.size()); + add(relativeRelocs.size() + relocs.size()); add(0); - std::vector relatives, nonRelatives; - - for (const DynamicReloc &rel : relocs) { + SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get(); + auto makeRela = [&](const DynamicReloc &rel) { Elf_Rela r; r.r_offset = rel.getOffset(); - r.setSymbolAndType(rel.getSymIndex(getPartition(ctx).dynSymTab.get()), - rel.type, false); + r.setSymbolAndType(rel.getSymIndex(symTab), rel.type, false); r.r_addend = ctx.arg.isRela ? rel.computeAddend(ctx) : 0; - - if (r.getType(ctx.arg.isMips64EL) == ctx.target->relativeRel) - relatives.push_back(r); - else - nonRelatives.push_back(r); - } + return r; + }; + std::vector relatives, nonRelatives; + for (const DynamicReloc &rel : relativeRelocs) + relatives.push_back(makeRela(rel)); + for (const DynamicReloc &rel : relocs) + nonRelatives.push_back(makeRela(rel)); llvm::sort(relatives, [](const Elf_Rel &a, const Elf_Rel &b) { return a.r_offset < b.r_offset; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 0373518ecd42..92dcbb922aa5 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -495,7 +495,7 @@ public: /// This overload can be used if the addends are written directly instead of /// using relocations on the input section (e.g. MipsGotSection::writeTo()). template void addReloc(const DynamicReloc &reloc) { - if (combreloc && reloc.type == relativeRel) + if (reloc.type == relativeRel) relativeRelocs.push_back(reloc); else relocs.push_back(reloc); diff --git a/lld/test/ELF/combreloc.s b/lld/test/ELF/combreloc.s index 59dedceb633f..08e404c66676 100644 --- a/lld/test/ELF/combreloc.s +++ b/lld/test/ELF/combreloc.s @@ -31,12 +31,12 @@ # NOCOMB-NOT: RELACOUNT # NOCOMB: Relocations [ # NOCOMB-NEXT: Section ({{.*}}) .rela.dyn { +# NOCOMB-NEXT: 0x3418 R_X86_64_RELATIVE - 0x3420 # NOCOMB-NEXT: 0x33F8 R_X86_64_64 aaa 0x0 # NOCOMB-NEXT: 0x3400 R_X86_64_64 ccc 0x0 # NOCOMB-NEXT: 0x3408 R_X86_64_64 bbb 0x0 # NOCOMB-NEXT: 0x3410 R_X86_64_64 aaa 0x0 # NOCOMB-NEXT: 0x23F0 R_X86_64_GLOB_DAT aaa 0x0 -# NOCOMB-NEXT: 0x3418 R_X86_64_RELATIVE - 0x3420 # NOCOMB-NEXT: } .globl aaa, bbb, ccc