Index: test/tools/llvm-objcopy/rename-section-flag.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/rename-section-flag.test @@ -0,0 +1,60 @@ +# RUN: yaml2obj %s > %t + +# Single flags: +# RUN: llvm-objcopy --rename-section=.foo=.bar,alloc %t %t.alloc +# RUN: llvm-readobj -sections %t.alloc | FileCheck %s --check-prefixes=CHECK,ALLOC,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,load %t %t.load +# RUN: llvm-readobj -sections %t.load | FileCheck %s --check-prefixes=CHECK,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,noload %t %t.noload +# RUN: llvm-readobj -sections %t.noload | FileCheck %s --check-prefixes=CHECK,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,readonly %t %t.readonly +# RUN: llvm-readobj -sections %t.readonly | FileCheck %s --check-prefixes=CHECK +# RUN: llvm-objcopy --rename-section=.foo=.bar,debug %t %t.debug +# RUN: llvm-readobj -sections %t.debug | FileCheck %s --check-prefixes=CHECK,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,code %t %t.code +# RUN: llvm-readobj -sections %t.code | FileCheck %s --check-prefixes=CHECK,CODE,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,data %t %t.data +# RUN: llvm-readobj -sections %t.data | FileCheck %s --check-prefixes=CHECK,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,rom %t %t.rom +# RUN: llvm-readobj -sections %t.rom | FileCheck %s --check-prefixes=CHECK,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,contents %t %t.contents +# RUN: llvm-readobj -sections %t.contents | FileCheck %s --check-prefixes=CHECK,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,merge %t %t.merge +# RUN: llvm-readobj -sections %t.merge | FileCheck %s --check-prefixes=CHECK,MERGE,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,strings %t %t.strings +# RUN: llvm-readobj -sections %t.strings | FileCheck %s --check-prefixes=CHECK,STRINGS,WRITE +# RUN: llvm-objcopy --rename-section=.foo=.bar,share %t %t.share +# RUN: llvm-readobj -sections %t.share | FileCheck %s --check-prefixes=CHECK,WRITE + +# Multiple flags: +# RUN: llvm-objcopy --rename-section=.foo=.bar,alloc,readonly,strings %t %t.alloc_ro_strings +# RUN: llvm-readobj -sections %t.alloc_ro_strings | FileCheck %s --check-prefixes=CHECK,ALLOC,STRINGS +# RUN: llvm-objcopy --rename-section=.foo=.bar,alloc,code %t %t.alloc_code +# RUN: llvm-readobj -sections %t.alloc_code | FileCheck %s --check-prefixes=CHECK,ALLOC,CODE,WRITE + +# Invalid flags: +# RUN: not llvm-objcopy --rename-section=.foo=.bar,xyzzy %t %t.xyzzy 2>&1 | FileCheck %s --check-prefix=BAD-FLAG + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "c3c3c3c3" + +# CHECK: Name: .bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# ALLOC-NEXT: SHF_ALLOC (0x2) +# CODE-NEXT: SHF_EXECINSTR (0x4) +# MERGE-NEXT: SHF_MERGE (0x10) +# STRINGS-NEXT: SHF_STRINGS (0x20) +# WRITE-NEXT: SHF_WRITE (0x1) +# CHECK-NEXT: ] + +# BAD-FLAG: Unknown flag type: xyzzy. Index: tools/llvm-objcopy/ObjcopyOpts.td =================================================================== --- tools/llvm-objcopy/ObjcopyOpts.td +++ tools/llvm-objcopy/ObjcopyOpts.td @@ -28,8 +28,8 @@ MetaVarName<"section">, HelpText<"Remove
">; defm rename_section : Eq<"rename-section">, - MetaVarName<"old=new">, - HelpText<"Renames a section from old to new">; + MetaVarName<"old=new[,flag1,...]">, + HelpText<"Renames a section from old to new, optionally with specified flags">; defm redefine_symbol : Eq<"redefine-sym">, MetaVarName<"old=new">, HelpText<"Change the name of a symbol old to new">; Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -9,7 +9,10 @@ #include "llvm-objcopy.h" #include "Object.h" +#include "llvm/ADT/BitmaskEnum.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/ELF.h" @@ -115,6 +118,12 @@ StripOptTable() : OptTable(StripInfoTable, true) {} }; +struct SectionRename { + StringRef OriginalName; + StringRef NewName; + Optional NewFlags; +}; + struct CopyConfig { StringRef OutputFilename; StringRef InputFilename; @@ -133,7 +142,7 @@ std::vector SymbolsToWeaken; std::vector SymbolsToRemove; std::vector SymbolsToKeep; - StringMap SectionsToRename; + StringMap SectionsToRename; StringMap SymbolsToRename; bool StripAll = false; bool StripAllGNU = false; @@ -152,6 +161,23 @@ using SectionPred = std::function; +enum SectionFlag { + SecNone = 0, + SecAlloc = 1 << 0, + SecLoad = 1 << 1, + SecNoload = 1 << 2, + SecReadonly = 1 << 3, + SecDebug = 1 << 4, + SecCode = 1 << 5, + SecData = 1 << 6, + SecRom = 1 << 7, + SecMerge = 1 << 8, + SecStrings = 1 << 9, + SecContents = 1 << 10, + SecShare = 1 << 11, + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare) +}; + } // namespace namespace llvm { @@ -185,6 +211,62 @@ } // end namespace objcopy } // end namespace llvm +static SectionFlag ParseSectionRenameFlag(StringRef SectionName) { + return llvm::StringSwitch(SectionName) + .Case("alloc", SectionFlag::SecAlloc) + .Case("load", SectionFlag::SecLoad) + .Case("noload", SectionFlag::SecNoload) + .Case("readonly", SectionFlag::SecReadonly) + .Case("debug", SectionFlag::SecDebug) + .Case("code", SectionFlag::SecCode) + .Case("data", SectionFlag::SecData) + .Case("rom", SectionFlag::SecRom) + .Case("merge", SectionFlag::SecMerge) + .Case("strings", SectionFlag::SecStrings) + .Case("contents", SectionFlag::SecContents) + .Case("share", SectionFlag::SecShare) + .Default(SectionFlag::SecNone); +} + +static SectionRename ParseRenameSectionValue(StringRef FlagValue) { + if (!FlagValue.contains('=')) + error("Bad format for --rename-section: expected '='"); + + // Initial split: ".foo" = ".bar,f1,f2,..." + auto Old2New = FlagValue.split('='); + SectionRename SR; + SR.OriginalName = Old2New.first; + + // Flags split: ".bar" "f1" "f2" ... + SmallVector NameAndFlags; + Old2New.second.split(NameAndFlags, ','); + SR.NewName = NameAndFlags[0]; + + if (NameAndFlags.size() > 1) { + SectionFlag Flags = SectionFlag::SecNone; + for (size_t i = 1; i < NameAndFlags.size(); ++i) { + SectionFlag Flag = ParseSectionRenameFlag(NameAndFlags[i]); + if (Flag == SectionFlag::SecNone) + error("Unknown flag type: " + NameAndFlags[i]); + Flags |= Flag; + } + + SR.NewFlags = 0; + if (Flags & SectionFlag::SecAlloc) + *SR.NewFlags |= ELF::SHF_ALLOC; + if (!(Flags & SectionFlag::SecReadonly)) + *SR.NewFlags |= ELF::SHF_WRITE; + if (Flags & SectionFlag::SecCode) + *SR.NewFlags |= ELF::SHF_EXECINSTR; + if (Flags & SectionFlag::SecMerge) + *SR.NewFlags |= ELF::SHF_MERGE; + if (Flags & SectionFlag::SecStrings) + *SR.NewFlags |= ELF::SHF_STRINGS; + } + + return SR; +} + static bool IsDWOSection(const SectionBase &Sec) { return Sec.Name.endswith(".dwo"); } @@ -434,8 +516,12 @@ if (!Config.SectionsToRename.empty()) { for (auto &Sec : Obj.sections()) { const auto Iter = Config.SectionsToRename.find(Sec.Name); - if (Iter != Config.SectionsToRename.end()) - Sec.Name = Iter->second; + if (Iter != Config.SectionsToRename.end()) { + const SectionRename &SR = Iter->second; + Sec.Name = SR.NewName; + if (SR.NewFlags.hasValue()) + Sec.Flags = SR.NewFlags.getValue(); + } } } @@ -597,11 +683,9 @@ } for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) { - if (!StringRef(Arg->getValue()).contains('=')) - error("Bad format for --rename-section"); - auto Old2New = StringRef(Arg->getValue()).split('='); - if (!Config.SectionsToRename.insert(Old2New).second) - error("Already have a section rename for " + Old2New.first); + SectionRename SR = ParseRenameSectionValue(StringRef(Arg->getValue())); + if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second) + error("Already have a section rename for " + SR.OriginalName); } for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))