[llvm] 6f1395a - [llvm-objcopy] --set-section-flags: allow "large" to add SHF_X86_64_LARGE
Arthur Eubanks via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 25 09:47:41 PDT 2023
Author: Thomas Köppe
Date: 2023-07-25T09:47:02-07:00
New Revision: 6f1395a1fef5533a5a8dfdb8621eab7de3922cc3
URL: https://github.com/llvm/llvm-project/commit/6f1395a1fef5533a5a8dfdb8621eab7de3922cc3
DIFF: https://github.com/llvm/llvm-project/commit/6f1395a1fef5533a5a8dfdb8621eab7de3922cc3.diff
LOG: [llvm-objcopy] --set-section-flags: allow "large" to add SHF_X86_64_LARGE
Currently, objcopy cannot set the new flag SHF_X86_64_LARGE. This change introduces the named flag "large" which translates to that section flag.
An "invalid argument" error is produced if a user attempts to set the flag on an architecture other than X86_64.
Reviewed By: jhenderson, MaskRay
Differential Revision: https://reviews.llvm.org/D153262
Added:
llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test
Modified:
llvm/docs/CommandGuide/llvm-objcopy.rst
llvm/include/llvm/ObjCopy/CommonConfig.h
llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
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 8894a7fea6bb75..0233a4f7b2f045 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -137,8 +137,9 @@ multiple file formats.
sections.
Supported flag names are `alloc`, `load`, `noload`, `readonly`, `exclude`,
- `debug`, `code`, `data`, `rom`, `share`, `contents`, `merge` and `strings`. Not
- all flags are meaningful for all object file formats.
+ `debug`, `code`, `data`, `rom`, `share`, `contents`, `merge`, `strings`, and
+ `large`. Not all flags are meaningful for all object file formats or target
+ architectures.
For ELF objects, the flags have the following effects:
@@ -152,6 +153,8 @@ multiple file formats.
- `strings` = add the `SHF_STRINGS` flag.
- `contents` = if the section has `SHT_NOBITS` type, mark it as a `SHT_PROGBITS`
section.
+ - `large` = add the `SHF_X86_64_LARGE` on x86_64; rejected if the target
+ architecture is not x86_64.
For COFF objects, the flags have the following effects:
diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index 17ca9e8be228ea..e7ce1e6f2c54d7 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -69,7 +69,8 @@ enum SectionFlag {
SecContents = 1 << 10,
SecShare = 1 << 11,
SecExclude = 1 << 12,
- LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/SecExclude)
+ SecLarge = 1 << 13,
+ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/SecLarge)
};
struct SectionRename {
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index dfe843e1d4b7a4..58cb9cb65679b7 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -68,7 +68,8 @@ static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
return !isDWOSection(Sec);
}
-static uint64_t getNewShfFlags(SectionFlag AllFlags) {
+static Expected<uint64_t> getNewShfFlags(SectionFlag AllFlags,
+ uint16_t EMachine) {
uint64_t NewFlags = 0;
if (AllFlags & SectionFlag::SecAlloc)
NewFlags |= ELF::SHF_ALLOC;
@@ -82,18 +83,27 @@ static uint64_t getNewShfFlags(SectionFlag AllFlags) {
NewFlags |= ELF::SHF_STRINGS;
if (AllFlags & SectionFlag::SecExclude)
NewFlags |= ELF::SHF_EXCLUDE;
+ if (AllFlags & SectionFlag::SecLarge) {
+ if (EMachine != EM_X86_64)
+ return createStringError(errc::invalid_argument,
+ "section flag SHF_X86_64_LARGE can only be used "
+ "with x86_64 architecture");
+ NewFlags |= ELF::SHF_X86_64_LARGE;
+ }
return NewFlags;
}
static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
- uint64_t NewFlags) {
+ uint64_t NewFlags,
+ uint16_t EMachine) {
// Preserve some flags which should not be dropped when setting flags.
// Also, preserve anything OS/processor dependant.
const uint64_t PreserveMask =
(ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |
ELF::SHF_INFO_LINK) &
- ~ELF::SHF_EXCLUDE;
+ ~ELF::SHF_EXCLUDE &
+ ~(EMachine == EM_X86_64 ? ELF::SHF_X86_64_LARGE : 0UL);
return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
}
@@ -105,8 +115,12 @@ static void setSectionType(SectionBase &Sec, uint64_t Type) {
Sec.Type = Type;
}
-static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
- Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags));
+static Error setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags,
+ uint16_t EMachine) {
+ Expected<uint64_t> NewFlags = getNewShfFlags(Flags, EMachine);
+ if (!NewFlags)
+ return NewFlags.takeError();
+ Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, *NewFlags, EMachine);
// In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
// may promote more non-ALLOC sections than GNU objcopy, but it is fine as
@@ -115,6 +129,8 @@ static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
(!(Sec.Flags & ELF::SHF_ALLOC) ||
Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
setSectionType(Sec, ELF::SHT_PROGBITS);
+
+ return Error::success();
}
static ElfType getOutputElfType(const Binary &Bin) {
@@ -681,7 +697,8 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
const auto Iter = Config.SetSectionFlags.find(Sec.Name);
if (Iter != Config.SetSectionFlags.end()) {
const SectionFlagsUpdate &SFU = Iter->second;
- setSectionFlagsAndType(Sec, SFU.NewFlags);
+ if (Error E = setSectionFlagsAndType(Sec, SFU.NewFlags, Obj.Machine))
+ return E;
}
auto It2 = Config.SetSectionType.find(Sec.Name);
if (It2 != Config.SetSectionType.end())
@@ -698,8 +715,10 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
if (Iter != Config.SectionsToRename.end()) {
const SectionRename &SR = Iter->second;
Sec.Name = std::string(SR.NewName);
- if (SR.NewFlags)
- setSectionFlagsAndType(Sec, *SR.NewFlags);
+ if (SR.NewFlags) {
+ if (Error E = setSectionFlagsAndType(Sec, *SR.NewFlags, Obj.Machine))
+ return E;
+ }
RenamedSections.insert(&Sec);
} else if (RelocSec && !(Sec.Flags & SHF_ALLOC))
// Postpone processing relocation sections which are not specified in
diff --git a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
index f0f3c2d86a306f..6141f797ecd49e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
@@ -1,10 +1,14 @@
-# Test that cpu/processor-specific SHF_* flags are preserved.
+# Test that cpu/processor-specific SHF_* flags are preserved,
+# except SHF_X86_64_LARGE on x86_64 (which is controlled with the
+# "large" flag).
# ===== x86_64 =====
# RUN: yaml2obj --docnum=1 %s -o %t-x86_64.o
# RUN: llvm-objcopy --rename-section=.foo=.bar,alloc %t-x86_64.o
# RUN: llvm-readobj --sections %t-x86_64.o | FileCheck %s --check-prefix=X86_64
+# RUN: llvm-objcopy --rename-section=.bar=.quz,alloc,large %t-x86_64.o
+# RUN: llvm-readobj --sections %t-x86_64.o | FileCheck %s --check-prefix=X86_64-LARGE
--- !ELF
FileHeader:
@@ -22,9 +26,16 @@ Sections:
# X86_64-NEXT: Flags [
# X86_64-NEXT: SHF_ALLOC (0x2)
# X86_64-NEXT: SHF_WRITE (0x1)
-# X86_64-NEXT: SHF_X86_64_LARGE (0x10000000)
# X86_64-NEXT: ]
+# X86_64-LARGE: Name: .quz
+# X86_64-LARGE-NEXT: Type: SHT_PROGBITS
+# X86_64-LARGE-NEXT: Flags [
+# X86_64-LARGE-NEXT: SHF_ALLOC (0x2)
+# X86_64-LARGE-NEXT: SHF_WRITE (0x1)
+# X86_64-LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
+# X86_64-LARGE-NEXT: ]
+
# ===== hex =====
# RUN: yaml2obj --docnum=2 %s -o %t-hex.o
diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test
new file mode 100644
index 00000000000000..f75ae170159401
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test
@@ -0,0 +1,69 @@
+# RUN: yaml2obj %s -o %t
+
+## When targetting non-x86_64, the "large" flag is not allowed:
+# RUN: not llvm-objcopy -O elf64-tradbigmips --set-section-flags=.foo=large %t %t.mips.large 2>&1 | FileCheck %s --check-prefixes=BAD-LARGE
+# BAD-LARGE: error: {{.*}}: section flag SHF_X86_64_LARGE can only be used with x86_64 architecture
+
+## Converting x86_64 to non-x86_64 preserves the flag equivalent to SHF_X86_64_LARGE.
+## (This is not a deliberate feature, but it reflects how preservation/setting of flags
+## works for arch-specific flags.)
+# RUN: llvm-objcopy -O elf64-tradbigmips --set-section-flags=.foo=alloc --set-section-flags=.bar=alloc %t %t.mips
+# RUN: llvm-readobj --sections %t.mips | FileCheck %s --check-prefixes=CHECK,REINTERPRET-GPREL
+
+## Converting non-x86_64 to x86_64 clears the flag equivalent to SHF_X86_64_LARGE,
+## and SHF_X86_64_LARGE is set according to the presence of the "large" flag,
+## as long as --set-section-flags is used. If --set-section-flag is _not_ used, then
+## the section flag is retained. (This latter behaviour is also not deliberate.)
+# RUN: llvm-objcopy -O elf64-x86-64 --set-section-flags=.foo=alloc --set-section-flags=.bar=alloc %t.mips %t.x86_64.no-large
+# RUN: llvm-readobj --sections %t.x86_64.no-large | FileCheck %s --check-prefixes=CHECK,REINTERPRET-LARGE
+# RUN: llvm-objcopy -O elf64-x86-64 --set-section-flags=.foo=alloc,large --set-section-flags=.bar=alloc,large %t.mips %t.x86_64.large
+# RUN: llvm-readobj --sections %t.x86_64.large | FileCheck %s --check-prefixes=CHECK,LARGE,REINTERPRET-LARGE
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ ]
+ - Name: .bar
+ Type: SHT_PROGBITS
+ Flags: [ SHF_X86_64_LARGE ]
+ - Name: .untouched
+ Type: SHT_PROGBITS
+ Flags: [ ]
+ - Name: .untouched_large
+ Type: SHT_PROGBITS
+ Flags: [ SHF_X86_64_LARGE ]
+
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# CHECK-NEXT: SHF_WRITE (0x1)
+# LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
+# CHECK-NEXT: ]
+
+# CHECK: Name: .bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# REINTERPRET-GPREL-NEXT: SHF_MIPS_GPREL (0x10000000)
+# CHECK-NEXT: SHF_WRITE (0x1)
+# LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
+# CHECK-NEXT: ]
+
+# CHECK: Name: .untouched
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+
+# CHECK: Name: .untouched_large
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# REINTERPRET-GPREL-NEXT: SHF_MIPS_GPREL (0x10000000)
+# REINTERPRET-LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
+# CHECK-NEXT: ]
diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
index afcac5527a57bc..c002c8807453d0 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
@@ -40,6 +40,12 @@
# RUN: llvm-objcopy --set-section-flags=.foo=share \
# RUN: --set-section-flags=.baz=share --set-section-flags=.rela.baz=share %t %t.share
# RUN: llvm-readobj --sections %t.share | FileCheck %s --check-prefixes=CHECK,PROGBITS,WRITE
+# RUN: llvm-objcopy --set-section-flags=.foo=large \
+# RUN: --set-section-flags=.baz=large --set-section-flags=.rela.baz=large %t %t.large
+# RUN: llvm-readobj --sections %t.large | FileCheck %s --check-prefixes=CHECK,LARGE,PROGBITS,WRITE
+# RUN: llvm-objcopy --set-section-flags=.foo=data \
+# RUN: --set-section-flags=.baz=data --set-section-flags=.rela.baz=data %t %t.no-large
+# RUN: llvm-readobj --sections %t.no-large | FileCheck %s --check-prefixes=CHECK,PROGBITS,WRITE
# Multiple flags:
# RUN: llvm-objcopy --set-section-flags=.foo=alloc,readonly,strings \
@@ -102,6 +108,7 @@ Sections:
# STRINGS-NEXT: SHF_STRINGS (0x20)
# EXCLUDE-NEXT: SHF_EXCLUDE (0x80000000)
# WRITE-NEXT: SHF_WRITE (0x1)
+# LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
# CHECK-NEXT: ]
# CHECK: Name: .baz
@@ -114,6 +121,7 @@ Sections:
# STRINGS-NEXT: SHF_STRINGS (0x20)
# EXCLUDE-NEXT: SHF_EXCLUDE (0x80000000)
# WRITE-NEXT: SHF_WRITE (0x1)
+# LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
# CHECK-NEXT: ]
# CHECK: Name: .rela.baz
@@ -125,6 +133,7 @@ Sections:
# STRINGS-NEXT: SHF_STRINGS (0x20)
# EXCLUDE-NEXT: SHF_EXCLUDE (0x80000000)
# WRITE-NEXT: SHF_WRITE (0x1)
+# LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
# CHECK-NEXT: ]
# BAD-FORMAT: bad format for --set-section-flags: missing '='
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 265e4fc6073c2b..2e0c3ca8671aa1 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -205,6 +205,7 @@ static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
.CaseLower("contents", SectionFlag::SecContents)
.CaseLower("share", SectionFlag::SecShare)
.CaseLower("exclude", SectionFlag::SecExclude)
+ .CaseLower("large", SectionFlag::SecLarge)
.Default(SectionFlag::SecNone);
}
@@ -218,7 +219,7 @@ parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
errc::invalid_argument,
"unrecognized section flag '%s'. Flags supported for GNU "
"compatibility: alloc, load, noload, readonly, exclude, debug, "
- "code, data, rom, share, contents, merge, strings",
+ "code, data, rom, share, contents, merge, strings, large",
Flag.str().c_str());
ParsedFlags |= ParsedFlag;
}
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index a7e4263271d356..ea8828637222ac 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -52,7 +52,7 @@ defm rename_section
"Renames a section from old to new, optionally with specified flags. "
"Flags supported for GNU compatibility: alloc, load, noload, "
"readonly, exclude, debug, code, data, rom, share, contents, merge, "
- "strings">,
+ "strings, large">,
MetaVarName<"old=new[,flag1,...]">;
defm redefine_symbol
: Eq<"redefine-sym", "Change the name of a symbol old to new">,
@@ -85,7 +85,7 @@ defm set_section_flags
: Eq<"set-section-flags",
"Set section flags for a given section. Flags supported for GNU "
"compatibility: alloc, load, noload, readonly, exclude, debug, code, "
- "data, rom, share, contents, merge, strings">,
+ "data, rom, share, contents, merge, strings, large">,
MetaVarName<"section=flag1[,flag2,...]">;
defm set_section_type
More information about the llvm-commits
mailing list