[llvm-objcopy][COFF] Add support for --set-section-flags

Reviewers: jhenderson, MaskRay, alexshap, rupprecht, mstorsjo

Reviewed By: jhenderson

Subscribers: abrachet, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73107
This commit is contained in:
Sergey Dmitriev 2020-01-24 06:36:09 -08:00
parent 76fa5d50f3
commit f69eba0772
3 changed files with 169 additions and 26 deletions

View File

@ -130,6 +130,45 @@ multiple file formats.
Set the alignment of section ``<section>`` to `<align>``. Can be specified
multiple times to update multiple sections.
.. option:: --set-section-flags <section>=<flag>[,<flag>,...]
Set section properties in the output of section ``<section>`` based on the
specified ``<flag>`` values. Can be specified multiple times to update multiple
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.
For ELF objects, the flags have the following effects:
- `alloc` = add the `SHF_ALLOC` flag.
- `load` = if the section has `SHT_NOBITS` type, mark it as a `SHT_PROGBITS`
section.
- `readonly` = if this flag is not specified, add the `SHF_WRITE` flag.
- `exclude` = add the `SHF_EXCLUDE` flag.
- `code` = add the `SHF_EXECINSTR` flag.
- `merge` = add the `SHF_MERGE` flag.
- `strings` = add the `SHF_STRINGS` flag.
- `contents` = if the section has `SHT_NOBITS` type, mark it as a `SHT_PROGBITS`
section.
For COFF objects, the flags have the following effects:
- `alloc` = add the `IMAGE_SCN_CNT_UNINITIALIZED_DATA` and `IMAGE_SCN_MEM_READ`
flags, unless the `load` flag is specified.
- `noload` = add the `IMAGE_SCN_LNK_REMOVE` and `IMAGE_SCN_MEM_READ` flags.
- `readonly` = if this flag is not specified, add the `IMAGE_SCN_MEM_WRITE`
flag.
- `exclude` = add the `IMAGE_SCN_LNK_REMOVE` and `IMAGE_SCN_MEM_READ` flags.
- `debug` = add the `IMAGE_SCN_CNT_INITIALIZED_DATA`,
`IMAGE_SCN_MEM_DISCARDABLE` and `IMAGE_SCN_MEM_READ` flags.
- `code` = add the `IMAGE_SCN_CNT_CODE`, `IMAGE_SCN_MEM_EXECUTE` and
`IMAGE_SCN_MEM_READ` flags.
- `data` = add the `IMAGE_SCN_CNT_INITIALIZED_DATA` and `IMAGE_SCN_MEM_READ`
flags.
- `share` = add the `IMAGE_SCN_MEM_SHARED` and `IMAGE_SCN_MEM_READ` flags.
.. option:: --strip-all-gnu
Remove all symbols, debug sections and relocations from the output. This option
@ -399,28 +438,6 @@ them.
specified ``<flag>`` values. See :option:`--set-section-flags` for a list of
supported flags. Can be specified multiple times to rename multiple sections.
.. option:: --set-section-flags <section>=<flag>[,<flag>,...]
Set section properties in the output of section ``<section>`` based on the
specified ``<flag>`` values. Can be specified multiple times to update multiple
sections.
Following is a list of supported flags and their effects:
- `alloc` = add the `SHF_ALLOC` flag.
- `load` = if the section has `SHT_NOBITS` type, mark it as a `SHT_PROGBITS`
section.
- `readonly` = if this flag is not specified, add the `SHF_WRITE` flag.
- `exclude` = add the `SHF_EXCLUDE` flag.
- `code` = add the `SHF_EXECINSTR` flag.
- `merge` = add the `SHF_MERGE` flag.
- `strings` = add the `SHF_STRINGS` flag.
- `contents` = if the section has `SHT_NOBITS` type, mark it as a `SHT_PROGBITS`
section.
The following flags are also accepted, but are ignored for GNU compatibility:
`noload`, `debug`, `data`, `rom`, `share`.
.. option:: --set-start-addr <addr>
Set the start address of the output to ``<addr>``. Overrides any previously

View File

@ -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

View File

@ -89,6 +89,43 @@ static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
IMAGE_SCN_MEM_DISCARDABLE);
}
static void setSectionFlags(Section &Sec, SectionFlag AllFlags) {
// Need to preserve alignment flags.
const uint32_t PreserveMask =
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 +215,13 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
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 +249,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
!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,