[llvm] [llvm-objcopy] --change-section-lma: skip segments with no assigned address (PR #218414)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 24 06:59:56 PDT 2026
https://github.com/GoranWall updated https://github.com/llvm/llvm-project/pull/218414
>From a195c69d9e760bfb7206168e08e03cf3ae6a5c32 Mon Sep 17 00:00:00 2001
From: goranwa <goran.wall at iar.com>
Date: Mon, 24 Aug 2026 15:05:56 +0200
Subject: [PATCH] [llvm-objcopy] --change-section-lma: skip segments with no
assigned address
--change-section-lma shifts the LMA of any segment with a nonzero
MemSize, regardless of whether the segment was ever assigned a real
address. This is incorrect for segment types that can carry a
nonzero MemSize/FileSize without representing real, addressable
memory, such as PT_RISCV_ATTRIBUTES: these commonly have VAddr and
PAddr both equal to 0, since they were never placed anywhere by the
linker.
When --change-section-lma is given a shift larger than such a
segment's PAddr, the existing overflow/underflow check fires and
objcopy aborts entirely with "address 0x0 cannot be decreased by
0x...", even though the segment was never meant to be relocated.
GNU objcopy does not exhibit this behavior.
This was observed on a RISC-V ELF containing a PT_RISCV_ATTRIBUTES
segment at address 0 alongside ordinary PT_LOAD segments; shifting
the LMA of the PT_LOAD segments via --change-section-lma *-<offset>
also attempted to shift the unrelated, unaddressed attributes
segment, underflowing and aborting the whole operation.
Restrict the shift to segments that have a real VAddr or PAddr,
which preserves existing behavior for segments like PT_PHDR (which
does have a real address and must continue to shift) while excluding
segments that were never assigned one.
Adds a regression test (change-section-lma-unaddressed-segment.test)
using a synthetic PT_RISCV_ATTRIBUTES-like segment to verify it is
excluded from the shift in both directions, and no longer triggers a
spurious underflow/overflow error.
See also #124680 (related --change-section-lma segment-eligibility
discrepancy vs. GNU objcopy in the same code path).
---
llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 2 +-
...hange-section-lma-unaddressed-segment.test | 38 +++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/tools/llvm-objcopy/ELF/change-section-lma-unaddressed-segment.test
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index edb6ae0a5b108..0e3d23a38dc5a 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -823,7 +823,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
if (Config.ChangeSectionLMAValAll != 0) {
for (Segment &Seg : Obj.segments()) {
- if (Seg.MemSize > 0) {
+ if (Seg.MemSize > 0 && (Seg.VAddr != 0 || Seg.PAddr != 0)) {
if (Config.ChangeSectionLMAValAll > 0 &&
Seg.PAddr > std::numeric_limits<uint64_t>::max() -
Config.ChangeSectionLMAValAll) {
diff --git a/llvm/test/tools/llvm-objcopy/ELF/change-section-lma-unaddressed-segment.test b/llvm/test/tools/llvm-objcopy/ELF/change-section-lma-unaddressed-segment.test
new file mode 100644
index 0000000000000..b1fa86d7e3810
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/change-section-lma-unaddressed-segment.test
@@ -0,0 +1,38 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --change-section-lma *-0x30 %t %t2
+# RUN: llvm-readelf --program-headers %t2 | FileCheck %s
+
+# Regression test: a segment with a nonzero MemSize but no assigned
+# VAddr/PAddr (e.g. PT_RISCV_ATTRIBUTES) must not participate in
+# --change-section-lma; previously this caused a spurious underflow
+# error when shifting other segments downward.
+#
+# This is a separate file (rather than an addition to
+# change-section-lma.test) because that file's first LOAD segment's
+# size is implicitly derived from the total program header table
+# size, making it fragile to extend with additional entries.
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x10
+ - Name: .riscv.attributes
+ Type: SHT_PROGBITS
+ Size: 0x3f
+ProgramHeaders:
+ - Type: PT_LOAD
+ VAddr: 0x1000
+ FirstSec: .text
+ LastSec: .text
+ - Type: 0x70000003
+ Flags: [ PF_R ]
+ VAddr: 0x0
+ PAddr: 0x0
+ Align: 0x1
+ FirstSec: .riscv.attributes
+ LastSec: .riscv.attributes
More information about the llvm-commits
mailing list