[llvm] 2b2f4ae - [llvm-objcopy] Add --change-section-address (#98664)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 30 02:58:04 PDT 2024
Author: Eleanor Bonnici
Date: 2024-07-30T10:57:57+01:00
New Revision: 2b2f4ae0fbe366ebaa8811bed567a6ff76bbe3b1
URL: https://github.com/llvm/llvm-project/commit/2b2f4ae0fbe366ebaa8811bed567a6ff76bbe3b1
DIFF: https://github.com/llvm/llvm-project/commit/2b2f4ae0fbe366ebaa8811bed567a6ff76bbe3b1.diff
LOG: [llvm-objcopy] Add --change-section-address (#98664)
--change-section address and its alias --adjust-section-vma allows
modification
of section addresses in a relocatable file. This used to be used, for
example,
in Fiasco microkernel.
On a relocatable file this option behaves the same as GNU objcopy, apart
from
the fact that it does not issue any warnings, for example, when an
argument is
not used.
GNU objcopy does not produce an error when passed an executable file but
the
usecase for this is not clear, and the behaviour is inconsistent. The
idea of
GNU objcopy --change-section-address is that the option should change
both LMA
and VMA in an executable file. Since this patch does not implement
executable
file support, only VMA is changed.
Added:
llvm/test/tools/llvm-objcopy/ELF/change-section-address.test
Modified:
llvm/docs/CommandGuide/llvm-objcopy.rst
llvm/include/llvm/ObjCopy/CommonConfig.h
llvm/lib/ObjCopy/ConfigManager.cpp
llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
llvm/tools/llvm-objcopy/ObjcopyOpts.td
Removed:
################################################################################
diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index 8ccb025a3f0f3..7f20a76550c83 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -303,6 +303,15 @@ them.
Shift LMA of non-zero-sized segments by ``<val>``.
+.. option:: --change-section-address <section>{=+-}<val>, --adjust-section-vma
+
+ Change the address of sections that match ``<section>`` pattern to the
+ specified value, or apply ``+<val>``/``-<val>`` to the current value. Can be
+ specified multiple times to specify multiple patterns. Each section is only
+ modified by one ``--change-section-address`` argument. If a section name
+ matches multiple patterns, the rightmost change applies. The object file needs
+ to be of ET_REL type.
+
.. option:: --change-start <incr>, --adjust-start
Add ``<incr>`` to the program's start address. Can be specified multiple
diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index 7f9d90d528b3e..5ae09760e9a54 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -151,6 +151,18 @@ class NameMatcher {
}
};
+enum class AdjustKind { Set, Add, Subtract };
+
+struct AddressUpdate {
+ uint64_t Value = 0;
+ AdjustKind Kind = AdjustKind::Add;
+};
+
+struct SectionPatternAddressUpdate {
+ NameMatcher SectionPattern;
+ AddressUpdate Update;
+};
+
enum class SymbolFlag {
Global,
Local,
@@ -219,6 +231,7 @@ struct CommonConfig {
SmallVector<NewSectionInfo, 0> AddSection;
SmallVector<StringRef, 0> DumpSection;
SmallVector<NewSectionInfo, 0> UpdateSection;
+ SmallVector<SectionPatternAddressUpdate, 0> ChangeSectionAddress;
// Section matchers
NameMatcher KeepSection;
diff --git a/llvm/lib/ObjCopy/ConfigManager.cpp b/llvm/lib/ObjCopy/ConfigManager.cpp
index c542c4e5f0743..78fc0c451e1a3 100644
--- a/llvm/lib/ObjCopy/ConfigManager.cpp
+++ b/llvm/lib/ObjCopy/ConfigManager.cpp
@@ -26,7 +26,8 @@ Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
Common.DecompressDebugSections ||
Common.DiscardMode == DiscardType::Locals ||
!Common.SymbolsToAdd.empty() || Common.GapFill != 0 ||
- Common.PadTo != 0 || Common.ChangeSectionLMAValAll != 0)
+ Common.PadTo != 0 || Common.ChangeSectionLMAValAll != 0 ||
+ !Common.ChangeSectionAddress.empty())
return createStringError(llvm::errc::invalid_argument,
"option is not supported for COFF");
@@ -48,7 +49,8 @@ Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
Common.DecompressDebugSections || Common.StripUnneeded ||
Common.DiscardMode == DiscardType::Locals ||
!Common.SymbolsToAdd.empty() || Common.GapFill != 0 ||
- Common.PadTo != 0 || Common.ChangeSectionLMAValAll != 0)
+ Common.PadTo != 0 || Common.ChangeSectionLMAValAll != 0 ||
+ !Common.ChangeSectionAddress.empty())
return createStringError(llvm::errc::invalid_argument,
"option is not supported for MachO");
@@ -68,7 +70,8 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
!Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
!Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
!Common.SymbolsToRename.empty() || Common.GapFill != 0 ||
- Common.PadTo != 0 || Common.ChangeSectionLMAValAll != 0)
+ Common.PadTo != 0 || Common.ChangeSectionLMAValAll != 0 ||
+ !Common.ChangeSectionAddress.empty())
return createStringError(llvm::errc::invalid_argument,
"only flags for section dumping, removal, and "
"addition are supported");
@@ -97,7 +100,8 @@ Expected<const XCOFFConfig &> ConfigManager::getXCOFFConfig() const {
Common.StripDebug || Common.StripNonAlloc || Common.StripSections ||
Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections ||
Common.GapFill != 0 || Common.PadTo != 0 ||
- Common.ChangeSectionLMAValAll != 0) {
+ Common.ChangeSectionLMAValAll != 0 ||
+ !Common.ChangeSectionAddress.empty()) {
return createStringError(
llvm::errc::invalid_argument,
"no flags are supported yet, only basic copying is allowed");
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 075455c034154..40598861d4273 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -745,6 +745,56 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
}
}
+ if (!Config.ChangeSectionAddress.empty()) {
+ if (Obj.Type != ELF::ET_REL)
+ return createStringError(
+ object_error::invalid_file_type,
+ "cannot change section address in a non-relocatable file");
+
+ StringMap<AddressUpdate> SectionsToUpdateAddress;
+ for (const SectionPatternAddressUpdate &PatternUpdate :
+ make_range(Config.ChangeSectionAddress.rbegin(),
+ Config.ChangeSectionAddress.rend())) {
+ for (SectionBase &Sec : Obj.sections()) {
+ if (PatternUpdate.SectionPattern.matches(Sec.Name) &&
+ SectionsToUpdateAddress.try_emplace(Sec.Name, PatternUpdate.Update)
+ .second) {
+ if (PatternUpdate.Update.Kind == AdjustKind::Subtract &&
+ Sec.Addr < PatternUpdate.Update.Value) {
+ return createStringError(
+ errc::invalid_argument,
+ "address 0x" + Twine::utohexstr(Sec.Addr) +
+ " cannot be decreased by 0x" +
+ Twine::utohexstr(PatternUpdate.Update.Value) +
+ ". The result would underflow");
+ }
+ if (PatternUpdate.Update.Kind == AdjustKind::Add &&
+ Sec.Addr > std::numeric_limits<uint64_t>::max() -
+ PatternUpdate.Update.Value) {
+ return createStringError(
+ errc::invalid_argument,
+ "address 0x" + Twine::utohexstr(Sec.Addr) +
+ " cannot be increased by 0x" +
+ Twine::utohexstr(PatternUpdate.Update.Value) +
+ ". The result would overflow");
+ }
+
+ switch (PatternUpdate.Update.Kind) {
+ case (AdjustKind::Set):
+ Sec.Addr = PatternUpdate.Update.Value;
+ break;
+ case (AdjustKind::Subtract):
+ Sec.Addr -= PatternUpdate.Update.Value;
+ break;
+ case (AdjustKind::Add):
+ Sec.Addr += PatternUpdate.Update.Value;
+ break;
+ }
+ }
+ }
+ }
+ }
+
if (Config.OnlyKeepDebug)
for (auto &Sec : Obj.sections())
if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
diff --git a/llvm/test/tools/llvm-objcopy/ELF/change-section-address.test b/llvm/test/tools/llvm-objcopy/ELF/change-section-address.test
new file mode 100644
index 0000000000000..b17b1492690af
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/change-section-address.test
@@ -0,0 +1,199 @@
+## This test tests the behavior of --change-section-address option.
+
+# RUN: yaml2obj -DTYPE=REL %s -o %ti1
+
+## Basic check that the option processes wildcards and changes the address as expected.
+# RUN: llvm-objcopy --change-section-address *+0x20 %ti1 %to1
+# RUN: llvm-readelf --section-headers %to1 | FileCheck %s --check-prefix=CHECK-ADD-ALL
+
+## Check that --change-section-address alias --adjust-section-vma produces the same output as the test above.
+# RUN: llvm-objcopy --adjust-section-vma *+0x20 %ti1 %to2
+# RUN: cmp %to1 %to2
+
+## Check that negative adjustment reduces the address by the specified value.
+# RUN: llvm-objcopy --change-section-address .anotherone-0x30 %ti1 %to3
+# RUN: llvm-readelf --section-headers %to3 | FileCheck %s --check-prefix=CHECK-SUB-SECTION
+
+## Check that a wildcard pattern works and only the specified sections are updated.
+# RUN: llvm-objcopy --change-section-address .text*+0x20 %ti1 %to4
+# RUN: llvm-readelf --section-headers %to4 | FileCheck %s --check-prefix=CHECK-ADD-PATTERN
+
+## Check that regex pattern can be used with --change-section-address.
+# RUN: llvm-objcopy --regex --change-section-address .text.+0x20 %ti1 %to5
+# RUN: llvm-readelf --section-headers %to5 | FileCheck %s --check-prefix=CHECK-ADD-PATTERN
+
+## Check that a section address can be set to a specific value.
+# RUN: llvm-objcopy --change-section-address .text*=0x10 %ti1 %to6
+# RUN: llvm-readelf --section-headers %to6 | FileCheck %s --check-prefix=CHECK-SET-PATTERN
+
+## Check setting that a section address can be set to the maximum possible value (UINT64_MAX).
+# RUN: llvm-objcopy --change-section-address .text2=0xffffffffffffffff %ti1 %to7
+# RUN: llvm-readelf --section-headers %to7 | FileCheck %s --check-prefix=CHECK-MAX
+
+## Check that a section address can be adjusted to the maximum possible value (UINT64_MAX).
+# RUN: llvm-objcopy --change-section-address .text2+0xfffffffffffffdff %ti1 %to8
+# RUN: llvm-readelf --section-headers %to8 | FileCheck %s --check-prefix=CHECK-MAX
+
+## Check that the section address can be adjusted to the minimum possible value (0).
+# RUN: llvm-objcopy --change-section-address .text2-0x200 %ti1 %to9
+# RUN: llvm-readelf --section-headers %to9 | FileCheck %s --check-prefix=CHECK-ZERO
+
+## Check that a section address can be adjusted by a maximum possible positive offset (UINT64_MAX).
+# RUN: llvm-objcopy --change-section-address .text2=0 %ti1 %to10
+# RUN: llvm-objcopy --change-section-address .text2+0xffffffffffffffff %to10 %to11
+# RUN: llvm-readelf --section-headers %to11 | FileCheck %s --check-prefix=CHECK-MAX
+
+## Check that a section address can be adjusted by a maximum possible negative offset (UINT64_MIN).
+# RUN: llvm-objcopy --change-section-address .text2=0xffffffffffffffff %ti1 %to12
+# RUN: llvm-objcopy --change-section-address .text2-0xffffffffffffffff %to12 %to13
+# RUN: llvm-readelf --section-headers %to13 | FileCheck %s --check-prefix=CHECK-ZERO
+
+## Check two independent changes.
+# RUN: llvm-objcopy --change-section-address .text1=0x110 --change-section-address .text2=0x210 %ti1 %to14
+# RUN: llvm-readelf --section-headers %to14 | FileCheck %s --check-prefix=CHECK-INDEPENDENT
+
+## Check two overlapping changes.
+# RUN: llvm-objcopy --change-section-address .anotherone-0x30 --change-section-address .anotherone+0x20 %ti1 %to15
+# RUN: llvm-readelf --section-headers %to15 | FileCheck %s --check-prefix=CHECK-USE-LAST
+
+## Check unused option.
+# RUN: llvm-objcopy --change-section-address .anotherone=0x455 --change-section-address *+0x20 %ti1 %to16
+# RUN: llvm-readelf --section-headers %to16 | FileCheck %s --check-prefix=CHECK-NOTSUPERSET-SET
+
+## Check partial overlap (.anotherone overlaps).
+# RUN: llvm-objcopy --change-section-address *+0x20 --change-section-address .anotherone=0x455 %ti1 %to17
+# RUN: llvm-readelf --section-headers %to17 | FileCheck %s --check-prefix=CHECK-SUPERSET-SET
+
+## Check more complex partial overlap (P1: .anotherone, .text2, P2: .text1, text2) (.text2 overlaps).
+# RUN: llvm-objcopy --regex --change-section-address ".(text2|anotherone)+0x20" --change-section-address .text.*+0x30 %ti1 %to18
+# RUN: llvm-readelf --section-headers %to18 | FileCheck %s --check-prefix=CHECK-PARTIAL-OVERLAP
+
+# CHECK-ADD-ALL: [Nr] Name Type Address
+# CHECK-ADD-ALL: .text1
+# CHECK-ADD-ALL-SAME: 0000000000000120
+# CHECK-ADD-ALL: .text2
+# CHECK-ADD-ALL-SAME: 0000000000000220
+# CHECK-ADD-ALL: .anotherone
+# CHECK-ADD-ALL-SAME: 0000000000000320
+# CHECK-ADD-ALL: =a-b+c++d
+# CHECK-ADD-ALL-SAME: 0000000000000420
+# CHECK-ADD-ALL: .strtab
+# CHECK-ADD_ALL-SAME: 0000000000000020
+# CHECK-ADD-ALL: .shstrtab
+# CHECK-ADD-ALL-SAME: 0000000000000020
+
+# CHECK-SUB-SECTION: .text1
+# CHECK-SUB-SECTION-SAME: 0000000000000100
+# CHECK-SUB-SECTION: .text2
+# CHECK-SUB-SECTION-SAME: 0000000000000200
+# CHECK-SUB-SECTION: .anotherone
+# CHECK-SUB-SECTION-SAME: 00000000000002d0
+
+# CHECK-ADD-PATTERN: .text1
+# CHECK-ADD-PATTERN-SAME: 0000000000000120
+# CHECK-ADD-PATTERN: .text2
+# CHECK-ADD-PATTERN-SAME: 0000000000000220
+# CHECK-ADD-PATTERN: .anotherone
+# CHECK-ADD-PATTERN-SAME: 0000000000000300
+
+# CHECK-SET-PATTERN: .text1
+# CHECK-SET-PATTERN-SAME: 0000000000000010
+# CHECK-SET-PATTERN: .text2
+# CHECK-SET-PATTERN-SAME: 0000000000000010
+# CHECK-SET-PATTERN: .anotherone
+# CHECK-SET-PATTERN-SAME: 0000000000000300
+
+# CHECK-MAX: .text2
+# CHECK-MAX-SAME: ffffffffffffffff
+# CHECK-ZERO: .text2
+# CHECK-ZERO-SAME: 0000000000000000
+
+# CHECK-INDEPENDENT: .text1
+# CHECK-INDEPENDENT-SAME: 0000000000000110
+# CHECK-INDEPENDENT: .text2
+# CHECK-INDEPENDENT-SAME: 0000000000000210
+
+# CHECK-USE-LAST: .anotherone
+# CHECK-USE-LAST-SAME: 0000000000000320
+
+# CHECK-NOTSUPERSET-SET: .text1
+# CHECK-NOTSUPERSET-SET-SAME: 0000000000000120
+# CHECK-NOTSUPERSET-SET: .text2
+# CHECK-NOTSUPERSET-SET-SAME: 0000000000000220
+# CHECK-NOTSUPERSET-SET: .anotherone
+# CHECK-NOTSUPERSET-SET-SAME: 0000000000000320
+
+# CHECK-SUPERSET-SET: .text1
+# CHECK-SUPERSET-SET-SAME: 0000000000000120
+# CHECK-SUPERSET-SET: .text2
+# CHECK-SUPERSET-SET-SAME: 0000000000000220
+# CHECK-SUPERSET-SET: .anotherone
+# CHECK-SUPERSET-SET-SAME: 0000000000000455
+
+# CHECK-PARTIAL-OVERLAP: .text1
+# CHECK-PARTIAL-OVERLAP-SAME: 0000000000000130
+# CHECK-PARTIAL-OVERLAP: .text2
+# CHECK-PARTIAL-OVERLAP-SAME: 0000000000000230
+# CHECK-PARTIAL-OVERLAP: .anotherone
+# CHECK-PARTIAL-OVERLAP-SAME: 0000000000000320
+
+## Check overflow by 1.
+# RUN: not llvm-objcopy --change-section-address .anotherone+0xfffffffffffffd00 %ti1 2>&1 | FileCheck %s --check-prefix=ERR-OVERFLOW
+## Check underflow by 1.
+# RUN: not llvm-objcopy --change-section-address .text2-0x201 %ti1 2>&1 | FileCheck %s --check-prefix=ERR-UNDERFLOW
+## Check error when argument value is invalid as a whole.
+# RUN: not llvm-objcopy --change-section-address 0 %ti1 2>&1 | FileCheck %s --check-prefix=ERR-IVALID-VAL
+## Check error when the value is invalid in the argument value.
+# RUN: not llvm-objcopy --change-section-address .anotherone+0c50 %ti1 2>&1 | FileCheck %s --check-prefix=ERR-NOT-INTEGER
+## Check error when the value does not fit in uint64_t.
+# RUN not llvm-objcopy --change-section-address .text1=0x10000000000000000 %ti1 %to 2>&1 | FileCheck %s --chack-prefix=ERR-NOT-INTEGER
+## Check error when the section pattern is missing.
+# RUN: not llvm-objcopy --change-section-address =0x10 %ti1 2>&1 | FileCheck %s --check-prefix=ERR-MISSING-SECTION
+## Check error when the negative adjustment value is missing.
+# RUN: not llvm-objcopy --change-section-address .text1- %ti1 2>&1 | FileCheck %s --check-prefix=ERR-MISSING-VALUE-MINUS
+## Check error when the positive adjustment value is missing.
+# RUN: not llvm-objcopy --change-section-address .text1+ %ti1 2>&1 | FileCheck %s --check-prefix=ERR-MISSING-VALUE-PLUS
+## Check error when the value to set the address to is missing.
+# RUN: not llvm-objcopy --change-section-address .text1= %ti1 2>&1 | FileCheck %s --check-prefix=ERR-MISSING-VALUE-EQUAL
+## Check error when the provided regex is invalid.
+# RUN: not llvm-objcopy --regex --change-section-address "ab**-0x20" %ti1 2>&1 | FileCheck %s --check-prefix=ERR-MATCHER-FAILURE
+
+# ERR-OVERFLOW: address 0x300 cannot be increased by 0xfffffffffffffd00. The result would overflow
+# ERR-UNDERFLOW: address 0x200 cannot be decreased by 0x201. The result would underflow
+# ERR-IVALID-VAL: error: bad format for --change-section-address: argument value 0 is invalid. See --help
+# ERR-NOT-INTEGER: error: bad format for --change-section-address: value after + is 0c50 when it should be a 64-bit integer
+# ERR-MISSING-SECTION: error: bad format for --change-section-address: missing section pattern to apply address change to
+# ERR-MISSING-VALUE-MINUS: error: bad format for --change-section-address: missing value of offset after '-'
+# ERR-MISSING-VALUE-PLUS: error: bad format for --change-section-address: missing value of offset after '+'
+# ERR-MISSING-VALUE-EQUAL: error: bad format for --change-section-address: missing address value after '='
+# ERR-MATCHER-FAILURE: error: cannot compile regular expression 'ab**': repetition-operator operand invalid
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_[[TYPE]]
+Sections:
+ - Name: .text1
+ Type: SHT_PROGBITS
+ Size: 0x100
+ Address: 0x100
+ - Name: .text2
+ Type: SHT_PROGBITS
+ Size: 0x100
+ Address: 0x200
+ - Name: .anotherone
+ Type: SHT_PROGBITS
+ Size: 0x100
+ Address: 0x300
+ - Name: =a-b+c++d
+ Type: SHT_PROGBITS
+ Size: 0x100
+ Address: 0x400
+
+# RUN: yaml2obj -DTYPE=EXEC %s -o %ti2
+
+## Input file is not ET_REL
+# RUN: not llvm-objcopy --change-section-address *+0x20 %ti2 2>&1 | FileCheck %s --check-prefix=ERR-FILE-TYPE
+
+# ERR-FILE-TYPE: cannot change section address in a non-relocatable file
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index a54feb7644bda..d82ecc8b3d36e 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -584,6 +584,68 @@ static Expected<int64_t> parseChangeSectionLMA(StringRef ArgValue,
return *LMAValue;
}
+static Expected<SectionPatternAddressUpdate>
+parseChangeSectionAddr(StringRef ArgValue, StringRef OptionName,
+ MatchStyle SectionMatchStyle,
+ function_ref<Error(Error)> ErrorCallback) {
+ SectionPatternAddressUpdate PatternUpdate;
+
+ size_t LastSymbolIndex = ArgValue.find_last_of("+-=");
+ if (LastSymbolIndex == StringRef::npos)
+ return createStringError(errc::invalid_argument,
+ "bad format for " + OptionName +
+ ": argument value " + ArgValue +
+ " is invalid. See --help");
+ char UpdateSymbol = ArgValue[LastSymbolIndex];
+
+ StringRef SectionPattern = ArgValue.slice(0, LastSymbolIndex);
+ if (SectionPattern.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for " + OptionName +
+ ": missing section pattern to apply address change to");
+ if (Error E = PatternUpdate.SectionPattern.addMatcher(NameOrPattern::create(
+ SectionPattern, SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
+
+ StringRef Value = ArgValue.slice(LastSymbolIndex + 1, StringRef::npos);
+ if (Value.empty()) {
+ switch (UpdateSymbol) {
+ case '+':
+ case '-':
+ return createStringError(errc::invalid_argument,
+ "bad format for " + OptionName +
+ ": missing value of offset after '" +
+ std::string({UpdateSymbol}) + "'");
+
+ case '=':
+ return createStringError(errc::invalid_argument,
+ "bad format for " + OptionName +
+ ": missing address value after '='");
+ }
+ }
+ auto AddrValue = getAsInteger<uint64_t>(Value);
+ if (!AddrValue)
+ return createStringError(AddrValue.getError(),
+ "bad format for " + OptionName + ": value after " +
+ std::string({UpdateSymbol}) + " is " + Value +
+ " when it should be a 64-bit integer");
+
+ switch (UpdateSymbol) {
+ case '+':
+ PatternUpdate.Update.Kind = AdjustKind::Add;
+ break;
+ case '-':
+ PatternUpdate.Update.Kind = AdjustKind::Subtract;
+ break;
+ case '=':
+ PatternUpdate.Update.Kind = AdjustKind::Set;
+ }
+
+ PatternUpdate.Update.Value = *AddrValue;
+ return PatternUpdate;
+}
+
// parseObjcopyOptions returns the config and sets the input arguments. If a
// help flag is set then parseObjcopyOptions will print the help messege and
// exit.
@@ -874,6 +936,15 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
Config.ChangeSectionLMAValAll = *LMAValue;
}
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_change_section_address)) {
+ Expected<SectionPatternAddressUpdate> AddressUpdate =
+ parseChangeSectionAddr(Arg->getValue(), Arg->getSpelling(),
+ SectionMatchStyle, ErrorCallback);
+ if (!AddressUpdate)
+ return AddressUpdate.takeError();
+ Config.ChangeSectionAddress.push_back(*AddressUpdate);
+ }
+
for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
if (!StringRef(Arg->getValue()).contains('='))
return createStringError(errc::invalid_argument,
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index b26c497ca3997..434b5ff92324e 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -267,6 +267,13 @@ defm change_section_lma
: Eq<"change-section-lma", "Shift LMA of non-zero-sized sections in the program header by <val>">,
MetaVarName<"*{+|-}val">;
+defm change_section_address
+ : Eq<"change-section-address", "Set the address of the <section> to, or adjust it by, <val>">,
+ MetaVarName<"sectionpattern{=|+|-}val">;
+def adjust_section_vma : JoinedOrSeparate<["--"], "adjust-section-vma">,
+ Alias<change_section_address>,
+ HelpText<"Alias for --change-section-address">;
+
defm add_symbol
: Eq<"add-symbol", "Add new symbol <name> to .symtab. Accepted flags: "
"global, local, weak, default, hidden, protected, file, section, object, "
More information about the llvm-commits
mailing list