[mach-o] Add support for -pie and -no_pie

There is a bit (MH_PIE) in the flags field of the mach_header which tells
the kernel is a program was built position independent (for ASLR).  The linker
automatically attempts to build programs PIE if they are built for a recent
OS version.  But the -pie and -no_pie options override that default behavior.

llvm-svn: 217408
This commit is contained in:
Nick Kledzik 2014-09-09 00:17:52 +00:00
parent 513e8a911f
commit b7035ae367
6 changed files with 121 additions and 2 deletions

View File

@ -104,6 +104,8 @@ public:
const StringRefVector &frameworkDirs() const { return _frameworkDirs; }
void setSysLibRoots(const StringRefVector &paths);
const StringRefVector &sysLibRoots() const { return _syslibRoots; }
bool PIE() const { return _pie; }
void setPIE(bool pie) { _pie = pie; }
/// \brief Checks whether a given path on the filesystem exists.
///
@ -266,6 +268,7 @@ private:
HeaderFileType _outputMachOType; // e.g MH_EXECUTE
bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog
bool _doNothing; // for -help and -v which just print info
bool _pie;
Arch _arch;
OS _os;
uint32_t _osMinVersion;

View File

@ -544,6 +544,52 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
}
// Handle -pie or -no_pie
if (llvm::opt::Arg *pie = parsedArgs->getLastArg(OPT_pie, OPT_no_pie)) {
switch (ctx.outputMachOType()) {
case llvm::MachO::MH_EXECUTE:
switch (ctx.os()) {
case MachOLinkingContext::OS::macOSX:
if ((minOSVersion < 0x000A0500) &&
(pie->getOption().getID() == OPT_pie)) {
diagnostics << "-pie can only be used when targeting "
"Mac OS X 10.5 or later\n";
return false;
}
break;
case MachOLinkingContext::OS::iOS:
if ((minOSVersion < 0x00040200) &&
(pie->getOption().getID() == OPT_pie)) {
diagnostics << "-pie can only be used when targeting "
"iOS 4.2 or later\n";
return false;
}
break;
case MachOLinkingContext::OS::iOS_simulator:
if (pie->getOption().getID() == OPT_no_pie)
diagnostics << "iOS simulator programs must be built PIE\n";
return false;
break;
case MachOLinkingContext::OS::unknown:
break;
}
ctx.setPIE(pie->getOption().getID() == OPT_pie);
break;
case llvm::MachO::MH_PRELOAD:
break;
case llvm::MachO::MH_DYLIB:
case llvm::MachO::MH_BUNDLE:
diagnostics << "warning: " << pie->getSpelling() << " being ignored. "
<< "It is only used when linking main executables\n";
break;
default:
diagnostics << pie->getSpelling()
<< " can only used when linking main executables\n";
return false;
break;
}
}
// Handle input files
for (auto &arg : *parsedArgs) {
ErrorOr<StringRef> resolvedPath = StringRef();

View File

@ -55,6 +55,12 @@ def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
def entry : Separate<["-"], "e">,
MetaVarName<"<entry-name>">,
HelpText<"entry symbol name">,Group<grp_main>;
def pie : Flag<["-"], "pie">,
HelpText<"Create Position Independent Executable (for ASLR)">,
Group<grp_main>;
def no_pie : Flag<["-"], "no_pie">,
HelpText<"Do not create Position Independent Executable">,
Group<grp_main>;
// dylib executable options
def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;

View File

@ -132,7 +132,8 @@ bool MachOLinkingContext::isThinObjectFile(StringRef path, Arch &arch) {
MachOLinkingContext::MachOLinkingContext()
: _outputMachOType(MH_EXECUTE), _outputMachOTypeStatic(false),
_doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
_doNothing(false), _pie(false),
_arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
_pageZeroSize(0), _pageSize(4096), _compatibilityVersion(0),
_currentVersion(0), _deadStrippableDylib(false), _printAtoms(false),
_testingFileUsage(false), _keepPrivateExterns(false),
@ -165,6 +166,22 @@ void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
_pageZeroSize = 0x1000;
}
// Make PIE by default when targetting newer OSs.
switch (os) {
case OS::macOSX:
if (minOSVersion >= 0x000A0700) // MacOSX 10.7
_pie = true;
break;
case OS::iOS:
if (minOSVersion >= 0x00040300) // iOS 4.3
_pie = true;
break;
case OS::iOS_simulator:
_pie = true;
break;
case OS::unknown:
break;
}
break;
case llvm::MachO::MH_DYLIB:
_globalsAreDeadStripRoots = true;

View File

@ -1120,7 +1120,10 @@ uint32_t Util::fileFlags() {
if (_context.outputMachOType() == MH_OBJECT) {
return MH_SUBSECTIONS_VIA_SYMBOLS;
} else {
return MH_DYLDLINK | MH_NOUNDEFS | MH_TWOLEVEL;
if ((_context.outputMachOType() == MH_EXECUTE) && _context.PIE())
return MH_DYLDLINK | MH_NOUNDEFS | MH_TWOLEVEL | MH_PIE;
else
return MH_DYLDLINK | MH_NOUNDEFS | MH_TWOLEVEL;
}
}

44
lld/test/mach-o/PIE.yaml Normal file
View File

@ -0,0 +1,44 @@
# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \
# RUN: llvm-objdump -macho -private-headers %t | FileCheck %s
#
# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -pie -o %t\
# RUN: && llvm-objdump -macho -private-headers %t | FileCheck %s
#
# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -no_pie -o %t\
# RUN: && llvm-objdump -macho -private-headers %t \
# RUN: | FileCheck --check-prefix=CHECK_NO_PIE %s
#
# Test various PIE options.
#
--- !mach-o
arch: x86_64
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
has-UUID: false
OS: unknown
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
address: 0x0000000000000000
content: [ 0xC3 ]
global-symbols:
- name: _main
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
--- !mach-o
arch: x86_64
file-type: MH_DYLIB
install-name: /usr/lib/libSystem.B.dylib
exports:
- name: dyld_stub_binder
...
# CHECK: MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE
# CHECK_NO_PIE-NOT: MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE