aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEleanor Bonnici <eleanor.bonnici@arm.com>2024-07-30 10:57:57 +0100
committerGitHub <noreply@github.com>2024-07-30 10:57:57 +0100
commit2b2f4ae0fbe366ebaa8811bed567a6ff76bbe3b1 (patch)
tree3c3ffd78b82432a329cd1846d69a101a456a3048
parentca8a4111f796fe8533e0af95557875b15becff06 (diff)
downloadllvm-2b2f4ae0fbe366ebaa8811bed567a6ff76bbe3b1.zip
llvm-2b2f4ae0fbe366ebaa8811bed567a6ff76bbe3b1.tar.gz
llvm-2b2f4ae0fbe366ebaa8811bed567a6ff76bbe3b1.tar.bz2
[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.
-rw-r--r--llvm/docs/CommandGuide/llvm-objcopy.rst9
-rw-r--r--llvm/include/llvm/ObjCopy/CommonConfig.h13
-rw-r--r--llvm/lib/ObjCopy/ConfigManager.cpp12
-rw-r--r--llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp50
-rw-r--r--llvm/test/tools/llvm-objcopy/ELF/change-section-address.test199
-rw-r--r--llvm/tools/llvm-objcopy/ObjcopyOptions.cpp71
-rw-r--r--llvm/tools/llvm-objcopy/ObjcopyOpts.td7
7 files changed, 357 insertions, 4 deletions
diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index 8ccb025..7f20a76 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 7f9d90d..5ae0976 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -151,6 +151,18 @@ public:
}
};
+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 c542c4e..78fc0c4 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 075455c..4059886 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 0000000..b17b149
--- /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 a54feb7..d82ecc8 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 b26c497..434b5ff 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, "