diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h --- a/llvm/include/llvm/ObjCopy/CommonConfig.h +++ b/llvm/include/llvm/ObjCopy/CommonConfig.h @@ -241,6 +241,7 @@ StringMap SectionsToRename; StringMap SetSectionAlignment; StringMap SetSectionFlags; + StringMap SetSectionType; StringMap SymbolsToRename; // Symbol info specified by --add-symbol option. diff --git a/llvm/lib/ObjCopy/ConfigManager.cpp b/llvm/lib/ObjCopy/ConfigManager.cpp --- a/llvm/lib/ObjCopy/ConfigManager.cpp +++ b/llvm/lib/ObjCopy/ConfigManager.cpp @@ -20,9 +20,9 @@ !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() || !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() || - Common.ExtractDWO || Common.PreserveDates || Common.StripDWO || - Common.StripNonAlloc || Common.StripSections || Common.Weaken || - Common.DecompressDebugSections || + !Common.SetSectionType.empty() || Common.ExtractDWO || + Common.PreserveDates || Common.StripDWO || Common.StripNonAlloc || + Common.StripSections || Common.Weaken || Common.DecompressDebugSections || Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty()) return createStringError(llvm::errc::invalid_argument, "option is not supported for COFF"); @@ -38,9 +38,10 @@ !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() || !Common.UnneededSymbolsToRemove.empty() || !Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() || - Common.ExtractDWO || Common.PreserveDates || Common.StripAllGNU || - Common.StripDWO || Common.StripNonAlloc || Common.StripSections || - Common.Weaken || Common.DecompressDebugSections || Common.StripUnneeded || + !Common.SetSectionType.empty() || Common.ExtractDWO || + Common.PreserveDates || Common.StripAllGNU || Common.StripDWO || + Common.StripNonAlloc || Common.StripSections || Common.Weaken || + Common.DecompressDebugSections || Common.StripUnneeded || Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty()) return createStringError(llvm::errc::invalid_argument, "option is not supported for MachO"); @@ -58,7 +59,8 @@ !Common.UnneededSymbolsToRemove.empty() || !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() || - !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty()) + !Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() || + !Common.SymbolsToRename.empty()) return createStringError(llvm::errc::invalid_argument, "only flags for section dumping, removal, and " "addition are supported"); @@ -79,12 +81,12 @@ !Common.UnneededSymbolsToRemove.empty() || !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() || - !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty() || - Common.ExtractDWO || Common.ExtractMainPartition || - Common.OnlyKeepDebug || Common.PreserveDates || Common.StripAllGNU || - Common.StripDWO || Common.StripDebug || Common.StripNonAlloc || - Common.StripSections || Common.Weaken || Common.StripUnneeded || - Common.DecompressDebugSections) { + !Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() || + !Common.SymbolsToRename.empty() || Common.ExtractDWO || + Common.ExtractMainPartition || Common.OnlyKeepDebug || + Common.PreserveDates || Common.StripAllGNU || Common.StripDWO || + Common.StripDebug || Common.StripNonAlloc || Common.StripSections || + Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections) { 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 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -675,14 +675,17 @@ for (const NewSymbolInfo &SI : Config.SymbolsToAdd) addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility); - // --set-section-flags works with sections added by --add-section. - if (!Config.SetSectionFlags.empty()) { + // --set-section-{flags,type} work with sections added by --add-section. + if (!Config.SetSectionFlags.empty() || !Config.SetSectionType.empty()) { for (auto &Sec : Obj.sections()) { const auto Iter = Config.SetSectionFlags.find(Sec.Name); if (Iter != Config.SetSectionFlags.end()) { const SectionFlagsUpdate &SFU = Iter->second; setSectionFlagsAndType(Sec, SFU.NewFlags); } + auto It2 = Config.SetSectionType.find(Sec.Name); + if (It2 != Config.SetSectionType.end()) + Sec.Type = It2->second; } } diff --git a/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-attr.test b/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-attr.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-attr.test @@ -0,0 +1,28 @@ +## Check --set-section-flags/--set-section-types work with sections added by --add-section. + +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-flags=foo=alloc,exclude %t %t.1 +# RUN: llvm-readobj -S %t.1 | FileCheck %s + +# CHECK: Name: foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXCLUDE +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] + +# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-type=foo=7 %t %t.2 +# RUN: llvm-readobj -S %t.2 | FileCheck %s --check-prefix=CHECK2 + +# CHECK2: Name: foo +# CHECK2-NEXT: Type: SHT_NOTE (0x7) +# CHECK2-NEXT: Flags [ +# CHECK2-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 diff --git a/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test b/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test deleted file mode 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test +++ /dev/null @@ -1,20 +0,0 @@ -## Check --set-section-flags works with sections added by --add-section. - -# RUN: yaml2obj %s -o %t -# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-flags=foo=alloc,exclude %t %t.out -# RUN: llvm-readobj -S %t.out | FileCheck %s - -# CHECK: Name: foo -# CHECK-NEXT: Type: SHT_PROGBITS -# CHECK-NEXT: Flags [ -# CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: SHF_EXCLUDE -# CHECK-NEXT: SHF_WRITE -# CHECK-NEXT: ] - ---- !ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_EXEC - Machine: EM_X86_64 diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test --- a/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test +++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test @@ -12,7 +12,20 @@ # CHECK: AddressAlignment: # CHECK-SAME: {{^}} 16 -# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.bar=alloc %t %t.2 2>&1 | FileCheck %s --check-prefix=SET-BAR +# RUN: llvm-objcopy --rename-section=.foo=.bar --set-section-type=.foo=5 %t %t.2 +# RUN: llvm-readobj -S %t.2 | FileCheck %s --check-prefix=CHECK2 + +# CHECK2: Name: .bar +# CHECK2-NEXT: Type: SHT_HASH +# CHECK2-NEXT: Flags [ +# CHECK2-NEXT: SHF_ALLOC +# CHECK2-NEXT: ] + +# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.bar=alloc %t %t.2 2>&1 | FileCheck %s --check-prefix=SET-BAR1 +# SET-BAR1: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar + +# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-type=.bar=1 %t %t.2 2>&1 | FileCheck %s --check-prefix=SET-BAR2 +# SET-BAR2: --set-section-type=.bar conflicts with --rename-section=.foo=.bar !ELF FileHeader: @@ -24,5 +37,3 @@ - Name: .foo Type: SHT_PROGBITS Flags: [ SHF_ALLOC ] - -# SET-BAR: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-type.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-type.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-type.test @@ -0,0 +1,51 @@ +# RUN: yaml2obj %s -o %t + +# RUN: llvm-objcopy --set-section-type=.foo=14 --set-section-type .bar=0xf %t %t.1 +# RUN: llvm-readobj --sections %t.1 | FileCheck %s + +# RUN: llvm-objcopy --set-section-type=.foo=13 --set-section-type=.foo=14 --set-section-type .bar=0xf %t %t.1 +# RUN: llvm-readobj --sections %t.1 | FileCheck %s + +# CHECK: Name: .foo +# CHECK-NEXT: Type: SHT_INIT_ARRAY (0xE) +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] + +# CHECK: Name: .bar +# CHECK-NEXT: Type: SHT_FINI_ARRAY (0xF) +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] + +## sh_type is an uint32_t. There is no diagnostic for an overflow value. +# RUN: llvm-objcopy --set-section-type=.foo=0x10000000a %t %t.2 2>&1 | count 0 +# RUN: llvm-readobj --sections %t.2 | FileCheck %s --check-prefix=CHECK2 + +# CHECK2: Name: .foo +# CHECK2-NEXT: Type: SHT_SHLIB +# CHECK2-NEXT: Flags [ +# CHECK2-NEXT: SHF_ALLOC +# CHECK2-NEXT: ] + +# RUN: not llvm-objcopy --set-section-type=.foo %t /dev/null 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT +# BAD-FORMAT: bad format for --set-section-type: missing '=' + +# RUN: not llvm-objcopy --set-section-type==4 %t /dev/null 2>&1 | FileCheck %s --check-prefix=MISSING-SECTION +# MISSING-SECTION: error: bad format for --set-section-type: missing section name + +# RUN: not llvm-objcopy --set-section-type=.foo=aaa %t /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID-TYPE +# INVALID-TYPE: error: invalid type for --set-section-type: 'aaa' + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + - Name: .bar + Type: SHT_PROGBITS + Flags: [ ] diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -277,6 +277,26 @@ return SFU; } +static Expected> +parseSetSectionType(StringRef TypeValue) { + if (!TypeValue.contains('=')) + return createStringError( + errc::invalid_argument, + "bad format for --set-section-type: missing '='"); + auto Split = StringRef(TypeValue).split('='); + if (Split.first.empty()) + return createStringError( + errc::invalid_argument, + "bad format for --set-section-type: missing section name"); + uint64_t NewAlign; + if (Split.second.getAsInteger(0, NewAlign)) + return createStringError( + errc::invalid_argument, + "invalid type for --set-section-type: '%s'", + Split.second.str().c_str()); + return std::make_pair(Split.first, NewAlign); +} + namespace { struct TargetInfo { FileFormat Format; @@ -809,8 +829,15 @@ "--set-section-flags set multiple times for section '%s'", SFU->Name.str().c_str()); } - // Prohibit combinations of --set-section-flags when the section name is used - // by the destination of a --rename-section. + for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_type)) { + Expected> NameAndAlign = + parseSetSectionType(Arg->getValue()); + if (!NameAndAlign) + return NameAndAlign.takeError(); + Config.SetSectionType[NameAndAlign->first] = NameAndAlign->second; + } + // Prohibit combinations of --set-section-{flags,type} when the section name + // is used by the destination of a --rename-section. for (const auto &E : Config.SectionsToRename) { const SectionRename &SR = E.second; if (Config.SetSectionFlags.count(SR.NewName)) @@ -819,6 +846,12 @@ "--set-section-flags=%s conflicts with --rename-section=%s=%s", SR.NewName.str().c_str(), SR.OriginalName.str().c_str(), SR.NewName.str().c_str()); + if (Config.SetSectionType.count(SR.NewName)) + return createStringError( + errc::invalid_argument, + "--set-section-type=%s conflicts with --rename-section=%s=%s", + SR.NewName.str().c_str(), SR.OriginalName.str().c_str(), + SR.NewName.str().c_str()); } for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td --- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td +++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td @@ -87,6 +87,11 @@ "data, rom, share, contents, merge, strings.">, MetaVarName<"section=flag1[,flag2,...]">; +defm set_section_type + : Eq<"set-section-type", + "Set the type for a given section to the integer ">, + MetaVarName<"section=type">; + def S : Flag<["-"], "S">, Alias, HelpText<"Alias for --strip-all">;