Index: llvm/test/tools/llvm-objcopy/COFF/set-section-flags.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-objcopy/COFF/set-section-flags.test @@ -0,0 +1,82 @@ +# RUN: yaml2obj %s -o %t + +# Single flag on a section with no flags: +# RUN: llvm-objcopy --set-section-flags=.foo=alloc %t %t.alloc +# RUN: llvm-readobj --sections %t.alloc | FileCheck %s --check-prefixes=CHECK,UNINITDATA,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=load %t %t.load +# RUN: llvm-readobj --sections %t.load | FileCheck %s --check-prefixes=CHECK,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=noload %t %t.noload +# RUN: llvm-readobj --sections %t.noload | FileCheck %s --check-prefixes=CHECK,READ,WRITE,REMOVE +# RUN: llvm-objcopy --set-section-flags=.foo=readonly %t %t.readonly +# RUN: llvm-readobj --sections %t.readonly | FileCheck %s --check-prefixes=CHECK,READ +# RUN: llvm-objcopy --set-section-flags=.foo=exclude %t %t.exclude +# RUN: llvm-readobj --sections %t.exclude | FileCheck %s --check-prefixes=CHECK,READ,WRITE,REMOVE +# RUN: llvm-objcopy --set-section-flags=.foo=debug %t %t.debug +# RUN: llvm-readobj --sections %t.debug | FileCheck %s --check-prefixes=CHECK,INITDATA,DISCARDABLE,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=code %t %t.code +# RUN: llvm-readobj --sections %t.code | FileCheck %s --check-prefixes=CHECK,CODE,EXECUTE,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=data %t %t.data +# RUN: llvm-readobj --sections %t.data | FileCheck %s --check-prefixes=CHECK,INITDATA,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=rom %t %t.rom +# RUN: llvm-readobj --sections %t.rom | FileCheck %s --check-prefixes=CHECK,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=contents %t %t.contents +# RUN: llvm-readobj --sections %t.contents | FileCheck %s --check-prefixes=CHECK,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=merge %t %t.merge +# RUN: llvm-readobj --sections %t.merge | FileCheck %s --check-prefixes=CHECK,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=strings %t %t.strings +# RUN: llvm-readobj --sections %t.strings | FileCheck %s --check-prefixes=CHECK,READ,WRITE +# RUN: llvm-objcopy --set-section-flags=.foo=share %t %t.share +# RUN: llvm-readobj --sections %t.share | FileCheck %s --check-prefixes=CHECK,READ,SHARED,WRITE + +# Multiple flags: +# RUN: llvm-objcopy --set-section-flags=.foo=alloc,readonly,share %t %t.alloc_ro_share +# RUN: llvm-readobj --sections %t.alloc_ro_share | FileCheck %s --check-prefixes=CHECK,UNINITDATA,READ,SHARED +# RUN: llvm-objcopy --set-section-flags=.foo=alloc,code %t %t.alloc_code +# RUN: llvm-readobj --sections %t.alloc_code | FileCheck %s --check-prefixes=CHECK,CODE,UNINITDATA,EXECUTE,READ,WRITE + +# Invalid flags: +# RUN: not llvm-objcopy --set-section-flags=.foo=xyzzy %t %t.xyzzy 2>&1 | FileCheck %s --check-prefix=BAD-FLAG + +# Bad flag format: +# RUN: not llvm-objcopy --set-section-flags=.foo %t %t2 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT + +# Setting flags for the same section multiple times: +# RUN: not llvm-objcopy --set-section-flags=.foo=alloc --set-section-flags=.foo=load %t %t2 2>&1 | FileCheck %s --check-prefix=MULTIPLE-SETS + +# Upper-case flags: +# RUN: llvm-objcopy --set-section-flags=.foo=ALLOC,LOAD,NOLOAD,READONLY,DEBUG,CODE,DATA,ROM,CONTENTS,MERGE,STRINGS,SHARE %t %t.upper +# RUN: llvm-readobj --sections %t.upper | FileCheck %s --check-prefixes=CHECK,CODE,INITDATA,REMOVE,DISCARDABLE,EXECUTE,READ,SHARED + +# Mixed-case flags: +# RUN: llvm-objcopy --set-section-flags=.foo=aLlOc,LoAd,NoLoad,rEAdONly,Debug,codE,DaTa,rOm,CoNtEnTs,mErGe,sTRINGs,SharE %t %t.mixed +# RUN: llvm-readobj --sections %t.mixed | FileCheck %s --check-prefixes=CHECK,CODE,INITDATA,REMOVE,DISCARDABLE,EXECUTE,READ,SHARED + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .foo + Characteristics: [ ] + Alignment: 4 +symbols: +... + +# CHECK: Name: .foo +# CHECK: Characteristics [ +# CHECK-NEXT: IMAGE_SCN_ALIGN_4BYTES +# CODE-NEXT: IMAGE_SCN_CNT_CODE +# INITDATA-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# UNINITDATA-NEXT: IMAGE_SCN_CNT_UNINITIALIZED_DATA +# REMOVE-NEXT: IMAGE_SCN_LNK_REMOVE +# DISCARDABLE-NEXT: IMAGE_SCN_MEM_DISCARDABLE +# EXECUTE-NEXT: IMAGE_SCN_MEM_EXECUTE +# READ-NEXT: IMAGE_SCN_MEM_READ +# SHARED-NEXT: IMAGE_SCN_MEM_SHARED +# WRITE-NEXT: IMAGE_SCN_MEM_WRITE +# CHECK-NEXT: ] + +# BAD-FORMAT: bad format for --set-section-flags: missing '=' +# MULTIPLE-SETS: --set-section-flags set multiple times for section '.foo' + +# BAD-FLAG: unrecognized section flag 'xyzzy'. Flags supported for GNU compatibility: alloc, load, noload, readonly, exclude, debug, code, data, rom, share, contents, merge, strings Index: llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -89,6 +89,44 @@ IMAGE_SCN_MEM_DISCARDABLE); } +static void setSectionFlags(Section &Sec, SectionFlag AllFlags) { + // Need to preserve existing flags like linker info or alignment settings. + const uint32_t PreserveMask = + IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_LNK_NRELOC_OVFL | + IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_ALIGN_4BYTES | + IMAGE_SCN_ALIGN_8BYTES | IMAGE_SCN_ALIGN_16BYTES | + IMAGE_SCN_ALIGN_32BYTES | IMAGE_SCN_ALIGN_64BYTES | + IMAGE_SCN_ALIGN_128BYTES | IMAGE_SCN_ALIGN_256BYTES | + IMAGE_SCN_ALIGN_512BYTES | IMAGE_SCN_ALIGN_1024BYTES | + IMAGE_SCN_ALIGN_2048BYTES | IMAGE_SCN_ALIGN_4096BYTES | + IMAGE_SCN_ALIGN_8192BYTES; + + // Setup new section characteristics based on the flags provided in command + // line. + uint32_t NewCharacteristics = + (Sec.Header.Characteristics & PreserveMask) | IMAGE_SCN_MEM_READ; + + if ((AllFlags & SectionFlag::SecAlloc) && !(AllFlags & SectionFlag::SecLoad)) + NewCharacteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; + if (AllFlags & SectionFlag::SecNoload) + NewCharacteristics |= IMAGE_SCN_LNK_REMOVE; + if (!(AllFlags & SectionFlag::SecReadonly)) + NewCharacteristics |= IMAGE_SCN_MEM_WRITE; + if (AllFlags & SectionFlag::SecDebug) + NewCharacteristics |= + IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE; + if (AllFlags & SectionFlag::SecCode) + NewCharacteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; + if (AllFlags & SectionFlag::SecData) + NewCharacteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; + if (AllFlags & SectionFlag::SecShare) + NewCharacteristics |= IMAGE_SCN_MEM_SHARED; + if (AllFlags & SectionFlag::SecExclude) + NewCharacteristics |= IMAGE_SCN_LNK_REMOVE; + + Sec.Header.Characteristics = NewCharacteristics; +} + static Error handleArgs(const CopyConfig &Config, Object &Obj) { // Perform the actual section removals. Obj.removeSections([&Config](const Section &Sec) { @@ -178,6 +216,13 @@ return false; }); + if (!Config.SetSectionFlags.empty()) + for (Section &Sec : Obj.getMutableSections()) { + const auto It = Config.SetSectionFlags.find(Sec.Name); + if (It != Config.SetSectionFlags.end()) + setSectionFlags(Sec, It->second.NewFlags); + } + for (const auto &Flag : Config.AddSection) { StringRef SecName, FileName; std::tie(SecName, FileName) = Flag.split("="); @@ -205,10 +250,10 @@ !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || - !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() || - Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden || - Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc || - Config.StripSections || Config.Weaken || Config.DecompressDebugSections || + !Config.SetSectionAlignment.empty() || Config.ExtractDWO || + Config.KeepFileSymbols || Config.LocalizeHidden || Config.PreserveDates || + Config.StripDWO || Config.StripNonAlloc || Config.StripSections || + Config.Weaken || Config.DecompressDebugSections || Config.DiscardMode == DiscardType::Locals || !Config.SymbolsToAdd.empty() || Config.EntryExpr) { return createStringError(llvm::errc::invalid_argument,