Skip to content

Commit 392aa97

Browse files
committed
[llvm-objcopy] Implement the PE-COFF specific --subsystem option
This implements the parsing of the highly PE-COFF specific option in ConfigManager.cpp, setting Optional<> values in COFFConfig, which then are used in COFFObjcopy. This should fix mstorsjo/llvm-mingw#239. Differential Revision: https://reviews.llvm.org/D116556
1 parent 581e855 commit 392aa97

File tree

7 files changed

+163
-5
lines changed

7 files changed

+163
-5
lines changed

llvm/docs/CommandGuide/llvm-objcopy.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,13 @@ MACH-O-SPECIFIC OPTIONS
477477

478478
Keep undefined symbols, even if they would otherwise be stripped.
479479

480+
COFF-SPECIFIC OPTIONS
481+
---------------------
482+
483+
.. option:: --subsystem <name>[:<version>]
484+
485+
Set the PE subsystem, and optionally subsystem version.
486+
480487
SUPPORTED FORMATS
481488
-----------------
482489

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
## Test that options for altering PE header fields error out on object files.
2+
3+
# RUN: yaml2obj %s -o %t.in.obj
4+
5+
# RUN: not llvm-objcopy --subsystem windows %t.in.obj %t.out.obj 2>&1 | FileCheck %s -DFILE=%t.out.obj
6+
7+
# CHECK: '[[FILE]]': unable to set subsystem on a relocatable object file
8+
9+
--- !COFF
10+
header:
11+
Machine: IMAGE_FILE_MACHINE_AMD64
12+
Characteristics: [ ]
13+
sections:
14+
- Name: .text
15+
Characteristics: [ ]
16+
VirtualAddress: 4096
17+
VirtualSize: 1
18+
SectionData: C3
19+
symbols:
20+
...
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
## Test the --subsystem option.
2+
3+
# RUN: yaml2obj %s -o %t.in.exe
4+
5+
# RUN: llvm-objcopy --subsystem=posix:7.4 --subsystem windows %t.in.exe %t.out.exe
6+
# RUN: llvm-readobj --file-headers %t.out.exe | FileCheck %s --check-prefix=WIN74
7+
8+
# WIN74: MajorOperatingSystemVersion: 6
9+
# WIN74: MinorOperatingSystemVersion: 0
10+
# WIN74: MajorSubsystemVersion: 7
11+
# WIN74: MinorSubsystemVersion: 4
12+
# WIN74: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
13+
14+
# RUN: llvm-objcopy --subsystem=posix:7.4 --subsystem windows:9 %t.in.exe %t.out.exe
15+
# RUN: llvm-readobj --file-headers %t.out.exe | FileCheck %s --check-prefix=WIN90
16+
17+
# WIN90: MajorOperatingSystemVersion: 6
18+
# WIN90: MinorOperatingSystemVersion: 0
19+
# WIN90: MajorSubsystemVersion: 9
20+
# WIN90: MinorSubsystemVersion: 0
21+
# WIN90: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
22+
23+
# RUN: not llvm-objcopy --subsystem=foobar %t.in.exe %t.err.exe 2>&1 | FileCheck %s --check-prefix=INVALID-SUBSYS
24+
25+
# INVALID-SUBSYS: 'foobar' is not a valid subsystem{{$}}
26+
27+
# RUN: not llvm-objcopy --subsystem=windows:foo %t.in.exe %t.err.exe 2>&1 | FileCheck %s --check-prefix=INVALID-MAJOR-NUMBER
28+
# RUN: not llvm-objcopy --subsystem=windows:8.bar %t.in.exe %t.err.exe 2>&1 | FileCheck %s --check-prefix=INVALID-MINOR-NUMBER
29+
30+
# INVALID-MAJOR-NUMBER: 'foo' is not a valid subsystem major version
31+
# INVALID-MINOR-NUMBER: 'bar' is not a valid subsystem minor version
32+
33+
--- !COFF
34+
OptionalHeader:
35+
AddressOfEntryPoint: 4096
36+
ImageBase: 1073741824
37+
SectionAlignment: 4096
38+
FileAlignment: 512
39+
MajorOperatingSystemVersion: 6
40+
MinorOperatingSystemVersion: 0
41+
MajorImageVersion: 0
42+
MinorImageVersion: 0
43+
MajorSubsystemVersion: 6
44+
MinorSubsystemVersion: 0
45+
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
46+
DLLCharacteristics: [ ]
47+
SizeOfStackReserve: 1048576
48+
SizeOfStackCommit: 4096
49+
SizeOfHeapReserve: 1048576
50+
SizeOfHeapCommit: 4096
51+
header:
52+
Machine: IMAGE_FILE_MACHINE_AMD64
53+
Characteristics: [ ]
54+
sections:
55+
- Name: .text
56+
Characteristics: [ ]
57+
VirtualAddress: 4096
58+
VirtualSize: 1
59+
SectionData: C3
60+
symbols:
61+
...

llvm/tools/llvm-objcopy/COFF/COFFConfig.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@
99
#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COFF_COFFCONFIG_H
1010
#define LLVM_TOOLS_LLVM_OBJCOPY_COFF_COFFCONFIG_H
1111

12+
#include "llvm/ADT/Optional.h"
13+
1214
namespace llvm {
1315
namespace objcopy {
1416

1517
// Coff specific configuration for copying/stripping a single file.
16-
struct COFFConfig {};
18+
struct COFFConfig {
19+
Optional<unsigned> Subsystem;
20+
Optional<unsigned> MajorSubsystemVersion;
21+
Optional<unsigned> MinorSubsystemVersion;
22+
};
1723

1824
} // namespace objcopy
1925
} // namespace llvm

llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ static uint32_t flagsToCharacteristics(SectionFlag AllFlags, uint32_t OldChar) {
130130
return NewCharacteristics;
131131
}
132132

133-
static Error handleArgs(const CommonConfig &Config, Object &Obj) {
133+
static Error handleArgs(const CommonConfig &Config,
134+
const COFFConfig &COFFConfig, Object &Obj) {
134135
// Perform the actual section removals.
135136
Obj.removeSections([&Config](const Section &Sec) {
136137
// Contrary to --only-keep-debug, --only-section fully removes sections that
@@ -256,18 +257,34 @@ static Error handleArgs(const CommonConfig &Config, Object &Obj) {
256257
if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink))
257258
return E;
258259

260+
if (COFFConfig.Subsystem || COFFConfig.MajorSubsystemVersion ||
261+
COFFConfig.MinorSubsystemVersion) {
262+
if (!Obj.IsPE)
263+
return createStringError(
264+
errc::invalid_argument,
265+
"'" + Config.OutputFilename +
266+
"': unable to set subsystem on a relocatable object file");
267+
if (COFFConfig.Subsystem)
268+
Obj.PeHeader.Subsystem = *COFFConfig.Subsystem;
269+
if (COFFConfig.MajorSubsystemVersion)
270+
Obj.PeHeader.MajorSubsystemVersion = *COFFConfig.MajorSubsystemVersion;
271+
if (COFFConfig.MinorSubsystemVersion)
272+
Obj.PeHeader.MinorSubsystemVersion = *COFFConfig.MinorSubsystemVersion;
273+
}
274+
259275
return Error::success();
260276
}
261277

262-
Error executeObjcopyOnBinary(const CommonConfig &Config, const COFFConfig &,
263-
COFFObjectFile &In, raw_ostream &Out) {
278+
Error executeObjcopyOnBinary(const CommonConfig &Config,
279+
const COFFConfig &COFFConfig, COFFObjectFile &In,
280+
raw_ostream &Out) {
264281
COFFReader Reader(In);
265282
Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
266283
if (!ObjOrErr)
267284
return createFileError(Config.InputFilename, ObjOrErr.takeError());
268285
Object *Obj = ObjOrErr->get();
269286
assert(Obj && "Unable to deserialize COFF object");
270-
if (Error E = handleArgs(Config, *Obj))
287+
if (Error E = handleArgs(Config, COFFConfig, *Obj))
271288
return createFileError(Config.InputFilename, std::move(E));
272289
COFFWriter Writer(*Obj, Out);
273290
if (Error E = Writer.write())

llvm/tools/llvm-objcopy/ConfigManager.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "llvm/ADT/SmallVector.h"
1212
#include "llvm/ADT/StringRef.h"
1313
#include "llvm/ADT/StringSet.h"
14+
#include "llvm/BinaryFormat/COFF.h"
1415
#include "llvm/Option/Arg.h"
1516
#include "llvm/Option/ArgList.h"
1617
#include "llvm/Support/CRC.h"
@@ -675,6 +676,7 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
675676

676677
ConfigManager ConfigMgr;
677678
CommonConfig &Config = ConfigMgr.Common;
679+
COFFConfig &COFFConfig = ConfigMgr.COFF;
678680
ELFConfig &ELFConfig = ConfigMgr.ELF;
679681
MachOConfig &MachOConfig = ConfigMgr.MachO;
680682
Config.InputFilename = Positional[0];
@@ -733,6 +735,46 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
733735
VisibilityStr.str().c_str());
734736
}
735737

738+
for (const auto *Arg : InputArgs.filtered(OBJCOPY_subsystem)) {
739+
StringRef Subsystem, Version;
740+
std::tie(Subsystem, Version) = StringRef(Arg->getValue()).split(':');
741+
COFFConfig.Subsystem =
742+
StringSwitch<unsigned>(Subsystem.lower())
743+
.Case("boot_application",
744+
COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
745+
.Case("console", COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
746+
.Case("efi_application", COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)
747+
.Case("efi_boot_service_driver",
748+
COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
749+
.Case("efi_rom", COFF::IMAGE_SUBSYSTEM_EFI_ROM)
750+
.Case("efi_runtime_driver",
751+
COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
752+
.Case("native", COFF::IMAGE_SUBSYSTEM_NATIVE)
753+
.Case("posix", COFF::IMAGE_SUBSYSTEM_POSIX_CUI)
754+
.Case("windows", COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
755+
.Default(COFF::IMAGE_SUBSYSTEM_UNKNOWN);
756+
if (*COFFConfig.Subsystem == COFF::IMAGE_SUBSYSTEM_UNKNOWN)
757+
return createStringError(errc::invalid_argument,
758+
"'%s' is not a valid subsystem",
759+
Subsystem.str().c_str());
760+
if (!Version.empty()) {
761+
StringRef Major, Minor;
762+
std::tie(Major, Minor) = Version.split('.');
763+
unsigned Number;
764+
if (Major.getAsInteger(10, Number))
765+
return createStringError(errc::invalid_argument,
766+
"'%s' is not a valid subsystem major version",
767+
Major.str().c_str());
768+
COFFConfig.MajorSubsystemVersion = Number;
769+
Number = 0;
770+
if (!Minor.empty() && Minor.getAsInteger(10, Number))
771+
return createStringError(errc::invalid_argument,
772+
"'%s' is not a valid subsystem minor version",
773+
Minor.str().c_str());
774+
COFFConfig.MinorSubsystemVersion = Number;
775+
}
776+
}
777+
736778
Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
737779
.Case("binary", FileFormat::Binary)
738780
.Case("ihex", FileFormat::IHex)

llvm/tools/llvm-objcopy/ObjcopyOpts.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ defm strip_unneeded_symbols
105105
"if they are not needed by relocations">,
106106
MetaVarName<"filename">;
107107

108+
defm subsystem
109+
: Eq<"subsystem",
110+
"Set PE subsystem and version">,
111+
MetaVarName<"name[:version]">;
112+
108113
def extract_dwo
109114
: Flag<["--"], "extract-dwo">,
110115
HelpText<

0 commit comments

Comments
 (0)