forked from OSchip/llvm-project
Set max segment protection level.
The initial segment protection was also being used to set the maximum segment protection level. Instead, the maximum should be set according to the architecture we are linking. For example on Mac OS it should be RWX on most pages, but on iOS is often on R_X. rdar://problem/24515136 llvm-svn: 259966
This commit is contained in:
parent
dc1414b3f9
commit
b8fec3ea62
|
@ -172,7 +172,8 @@ struct Segment {
|
|||
StringRef name;
|
||||
Hex64 address;
|
||||
Hex64 size;
|
||||
VMProtect access;
|
||||
VMProtect init_access;
|
||||
VMProtect max_access;
|
||||
};
|
||||
|
||||
/// Only used in normalized final linked images to specify on which dylibs
|
||||
|
|
|
@ -570,7 +570,7 @@ void MachOFileLayout::buildFileOffsets() {
|
|||
llvm::dbgs() << "buildFileOffsets()\n");
|
||||
for (const Segment &sg : _file.segments) {
|
||||
_segInfo[&sg].fileOffset = fileOffset;
|
||||
if ((_seg1addr == INT64_MAX) && sg.access)
|
||||
if ((_seg1addr == INT64_MAX) && sg.init_access)
|
||||
_seg1addr = sg.address;
|
||||
DEBUG_WITH_TYPE("MachOFileLayout",
|
||||
llvm::dbgs() << " segment=" << sg.name
|
||||
|
@ -578,7 +578,7 @@ void MachOFileLayout::buildFileOffsets() {
|
|||
|
||||
uint32_t segFileSize = 0;
|
||||
// A segment that is not zero-fill must use a least one page of disk space.
|
||||
if (sg.access)
|
||||
if (sg.init_access)
|
||||
segFileSize = _file.pageSize;
|
||||
for (const Section *s : _segInfo[&sg].sections) {
|
||||
uint32_t sectOffset = s->address - sg.address;
|
||||
|
@ -711,8 +711,8 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
|
|||
cmd->vmsize = llvm::alignTo(linkeditSize, _file.pageSize);
|
||||
cmd->fileoff = _startOfLinkEdit;
|
||||
cmd->filesize = linkeditSize;
|
||||
cmd->initprot = seg.access;
|
||||
cmd->maxprot = seg.access;
|
||||
cmd->initprot = seg.init_access;
|
||||
cmd->maxprot = seg.max_access;
|
||||
cmd->nsects = 0;
|
||||
cmd->flags = 0;
|
||||
if (_swap)
|
||||
|
@ -731,8 +731,8 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
|
|||
cmd->vmsize = seg.size;
|
||||
cmd->fileoff = segInfo.fileOffset;
|
||||
cmd->filesize = segInfo.fileSize;
|
||||
cmd->maxprot = seg.access;
|
||||
cmd->initprot = seg.access;
|
||||
cmd->initprot = seg.init_access;
|
||||
cmd->maxprot = seg.max_access;
|
||||
cmd->nsects = segInfo.sections.size();
|
||||
cmd->flags = 0;
|
||||
if (_swap)
|
||||
|
|
|
@ -92,13 +92,15 @@ struct SegmentInfo {
|
|||
StringRef name;
|
||||
uint64_t address;
|
||||
uint64_t size;
|
||||
uint32_t access;
|
||||
uint32_t init_access;
|
||||
uint32_t max_access;
|
||||
std::vector<SectionInfo*> sections;
|
||||
uint32_t normalizedSegmentIndex;
|
||||
};
|
||||
|
||||
SegmentInfo::SegmentInfo(StringRef n)
|
||||
: name(n), address(0), size(0), access(0), normalizedSegmentIndex(0) {
|
||||
: name(n), address(0), size(0), init_access(0), max_access(0),
|
||||
normalizedSegmentIndex(0) {
|
||||
}
|
||||
|
||||
class Util {
|
||||
|
@ -432,12 +434,38 @@ SegmentInfo *Util::segmentForName(StringRef segName) {
|
|||
return si;
|
||||
}
|
||||
auto *info = new (_allocator) SegmentInfo(segName);
|
||||
|
||||
// Set the initial segment protection.
|
||||
if (segName.equals("__TEXT"))
|
||||
info->access = VM_PROT_READ | VM_PROT_EXECUTE;
|
||||
else if (segName.equals("__DATA"))
|
||||
info->access = VM_PROT_READ | VM_PROT_WRITE;
|
||||
info->init_access = VM_PROT_READ | VM_PROT_EXECUTE;
|
||||
else if (segName.equals("__PAGEZERO"))
|
||||
info->access = 0;
|
||||
info->init_access = 0;
|
||||
else if (segName.equals("__LINKEDIT"))
|
||||
info->init_access = VM_PROT_READ;
|
||||
else {
|
||||
// All others default to read-write
|
||||
info->init_access = VM_PROT_READ | VM_PROT_WRITE;
|
||||
}
|
||||
|
||||
// Set max segment protection
|
||||
// Note, its overkill to use a switch statement here, but makes it so much
|
||||
// easier to use switch coverage to catch new cases.
|
||||
switch (_ctx.os()) {
|
||||
case lld::MachOLinkingContext::OS::unknown:
|
||||
case lld::MachOLinkingContext::OS::macOSX:
|
||||
case lld::MachOLinkingContext::OS::iOS_simulator:
|
||||
if (segName.equals("__PAGEZERO")) {
|
||||
info->max_access = 0;
|
||||
break;
|
||||
}
|
||||
// All others default to all
|
||||
info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
|
||||
break;
|
||||
case lld::MachOLinkingContext::OS::iOS:
|
||||
// iPhoneOS always uses same protection for max and initial
|
||||
info->max_access = info->init_access;
|
||||
break;
|
||||
}
|
||||
_segmentInfos.push_back(info);
|
||||
return info;
|
||||
}
|
||||
|
@ -589,7 +617,8 @@ void Util::copySegmentInfo(NormalizedFile &file) {
|
|||
seg.name = sgi->name;
|
||||
seg.address = sgi->address;
|
||||
seg.size = sgi->size;
|
||||
seg.access = sgi->access;
|
||||
seg.init_access = sgi->init_access;
|
||||
seg.max_access = sgi->max_access;
|
||||
file.segments.push_back(seg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -504,10 +504,11 @@ struct ScalarTraits<VMProtect> {
|
|||
template <>
|
||||
struct MappingTraits<Segment> {
|
||||
static void mapping(IO &io, Segment& seg) {
|
||||
io.mapRequired("name", seg.name);
|
||||
io.mapRequired("address", seg.address);
|
||||
io.mapRequired("size", seg.size);
|
||||
io.mapRequired("access", seg.access);
|
||||
io.mapRequired("name", seg.name);
|
||||
io.mapRequired("address", seg.address);
|
||||
io.mapRequired("size", seg.size);
|
||||
io.mapRequired("init-access", seg.init_access);
|
||||
io.mapRequired("max-access", seg.max_access);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
|
||||
|
||||
--- !mach-o
|
||||
arch: arm64
|
||||
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: [ 0x00, 0x00 ]
|
||||
global-symbols:
|
||||
- name: _main
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: start
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
|
||||
...
|
||||
|
||||
# CHECK: Load command 0
|
||||
# CHECK: cmd LC_SEGMENT_64
|
||||
# CHECK: cmdsize 72
|
||||
# CHECK: segname __PAGEZERO
|
||||
# CHECK: vmaddr
|
||||
# CHECK: vmsize
|
||||
# CHECK: fileoff
|
||||
# CHECK: filesize
|
||||
# CHECK: maxprot ---
|
||||
# CHECK: initprot ---
|
||||
# CHECK: nsects 0
|
||||
# CHECK: flags (none)
|
||||
# CHECK: Load command 1
|
||||
# CHECK: cmd LC_SEGMENT_64
|
||||
# CHECK: cmdsize 152
|
||||
# CHECK: segname __TEXT
|
||||
# CHECK: vmaddr
|
||||
# CHECK: vmsize
|
||||
# CHECK: fileoff
|
||||
# CHECK: filesize
|
||||
# CHECK: maxprot r-x
|
||||
# CHECK: initprot r-x
|
||||
# CHECK: nsects 1
|
||||
# CHECK: flags (none)
|
||||
# CHECK: Section
|
||||
# CHECK: sectname __text
|
||||
# CHECK: segname __TEXT
|
||||
# CHECK: addr
|
||||
# CHECK: size
|
||||
# CHECK: offset
|
||||
# CHECK: align 2^0 (1)
|
||||
# CHECK: reloff 0
|
||||
# CHECK: nreloc 0
|
||||
# CHECK: type S_REGULAR
|
||||
# CHECK: attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
|
||||
# CHECK: reserved1 0
|
||||
# CHECK: reserved2 0
|
||||
# CHECK: Load command 2
|
||||
# CHECK: cmd LC_SEGMENT_64
|
||||
# CHECK: cmdsize 72
|
||||
# CHECK: segname __LINKEDIT
|
||||
# CHECK: vmaddr
|
||||
# CHECK: vmsize
|
||||
# CHECK: fileoff
|
||||
# CHECK: filesize
|
||||
# CHECK: maxprot r--
|
||||
# CHECK: initprot r--
|
||||
# CHECK: nsects 0
|
||||
# CHECK: flags (none)
|
|
@ -0,0 +1,78 @@
|
|||
# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
|
||||
|
||||
--- !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: [ 0x00, 0x00 ]
|
||||
global-symbols:
|
||||
- name: _main
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: start
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
|
||||
...
|
||||
|
||||
# CHECK: Load command 0
|
||||
# CHECK: cmd LC_SEGMENT_64
|
||||
# CHECK: cmdsize 72
|
||||
# CHECK: segname __PAGEZERO
|
||||
# CHECK: vmaddr
|
||||
# CHECK: vmsize
|
||||
# CHECK: fileoff
|
||||
# CHECK: filesize
|
||||
# CHECK: maxprot ---
|
||||
# CHECK: initprot ---
|
||||
# CHECK: nsects 0
|
||||
# CHECK: flags (none)
|
||||
# CHECK: Load command 1
|
||||
# CHECK: cmd LC_SEGMENT_64
|
||||
# CHECK: cmdsize 152
|
||||
# CHECK: segname __TEXT
|
||||
# CHECK: vmaddr
|
||||
# CHECK: vmsize
|
||||
# CHECK: fileoff
|
||||
# CHECK: filesize
|
||||
# CHECK: maxprot rwx
|
||||
# CHECK: initprot r-x
|
||||
# CHECK: nsects 1
|
||||
# CHECK: flags (none)
|
||||
# CHECK: Section
|
||||
# CHECK: sectname __text
|
||||
# CHECK: segname __TEXT
|
||||
# CHECK: addr
|
||||
# CHECK: size
|
||||
# CHECK: offset
|
||||
# CHECK: align 2^0 (1)
|
||||
# CHECK: reloff 0
|
||||
# CHECK: nreloc 0
|
||||
# CHECK: type S_REGULAR
|
||||
# CHECK: attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
|
||||
# CHECK: reserved1 0
|
||||
# CHECK: reserved2 0
|
||||
# CHECK: Load command 2
|
||||
# CHECK: cmd LC_SEGMENT_64
|
||||
# CHECK: cmdsize 72
|
||||
# CHECK: segname __LINKEDIT
|
||||
# CHECK: vmaddr
|
||||
# CHECK: vmsize
|
||||
# CHECK: fileoff
|
||||
# CHECK: filesize
|
||||
# CHECK: maxprot rwx
|
||||
# CHECK: initprot r--
|
||||
# CHECK: nsects 0
|
||||
# CHECK: flags (none)
|
Loading…
Reference in New Issue