[lld-macho] Add support for arm64_32
From what I can tell, it's pretty similar to arm64. The two main differences are: 1. No 64-bit relocations 2. Stub code writes to 32-bit registers instead of 64-bit Plus of course the various on-disk structures like `segment_command` are using the 32-bit instead of the 64-bit variants. Reviewed By: #lld-macho, gkm Differential Revision: https://reviews.llvm.org/D99822
This commit is contained in:
parent
db7a413e51
commit
3bc88eb392
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Arch/ARM64Common.h"
|
||||
#include "InputFiles.h"
|
||||
#include "Symbols.h"
|
||||
#include "SyntheticSections.h"
|
||||
|
@ -25,22 +26,13 @@ using namespace lld::macho;
|
|||
|
||||
namespace {
|
||||
|
||||
struct ARM64 : TargetInfo {
|
||||
struct ARM64 : ARM64Common {
|
||||
ARM64();
|
||||
|
||||
int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset,
|
||||
const relocation_info) const override;
|
||||
void relocateOne(uint8_t *loc, const Reloc &, uint64_t va,
|
||||
uint64_t pc) const override;
|
||||
|
||||
void writeStub(uint8_t *buf, const Symbol &) const override;
|
||||
void writeStubHelperHeader(uint8_t *buf) const override;
|
||||
void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
|
||||
uint64_t entryAddr) const override;
|
||||
|
||||
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
|
||||
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
|
||||
uint64_t getPageSize() const override { return 16 * 1024; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -77,140 +69,6 @@ const RelocAttrs &ARM64::getRelocAttrs(uint8_t type) const {
|
|||
return relocAttrsArray[type];
|
||||
}
|
||||
|
||||
int64_t ARM64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
|
||||
const relocation_info rel) const {
|
||||
if (rel.r_type != ARM64_RELOC_UNSIGNED &&
|
||||
rel.r_type != ARM64_RELOC_SUBTRACTOR) {
|
||||
// All other reloc types should use the ADDEND relocation to store their
|
||||
// addends.
|
||||
// TODO(gkm): extract embedded addend just so we can assert that it is 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
|
||||
const uint8_t *loc = buf + offset + rel.r_address;
|
||||
switch (rel.r_length) {
|
||||
case 2:
|
||||
return static_cast<int32_t>(read32le(loc));
|
||||
case 3:
|
||||
return read64le(loc);
|
||||
default:
|
||||
llvm_unreachable("invalid r_length");
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t bitField(uint64_t value, int right, int width, int left) {
|
||||
return ((value >> right) & ((1 << width) - 1)) << left;
|
||||
}
|
||||
|
||||
// 25 0
|
||||
// +-----------+---------------------------------------------------+
|
||||
// | | imm26 |
|
||||
// +-----------+---------------------------------------------------+
|
||||
|
||||
inline uint64_t encodeBranch26(const Reloc &r, uint64_t base, uint64_t va) {
|
||||
checkInt(r, va, 28);
|
||||
// Since branch destinations are 4-byte aligned, the 2 least-
|
||||
// significant bits are 0. They are right shifted off the end.
|
||||
return (base | bitField(va, 2, 26, 0));
|
||||
}
|
||||
|
||||
inline uint64_t encodeBranch26(SymbolDiagnostic d, uint64_t base, uint64_t va) {
|
||||
checkInt(d, va, 28);
|
||||
return (base | bitField(va, 2, 26, 0));
|
||||
}
|
||||
|
||||
// 30 29 23 5
|
||||
// +-+---+---------+-------------------------------------+---------+
|
||||
// | |ilo| | immhi | |
|
||||
// +-+---+---------+-------------------------------------+---------+
|
||||
|
||||
inline uint64_t encodePage21(const Reloc &r, uint64_t base, uint64_t va) {
|
||||
checkInt(r, va, 35);
|
||||
return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5));
|
||||
}
|
||||
|
||||
inline uint64_t encodePage21(SymbolDiagnostic d, uint64_t base, uint64_t va) {
|
||||
checkInt(d, va, 35);
|
||||
return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5));
|
||||
}
|
||||
|
||||
// 21 10
|
||||
// +-------------------+-----------------------+-------------------+
|
||||
// | | imm12 | |
|
||||
// +-------------------+-----------------------+-------------------+
|
||||
|
||||
inline uint64_t encodePageOff12(uint32_t base, uint64_t va) {
|
||||
int scale = 0;
|
||||
if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store
|
||||
scale = base >> 30;
|
||||
if (scale == 0 && (base & 0x0480'0000) == 0x0480'0000) // 128-bit variant
|
||||
scale = 4;
|
||||
}
|
||||
|
||||
// TODO(gkm): extract embedded addend and warn if != 0
|
||||
// uint64_t addend = ((base & 0x003FFC00) >> 10);
|
||||
return (base | bitField(va, scale, 12 - scale, 10));
|
||||
}
|
||||
|
||||
inline uint64_t pageBits(uint64_t address) {
|
||||
const uint64_t pageMask = ~0xfffull;
|
||||
return address & pageMask;
|
||||
}
|
||||
|
||||
// For instruction relocations (load, store, add), the base
|
||||
// instruction is pre-populated in the text section. A pre-populated
|
||||
// instruction has opcode & register-operand bits set, with immediate
|
||||
// operands zeroed. We read it from text, OR-in the immediate
|
||||
// operands, then write-back the completed instruction.
|
||||
|
||||
void ARM64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
|
||||
uint64_t pc) const {
|
||||
uint32_t base = ((r.length == 2) ? read32le(loc) : 0);
|
||||
value += r.addend;
|
||||
switch (r.type) {
|
||||
case ARM64_RELOC_BRANCH26:
|
||||
value = encodeBranch26(r, base, value - pc);
|
||||
break;
|
||||
case ARM64_RELOC_SUBTRACTOR:
|
||||
case ARM64_RELOC_UNSIGNED:
|
||||
if (r.length == 2)
|
||||
checkInt(r, value, 32);
|
||||
break;
|
||||
case ARM64_RELOC_POINTER_TO_GOT:
|
||||
if (r.pcrel)
|
||||
value -= pc;
|
||||
checkInt(r, value, 32);
|
||||
break;
|
||||
case ARM64_RELOC_PAGE21:
|
||||
case ARM64_RELOC_GOT_LOAD_PAGE21:
|
||||
case ARM64_RELOC_TLVP_LOAD_PAGE21: {
|
||||
assert(r.pcrel);
|
||||
value = encodePage21(r, base, pageBits(value) - pageBits(pc));
|
||||
break;
|
||||
}
|
||||
case ARM64_RELOC_PAGEOFF12:
|
||||
case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
||||
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
|
||||
assert(!r.pcrel);
|
||||
value = encodePageOff12(base, value);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected relocation type");
|
||||
}
|
||||
|
||||
switch (r.length) {
|
||||
case 2:
|
||||
write32le(loc, value);
|
||||
break;
|
||||
case 3:
|
||||
write64le(loc, value);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("invalid r_length");
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint32_t stubCode[] = {
|
||||
0x90000010, // 00: adrp x16, __la_symbol_ptr@page
|
||||
0xf9400210, // 04: ldr x16, [x16, __la_symbol_ptr@pageoff]
|
||||
|
@ -218,15 +76,7 @@ static constexpr uint32_t stubCode[] = {
|
|||
};
|
||||
|
||||
void ARM64::writeStub(uint8_t *buf8, const Symbol &sym) const {
|
||||
auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
|
||||
uint64_t pcPageBits =
|
||||
pageBits(in.stubs->addr + sym.stubsIndex * sizeof(stubCode));
|
||||
uint64_t lazyPointerVA =
|
||||
in.lazyPointers->addr + sym.stubsIndex * LP64::wordSize;
|
||||
buf32[0] = encodePage21({&sym, "stub"}, stubCode[0],
|
||||
pageBits(lazyPointerVA) - pcPageBits);
|
||||
buf32[1] = encodePageOff12(stubCode[1], lazyPointerVA);
|
||||
buf32[2] = stubCode[2];
|
||||
::writeStub<LP64, stubCode>(buf8, sym);
|
||||
}
|
||||
|
||||
static constexpr uint32_t stubHelperHeaderCode[] = {
|
||||
|
@ -239,22 +89,7 @@ static constexpr uint32_t stubHelperHeaderCode[] = {
|
|||
};
|
||||
|
||||
void ARM64::writeStubHelperHeader(uint8_t *buf8) const {
|
||||
auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
|
||||
auto pcPageBits = [](int i) {
|
||||
return pageBits(in.stubHelper->addr + i * sizeof(uint32_t));
|
||||
};
|
||||
uint64_t loaderVA = in.imageLoaderCache->getVA();
|
||||
SymbolDiagnostic d = {nullptr, "stub header helper"};
|
||||
buf32[0] = encodePage21(d, stubHelperHeaderCode[0],
|
||||
pageBits(loaderVA) - pcPageBits(0));
|
||||
buf32[1] = encodePageOff12(stubHelperHeaderCode[1], loaderVA);
|
||||
buf32[2] = stubHelperHeaderCode[2];
|
||||
uint64_t binderVA =
|
||||
in.got->addr + in.stubHelper->stubBinder->gotIndex * LP64::wordSize;
|
||||
buf32[3] = encodePage21(d, stubHelperHeaderCode[3],
|
||||
pageBits(binderVA) - pcPageBits(3));
|
||||
buf32[4] = encodePageOff12(stubHelperHeaderCode[4], binderVA);
|
||||
buf32[5] = stubHelperHeaderCode[5];
|
||||
::writeStubHelperHeader<LP64, stubHelperHeaderCode>(buf8);
|
||||
}
|
||||
|
||||
static constexpr uint32_t stubHelperEntryCode[] = {
|
||||
|
@ -265,34 +100,10 @@ static constexpr uint32_t stubHelperEntryCode[] = {
|
|||
|
||||
void ARM64::writeStubHelperEntry(uint8_t *buf8, const DylibSymbol &sym,
|
||||
uint64_t entryVA) const {
|
||||
auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
|
||||
auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); };
|
||||
uint64_t stubHelperHeaderVA = in.stubHelper->addr;
|
||||
buf32[0] = stubHelperEntryCode[0];
|
||||
buf32[1] = encodeBranch26({&sym, "stub helper"}, stubHelperEntryCode[1],
|
||||
stubHelperHeaderVA - pcVA(1));
|
||||
buf32[2] = sym.lazyBindOffset;
|
||||
::writeStubHelperEntry<stubHelperEntryCode>(buf8, sym, entryVA);
|
||||
}
|
||||
|
||||
void ARM64::relaxGotLoad(uint8_t *loc, uint8_t type) const {
|
||||
// The instruction format comments below are quoted from
|
||||
// Arm® Architecture Reference Manual
|
||||
// Armv8, for Armv8-A architecture profile
|
||||
// ARM DDI 0487G.a (ID011921)
|
||||
uint32_t instruction = read32le(loc);
|
||||
// C6.2.132 LDR (immediate)
|
||||
// LDR <Xt>, [<Xn|SP>{, #<pimm>}]
|
||||
if ((instruction & 0xffc00000) != 0xf9400000)
|
||||
error(getRelocAttrs(type).name + " reloc requires LDR instruction");
|
||||
assert(((instruction >> 10) & 0xfff) == 0 &&
|
||||
"non-zero embedded LDR immediate");
|
||||
// C6.2.4 ADD (immediate)
|
||||
// ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}
|
||||
instruction = ((instruction & 0x001fffff) | 0x91000000);
|
||||
write32le(loc, instruction);
|
||||
}
|
||||
|
||||
ARM64::ARM64() : TargetInfo(LP64()) {
|
||||
ARM64::ARM64() : ARM64Common(LP64()) {
|
||||
cpuType = CPU_TYPE_ARM64;
|
||||
cpuSubtype = CPU_SUBTYPE_ARM64_ALL;
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
//===- ARM64Common.cpp ----------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Arch/ARM64Common.h"
|
||||
|
||||
#include "lld/Common/ErrorHandler.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
using namespace llvm::MachO;
|
||||
using namespace llvm::support::endian;
|
||||
using namespace lld;
|
||||
using namespace lld::macho;
|
||||
|
||||
int64_t ARM64Common::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
|
||||
const relocation_info rel) const {
|
||||
if (rel.r_type != ARM64_RELOC_UNSIGNED &&
|
||||
rel.r_type != ARM64_RELOC_SUBTRACTOR) {
|
||||
// All other reloc types should use the ADDEND relocation to store their
|
||||
// addends.
|
||||
// TODO(gkm): extract embedded addend just so we can assert that it is 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
|
||||
const uint8_t *loc = buf + offset + rel.r_address;
|
||||
switch (rel.r_length) {
|
||||
case 2:
|
||||
return static_cast<int32_t>(read32le(loc));
|
||||
case 3:
|
||||
return read64le(loc);
|
||||
default:
|
||||
llvm_unreachable("invalid r_length");
|
||||
}
|
||||
}
|
||||
|
||||
// For instruction relocations (load, store, add), the base
|
||||
// instruction is pre-populated in the text section. A pre-populated
|
||||
// instruction has opcode & register-operand bits set, with immediate
|
||||
// operands zeroed. We read it from text, OR-in the immediate
|
||||
// operands, then write-back the completed instruction.
|
||||
|
||||
void ARM64Common::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
|
||||
uint64_t pc) const {
|
||||
uint32_t base = ((r.length == 2) ? read32le(loc) : 0);
|
||||
value += r.addend;
|
||||
switch (r.type) {
|
||||
case ARM64_RELOC_BRANCH26:
|
||||
value = encodeBranch26(r, base, value - pc);
|
||||
break;
|
||||
case ARM64_RELOC_SUBTRACTOR:
|
||||
case ARM64_RELOC_UNSIGNED:
|
||||
if (r.length == 2)
|
||||
checkInt(r, value, 32);
|
||||
break;
|
||||
case ARM64_RELOC_POINTER_TO_GOT:
|
||||
if (r.pcrel)
|
||||
value -= pc;
|
||||
checkInt(r, value, 32);
|
||||
break;
|
||||
case ARM64_RELOC_PAGE21:
|
||||
case ARM64_RELOC_GOT_LOAD_PAGE21:
|
||||
case ARM64_RELOC_TLVP_LOAD_PAGE21: {
|
||||
assert(r.pcrel);
|
||||
value = encodePage21(r, base, pageBits(value) - pageBits(pc));
|
||||
break;
|
||||
}
|
||||
case ARM64_RELOC_PAGEOFF12:
|
||||
case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
||||
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
|
||||
assert(!r.pcrel);
|
||||
value = encodePageOff12(base, value);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected relocation type");
|
||||
}
|
||||
|
||||
switch (r.length) {
|
||||
case 2:
|
||||
write32le(loc, value);
|
||||
break;
|
||||
case 3:
|
||||
write64le(loc, value);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("invalid r_length");
|
||||
}
|
||||
}
|
||||
|
||||
void ARM64Common::relaxGotLoad(uint8_t *loc, uint8_t type) const {
|
||||
// The instruction format comments below are quoted from
|
||||
// Arm® Architecture Reference Manual
|
||||
// Armv8, for Armv8-A architecture profile
|
||||
// ARM DDI 0487G.a (ID011921)
|
||||
uint32_t instruction = read32le(loc);
|
||||
// C6.2.132 LDR (immediate)
|
||||
// LDR <Xt>, [<Xn|SP>{, #<pimm>}]
|
||||
if ((instruction & 0xffc00000) != 0xf9400000)
|
||||
error(getRelocAttrs(type).name + " reloc requires LDR instruction");
|
||||
assert(((instruction >> 10) & 0xfff) == 0 &&
|
||||
"non-zero embedded LDR immediate");
|
||||
// C6.2.4 ADD (immediate)
|
||||
// ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}
|
||||
instruction = ((instruction & 0x001fffff) | 0x91000000);
|
||||
write32le(loc, instruction);
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
//===- ARM64Common.h --------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_MACHO_ARCH_ARM64COMMON_H
|
||||
#define LLD_MACHO_ARCH_ARM64COMMON_H
|
||||
|
||||
#include "InputFiles.h"
|
||||
#include "Symbols.h"
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
|
||||
#include "llvm/BinaryFormat/MachO.h"
|
||||
|
||||
namespace lld {
|
||||
namespace macho {
|
||||
|
||||
struct ARM64Common : TargetInfo {
|
||||
template <class LP> ARM64Common(LP lp) : TargetInfo(lp) {}
|
||||
|
||||
int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset,
|
||||
const llvm::MachO::relocation_info) const override;
|
||||
void relocateOne(uint8_t *loc, const Reloc &, uint64_t va,
|
||||
uint64_t pc) const override;
|
||||
|
||||
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
|
||||
uint64_t getPageSize() const override { return 16 * 1024; }
|
||||
};
|
||||
|
||||
inline uint64_t bitField(uint64_t value, int right, int width, int left) {
|
||||
return ((value >> right) & ((1 << width) - 1)) << left;
|
||||
}
|
||||
|
||||
// 25 0
|
||||
// +-----------+---------------------------------------------------+
|
||||
// | | imm26 |
|
||||
// +-----------+---------------------------------------------------+
|
||||
|
||||
inline uint64_t encodeBranch26(const Reloc &r, uint64_t base, uint64_t va) {
|
||||
checkInt(r, va, 28);
|
||||
// Since branch destinations are 4-byte aligned, the 2 least-
|
||||
// significant bits are 0. They are right shifted off the end.
|
||||
return (base | bitField(va, 2, 26, 0));
|
||||
}
|
||||
|
||||
inline uint64_t encodeBranch26(SymbolDiagnostic d, uint64_t base, uint64_t va) {
|
||||
checkInt(d, va, 28);
|
||||
return (base | bitField(va, 2, 26, 0));
|
||||
}
|
||||
|
||||
// 30 29 23 5
|
||||
// +-+---+---------+-------------------------------------+---------+
|
||||
// | |ilo| | immhi | |
|
||||
// +-+---+---------+-------------------------------------+---------+
|
||||
|
||||
inline uint64_t encodePage21(const Reloc &r, uint64_t base, uint64_t va) {
|
||||
checkInt(r, va, 35);
|
||||
return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5));
|
||||
}
|
||||
|
||||
inline uint64_t encodePage21(SymbolDiagnostic d, uint64_t base, uint64_t va) {
|
||||
checkInt(d, va, 35);
|
||||
return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5));
|
||||
}
|
||||
|
||||
// 21 10
|
||||
// +-------------------+-----------------------+-------------------+
|
||||
// | | imm12 | |
|
||||
// +-------------------+-----------------------+-------------------+
|
||||
|
||||
inline uint64_t encodePageOff12(uint32_t base, uint64_t va) {
|
||||
int scale = 0;
|
||||
if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store
|
||||
scale = base >> 30;
|
||||
if (scale == 0 && (base & 0x0480'0000) == 0x0480'0000) // 128-bit variant
|
||||
scale = 4;
|
||||
}
|
||||
|
||||
// TODO(gkm): extract embedded addend and warn if != 0
|
||||
// uint64_t addend = ((base & 0x003FFC00) >> 10);
|
||||
return (base | bitField(va, scale, 12 - scale, 10));
|
||||
}
|
||||
|
||||
inline uint64_t pageBits(uint64_t address) {
|
||||
const uint64_t pageMask = ~0xfffull;
|
||||
return address & pageMask;
|
||||
}
|
||||
|
||||
template <class LP, const uint32_t stubCode[3]>
|
||||
inline void writeStub(uint8_t *buf8, const macho::Symbol &sym) {
|
||||
auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
|
||||
uint64_t pcPageBits =
|
||||
pageBits(in.stubs->addr + sym.stubsIndex * sizeof(stubCode));
|
||||
uint64_t lazyPointerVA =
|
||||
in.lazyPointers->addr + sym.stubsIndex * LP::wordSize;
|
||||
buf32[0] = encodePage21({&sym, "stub"}, stubCode[0],
|
||||
pageBits(lazyPointerVA) - pcPageBits);
|
||||
buf32[1] = encodePageOff12(stubCode[1], lazyPointerVA);
|
||||
buf32[2] = stubCode[2];
|
||||
}
|
||||
|
||||
template <class LP, const uint32_t stubHelperHeaderCode[6]>
|
||||
inline void writeStubHelperHeader(uint8_t *buf8) {
|
||||
auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
|
||||
auto pcPageBits = [](int i) {
|
||||
return pageBits(in.stubHelper->addr + i * sizeof(uint32_t));
|
||||
};
|
||||
uint64_t loaderVA = in.imageLoaderCache->getVA();
|
||||
SymbolDiagnostic d = {nullptr, "stub header helper"};
|
||||
buf32[0] = encodePage21(d, stubHelperHeaderCode[0],
|
||||
pageBits(loaderVA) - pcPageBits(0));
|
||||
buf32[1] = encodePageOff12(stubHelperHeaderCode[1], loaderVA);
|
||||
buf32[2] = stubHelperHeaderCode[2];
|
||||
uint64_t binderVA =
|
||||
in.got->addr + in.stubHelper->stubBinder->gotIndex * LP::wordSize;
|
||||
buf32[3] = encodePage21(d, stubHelperHeaderCode[3],
|
||||
pageBits(binderVA) - pcPageBits(3));
|
||||
buf32[4] = encodePageOff12(stubHelperHeaderCode[4], binderVA);
|
||||
buf32[5] = stubHelperHeaderCode[5];
|
||||
}
|
||||
|
||||
template <const uint32_t stubHelperEntryCode[3]>
|
||||
void writeStubHelperEntry(uint8_t *buf8, const DylibSymbol &sym,
|
||||
uint64_t entryVA) {
|
||||
auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
|
||||
auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); };
|
||||
uint64_t stubHelperHeaderVA = in.stubHelper->addr;
|
||||
buf32[0] = stubHelperEntryCode[0];
|
||||
buf32[1] = encodeBranch26({&sym, "stub helper"}, stubHelperEntryCode[1],
|
||||
stubHelperHeaderVA - pcVA(1));
|
||||
buf32[2] = sym.lazyBindOffset;
|
||||
}
|
||||
|
||||
} // namespace macho
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -0,0 +1,116 @@
|
|||
//===- ARM64_32.cpp
|
||||
//----------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Arch/ARM64Common.h"
|
||||
#include "InputFiles.h"
|
||||
#include "Symbols.h"
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
|
||||
#include "lld/Common/ErrorHandler.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/BinaryFormat/MachO.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
using namespace llvm::MachO;
|
||||
using namespace llvm::support::endian;
|
||||
using namespace lld;
|
||||
using namespace lld::macho;
|
||||
|
||||
namespace {
|
||||
|
||||
struct ARM64_32 : ARM64Common {
|
||||
ARM64_32();
|
||||
void writeStub(uint8_t *buf, const Symbol &) const override;
|
||||
void writeStubHelperHeader(uint8_t *buf) const override;
|
||||
void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
|
||||
uint64_t entryAddr) const override;
|
||||
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// These are very similar to ARM64's relocation attributes, except that we don't
|
||||
// have the BYTE8 flag set.
|
||||
const RelocAttrs &ARM64_32::getRelocAttrs(uint8_t type) const {
|
||||
static const std::array<RelocAttrs, 11> relocAttrsArray{{
|
||||
#define B(x) RelocAttrBits::x
|
||||
{"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
|
||||
{"SUBTRACTOR", B(SUBTRAHEND) | B(BYTE4)},
|
||||
{"BRANCH26", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
|
||||
{"PAGE21", B(PCREL) | B(EXTERN) | B(BYTE4)},
|
||||
{"PAGEOFF12", B(ABSOLUTE) | B(EXTERN) | B(BYTE4)},
|
||||
{"GOT_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(GOT) | B(BYTE4)},
|
||||
{"GOT_LOAD_PAGEOFF12",
|
||||
B(ABSOLUTE) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)},
|
||||
{"POINTER_TO_GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)},
|
||||
{"TLVP_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(TLV) | B(BYTE4)},
|
||||
{"TLVP_LOAD_PAGEOFF12",
|
||||
B(ABSOLUTE) | B(EXTERN) | B(TLV) | B(LOAD) | B(BYTE4)},
|
||||
{"ADDEND", B(ADDEND)},
|
||||
#undef B
|
||||
}};
|
||||
assert(type < relocAttrsArray.size() && "invalid relocation type");
|
||||
if (type >= relocAttrsArray.size())
|
||||
return invalidRelocAttrs;
|
||||
return relocAttrsArray[type];
|
||||
}
|
||||
|
||||
// The stub code is fairly similar to ARM64's, except that we load pointers into
|
||||
// 32-bit 'w' registers, instead of the 64-bit 'x' ones.
|
||||
|
||||
static constexpr uint32_t stubCode[] = {
|
||||
0x90000010, // 00: adrp x16, __la_symbol_ptr@page
|
||||
0xb9400210, // 04: ldr w16, [x16, __la_symbol_ptr@pageoff]
|
||||
0xd61f0200, // 08: br x16
|
||||
};
|
||||
|
||||
void ARM64_32::writeStub(uint8_t *buf8, const Symbol &sym) const {
|
||||
::writeStub<ILP32, stubCode>(buf8, sym);
|
||||
}
|
||||
|
||||
static constexpr uint32_t stubHelperHeaderCode[] = {
|
||||
0x90000011, // 00: adrp x17, _dyld_private@page
|
||||
0x91000231, // 04: add x17, x17, _dyld_private@pageoff
|
||||
0xa9bf47f0, // 08: stp x16/x17, [sp, #-16]!
|
||||
0x90000010, // 0c: adrp x16, dyld_stub_binder@page
|
||||
0xb9400210, // 10: ldr w16, [x16, dyld_stub_binder@pageoff]
|
||||
0xd61f0200, // 14: br x16
|
||||
};
|
||||
|
||||
void ARM64_32::writeStubHelperHeader(uint8_t *buf8) const {
|
||||
::writeStubHelperHeader<ILP32, stubHelperHeaderCode>(buf8);
|
||||
}
|
||||
|
||||
static constexpr uint32_t stubHelperEntryCode[] = {
|
||||
0x18000050, // 00: ldr w16, l0
|
||||
0x14000000, // 04: b stubHelperHeader
|
||||
0x00000000, // 08: l0: .long 0
|
||||
};
|
||||
|
||||
void ARM64_32::writeStubHelperEntry(uint8_t *buf8, const DylibSymbol &sym,
|
||||
uint64_t entryVA) const {
|
||||
::writeStubHelperEntry<stubHelperEntryCode>(buf8, sym, entryVA);
|
||||
}
|
||||
|
||||
ARM64_32::ARM64_32() : ARM64Common(ILP32()) {
|
||||
cpuType = CPU_TYPE_ARM64_32;
|
||||
cpuSubtype = CPU_SUBTYPE_ARM64_V8;
|
||||
|
||||
stubSize = sizeof(stubCode);
|
||||
stubHelperHeaderSize = sizeof(stubHelperHeaderCode);
|
||||
stubHelperEntrySize = sizeof(stubHelperEntryCode);
|
||||
}
|
||||
|
||||
TargetInfo *macho::createARM64_32TargetInfo() {
|
||||
static ARM64_32 t;
|
||||
return &t;
|
||||
}
|
|
@ -7,6 +7,8 @@ include_directories(${LLVM_MAIN_SRC_DIR}/../libunwind/include)
|
|||
add_lld_library(lldMachO2
|
||||
Arch/X86_64.cpp
|
||||
Arch/ARM64.cpp
|
||||
Arch/ARM64Common.cpp
|
||||
Arch/ARM64_32.cpp
|
||||
UnwindInfoSection.cpp
|
||||
Driver.cpp
|
||||
DriverUtils.cpp
|
||||
|
|
|
@ -622,6 +622,8 @@ static TargetInfo *createTargetInfo(InputArgList &args) {
|
|||
return createX86_64TargetInfo();
|
||||
case CPU_TYPE_ARM64:
|
||||
return createARM64TargetInfo();
|
||||
case CPU_TYPE_ARM64_32:
|
||||
return createARM64_32TargetInfo();
|
||||
default:
|
||||
fatal("missing or unsupported -arch " + archName);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,13 @@ struct nlist {
|
|||
llvm::support::ulittle32_t n_value;
|
||||
};
|
||||
|
||||
struct entry_point_command {
|
||||
llvm::support::ulittle32_t cmd;
|
||||
llvm::support::ulittle32_t cmdsize;
|
||||
llvm::support::ulittle64_t entryoff;
|
||||
llvm::support::ulittle64_t stacksize;
|
||||
};
|
||||
|
||||
} // namespace structs
|
||||
|
||||
} // namespace lld
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
|
||||
TargetInfo *createX86_64TargetInfo();
|
||||
TargetInfo *createARM64TargetInfo();
|
||||
TargetInfo *createARM64_32TargetInfo();
|
||||
|
||||
struct LP64 {
|
||||
using mach_header = llvm::MachO::mach_header_64;
|
||||
|
|
|
@ -234,10 +234,12 @@ private:
|
|||
};
|
||||
|
||||
class LCMain : public LoadCommand {
|
||||
uint32_t getSize() const override { return sizeof(entry_point_command); }
|
||||
uint32_t getSize() const override {
|
||||
return sizeof(structs::entry_point_command);
|
||||
}
|
||||
|
||||
void writeTo(uint8_t *buf) const override {
|
||||
auto *c = reinterpret_cast<entry_point_command *>(buf);
|
||||
auto *c = reinterpret_cast<structs::entry_point_command *>(buf);
|
||||
c->cmd = LC_MAIN;
|
||||
c->cmdsize = getSize();
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
--- !tapi-tbd
|
||||
tbd-version: 4
|
||||
targets: [ armv7k-watchos, arm64_32-watchos ]
|
||||
uuids:
|
||||
- target: armv7k-watchos
|
||||
value: 00000000-0000-0000-0000-000000000001
|
||||
- target: arm64_32-watchos
|
||||
value: 00000000-0000-0000-0000-000000000002
|
||||
install-name: '/usr/lib/libSystem.dylib'
|
||||
current-version: 1.0.0
|
||||
exports:
|
||||
- targets: [ arm64_32-watchos, armv7k-watchos ]
|
||||
symbols: [ dyld_stub_binder ]
|
||||
...
|
|
@ -0,0 +1,14 @@
|
|||
--- !tapi-tbd
|
||||
tbd-version: 4
|
||||
targets: [ armv7k-watchos, arm64_32-watchos ]
|
||||
uuids:
|
||||
- target: armv7k-watchos
|
||||
value: 00000000-0000-0000-0000-000000000001
|
||||
- target: arm64_32-watchos
|
||||
value: 00000000-0000-0000-0000-000000000002
|
||||
install-name: '/usr/lib/libc++.dylib'
|
||||
current-version: 1.0.0
|
||||
reexported-libraries:
|
||||
- targets: [ arm64_32-watchos, armv7k-watchos ]
|
||||
libraries: [ '/usr/lib/libc++abi.dylib' ]
|
||||
...
|
|
@ -0,0 +1,14 @@
|
|||
--- !tapi-tbd
|
||||
tbd-version: 4
|
||||
targets: [ armv7k-watchos, arm64_32-watchos ]
|
||||
uuids:
|
||||
- target: armv7k-watchos
|
||||
value: 00000000-0000-0000-0000-000000000001
|
||||
- target: arm64_32-watchos
|
||||
value: 00000000-0000-0000-0000-000000000002
|
||||
install-name: '/usr/lib/libc++abi.dylib'
|
||||
current-version: 1.0.0
|
||||
exports:
|
||||
- targets: [ arm64_32-watchos, armv7k-watchos ]
|
||||
symbols: [ ___gxx_personality_v0 ]
|
||||
...
|
|
@ -0,0 +1,60 @@
|
|||
# REQUIRES: aarch64
|
||||
|
||||
## FIXME: This test is very similar to arm64-stubs.s, but has been split into a
|
||||
## separate file because llvm-objdump doesn't correctly symbolize arm64_32. In
|
||||
## particular, the "literal pool symbol address" comments are missing (PR49944).
|
||||
|
||||
# RUN: rm -rf %t; split-file %s %t
|
||||
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %t/foo.s -o %t/foo.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %t/bar.s -o %t/bar.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %t/test.s -o %t/test.o
|
||||
# RUN: %lld-watchos -dylib -install_name @executable_path/libfoo.dylib %t/foo.o -o %t/libfoo.dylib
|
||||
# RUN: %lld-watchos -dylib -install_name @executable_path/libbar.dylib %t/bar.o -o %t/libbar.dylib
|
||||
# RUN: %lld-watchos -lSystem %t/libfoo.dylib %t/libbar.dylib %t/test.o -o %t/test
|
||||
|
||||
# RUN: llvm-objdump --macho -d --no-show-raw-insn --section="__TEXT,__stubs" --section="__TEXT,__stub_helper" %t/test | FileCheck %s
|
||||
|
||||
# CHECK: _main:
|
||||
# CHECK-NEXT: bl 0x[[#%x,FOO:]] ; symbol stub for: _foo
|
||||
# CHECK-NEXT: bl 0x[[#%x,BAR:]] ; symbol stub for: _bar
|
||||
# CHECK-NEXT: ret
|
||||
|
||||
# CHECK-LABEL: Contents of (__TEXT,__stubs) section
|
||||
# CHECK-NEXT: [[#BAR]]: adrp x16
|
||||
# CHECK-NEXT: ldr w16, [x16{{.*}}]
|
||||
# CHECK-NEXT: br x16
|
||||
# CHECK-NEXT: [[#FOO]]: adrp x16
|
||||
# CHECK-NEXT: ldr w16, [x16{{.*}}]
|
||||
# CHECK-NEXT: br x16
|
||||
|
||||
# CHECK-LABEL: Contents of (__TEXT,__stub_helper) section
|
||||
# CHECK-NEXT: [[#%x,HELPER_HEADER:]]: adrp x17
|
||||
# CHECK-NEXT: add x17, x17
|
||||
# CHECK-NEXT: stp x16, x17, [sp, #-16]!
|
||||
# CHECK-NEXT: adrp x16
|
||||
# CHECK-NEXT: ldr w16, [x16]
|
||||
# CHECK-NEXT: br x16
|
||||
# CHECK-NEXT: ldr w16, 0x[[#%x,BAR_BIND_OFF_ADDR:]]
|
||||
# CHECK-NEXT: b 0x[[#HELPER_HEADER]]
|
||||
# CHECK-NEXT: [[#BAR_BIND_OFF_ADDR]]: udf #0
|
||||
# CHECK-NEXT: ldr w16, 0x[[#%x,FOO_BIND_OFF_ADDR:]]
|
||||
# CHECK-NEXT: b 0x[[#HELPER_HEADER]]
|
||||
# CHECK-NEXT: [[#FOO_BIND_OFF_ADDR]]: udf #11
|
||||
|
||||
#--- foo.s
|
||||
.globl _foo
|
||||
_foo:
|
||||
|
||||
#--- bar.s
|
||||
.globl _bar
|
||||
_bar:
|
||||
|
||||
#--- test.s
|
||||
.text
|
||||
.globl _main
|
||||
|
||||
.p2align 2
|
||||
_main:
|
||||
bl _foo
|
||||
bl _bar
|
||||
ret
|
|
@ -1,19 +1,27 @@
|
|||
# REQUIRES: x86, aarch64
|
||||
# RUN: rm -rf %t && mkdir -p %t
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/x86_64-test.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/x86-64-test.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t/arm64-test.o
|
||||
# RUN: %lld -arch x86_64 -platform_version macos 10.5.0 11.0 -o %t/x86-64-executable %t/x86_64-test.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %s -o %t/arm64-32-test.o
|
||||
# RUN: %lld -arch x86_64 -platform_version macos 10.5.0 11.0 -o %t/x86-64-executable %t/x86-64-test.o
|
||||
# RUN: %lld -arch arm64 -o %t/arm64-executable %t/arm64-test.o
|
||||
# RUN: %lld -arch x86_64 -dylib -o %t/x86-64-dylib %t/x86_64-test.o
|
||||
# RUN: %lld-watchos -o %t/arm64-32-executable %t/arm64-32-test.o
|
||||
# RUN: %lld -arch x86_64 -dylib -o %t/x86-64-dylib %t/x86-64-test.o
|
||||
# RUN: %lld -arch arm64 -dylib -o %t/arm64-dylib %t/arm64-test.o
|
||||
# RUN: %lld-watchos -dylib -o %t/arm64-32-dylib %t/arm64-32-test.o
|
||||
|
||||
# RUN: llvm-objdump --macho --private-header %t/x86-64-executable | FileCheck %s -DCAPS=LIB64
|
||||
# RUN: llvm-objdump --macho --private-header %t/arm64-executable | FileCheck %s -DCAPS=0x00
|
||||
# RUN: llvm-objdump --macho --private-header %t/x86-64-dylib | FileCheck %s -DCAPS=0x00
|
||||
# RUN: llvm-objdump --macho --private-header %t/arm64-dylib | FileCheck %s -DCAPS=0x00
|
||||
# RUN: llvm-objdump --macho --private-header %t/x86-64-executable | FileCheck %s -DCPU=X86_64 -DCAPS=LIB64
|
||||
# RUN: llvm-objdump --macho --private-header %t/arm64-executable | FileCheck %s -DCPU=ARM64 -DCAPS=0x00
|
||||
# RUN: llvm-objdump --macho --private-header %t/arm64-32-executable | FileCheck %s --check-prefix=ARM64-32
|
||||
# RUN: llvm-objdump --macho --private-header %t/x86-64-dylib | FileCheck %s -DCPU=X86_64 -DCAPS=0x00
|
||||
# RUN: llvm-objdump --macho --private-header %t/arm64-dylib | FileCheck %s -DCPU=ARM64 -DCAPS=0x00
|
||||
# RUN: llvm-objdump --macho --private-header %t/arm64-32-dylib | FileCheck %s --check-prefix=ARM64-32
|
||||
|
||||
# CHECK: magic cputype cpusubtype caps filetype {{.*}} flags
|
||||
# CHECK-NEXT: MH_MAGIC_64 {{.*}} ALL [[CAPS]] {{.*}} NOUNDEFS {{.*}} TWOLEVEL
|
||||
# CHECK: magic cputype cpusubtype caps filetype {{.*}} flags
|
||||
# CHECK-NEXT: MH_MAGIC_64 [[CPU]] ALL [[CAPS]] {{.*}} NOUNDEFS {{.*}} TWOLEVEL
|
||||
|
||||
# ARM64-32: magic cputype cpusubtype caps filetype {{.*}} flags
|
||||
# ARM64-32-NEXT: MH_MAGIC ARM64_32 V8 0x00 {{.*}} NOUNDEFS {{.*}} TWOLEVEL
|
||||
|
||||
.globl _main
|
||||
_main:
|
||||
|
|
|
@ -2,12 +2,20 @@
|
|||
|
||||
import os
|
||||
|
||||
# We specify the most commonly-used arch and platform version in our tests here
|
||||
# Tests which need different settings can just append to this, as only the last
|
||||
# value will be used.
|
||||
# We specify the most commonly-used archs and platform versions in our tests
|
||||
# here. Tests which need different settings can just append to this, as only
|
||||
# the last value will be used.
|
||||
#
|
||||
# Note however that this does not apply to `-syslibroot`: each instance of that
|
||||
# flag will append to the set of library roots.
|
||||
# flag will append to the set of library roots. As such, we define a separate
|
||||
# alias for each platform.
|
||||
|
||||
config.substitutions.append(('%lld-watchos',
|
||||
'ld64.lld -fatal_warnings -arch arm64_32 -platform_version watchos 7.0 8.0 -syslibroot ' +
|
||||
os.path.join(config.test_source_root, "MachO", "Inputs", "WatchOS.sdk")))
|
||||
|
||||
# Since most of our tests are written around x86_64, we give this platform the
|
||||
# shortest substitution of "%lld".
|
||||
lld = ('ld64.lld -arch x86_64 -platform_version macos 10.0 11.0 -syslibroot ' +
|
||||
os.path.join(config.test_source_root, "MachO", "Inputs", "MacOSX.sdk"))
|
||||
config.substitutions.append(('%lld', lld + ' -fatal_warnings'))
|
||||
|
|
|
@ -1,20 +1,28 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: rm -rf %t
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
|
||||
# RUN: %lld -o %t %t.o
|
||||
# RUN: llvm-readobj --macho-segment %t > %t.out
|
||||
# RUN: echo "Total file size" >> %t.out
|
||||
# RUN: wc -c %t >> %t.out
|
||||
# RUN: FileCheck %s < %t.out
|
||||
# REQUIRES: x86, aarch64
|
||||
# RUN: rm -rf %t; mkdir -p %t
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/x86_64.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %s -o %t/arm64-32.o
|
||||
# RUN: %lld -o %t/x86_64 %t/x86_64.o
|
||||
# RUN: %lld-watchos -o %t/arm64_32 %t/arm64-32.o
|
||||
|
||||
# RUN: llvm-readobj --macho-segment %t/x86_64 > %t/x86_64.out
|
||||
# RUN: echo "Total file size" >> %t/x86_64.out
|
||||
# RUN: wc -c %t/x86_64 >> %t/x86_64.out
|
||||
# RUN: FileCheck %s -DSUFFIX=_64 -DPAGEZERO_SIZE=0x100000000 -DTEXT_ADDR=0x100000000 < %t/x86_64.out
|
||||
|
||||
# RUN: llvm-readobj --macho-segment %t/arm64_32 > %t/arm64-32.out
|
||||
# RUN: echo "Total file size" >> %t/arm64-32.out
|
||||
# RUN: wc -c %t/arm64_32 >> %t/arm64-32.out
|
||||
# RUN: FileCheck %s -DSUFFIX= -DPAGEZERO_SIZE=0x1000 -DTEXT_ADDR=0x4000 < %t/arm64-32.out
|
||||
|
||||
## These two segments must always be present at the start of an executable.
|
||||
# CHECK-NOT: Segment {
|
||||
# CHECK: Segment {
|
||||
# CHECK-NEXT: Cmd: LC_SEGMENT_64
|
||||
# CHECK-NEXT: Cmd: LC_SEGMENT[[SUFFIX]]{{$}}
|
||||
# CHECK-NEXT: Name: __PAGEZERO
|
||||
# CHECK-NEXT: Size: 72
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: vmaddr: 0x0
|
||||
# CHECK-NEXT: vmsize: 0x100000000
|
||||
# CHECK-NEXT: vmsize: [[PAGEZERO_SIZE]]
|
||||
# CHECK-NEXT: fileoff: 0
|
||||
# CHECK-NEXT: filesize: 0
|
||||
## The kernel won't execute a binary with the wrong protections for __PAGEZERO.
|
||||
|
@ -24,10 +32,10 @@
|
|||
# CHECK-NEXT: flags: 0x0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Segment {
|
||||
# CHECK-NEXT: Cmd: LC_SEGMENT_64
|
||||
# CHECK-NEXT: Cmd: LC_SEGMENT[[SUFFIX]]{{$}}
|
||||
# CHECK-NEXT: Name: __TEXT
|
||||
# CHECK-NEXT: Size: 152
|
||||
# CHECK-NEXT: vmaddr: 0x100000000
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: vmaddr: [[TEXT_ADDR]]
|
||||
# CHECK-NEXT: vmsize:
|
||||
## dyld3 assumes that the __TEXT segment starts from the file header
|
||||
# CHECK-NEXT: fileoff: 0
|
||||
|
@ -39,7 +47,7 @@
|
|||
# CHECK-NEXT: }
|
||||
|
||||
## Check that we handle max-length names correctly.
|
||||
# CHECK: Cmd: LC_SEGMENT_64
|
||||
# CHECK: Cmd: LC_SEGMENT[[SUFFIX]]{{$}}
|
||||
# CHECK-NEXT: Name: maxlen_16ch_name
|
||||
|
||||
## This segment must always be present at the end of an executable, and cover
|
||||
|
@ -52,7 +60,7 @@
|
|||
# CHECK-NEXT: filesize: [[#%u, LINKEDIT_SIZE:]]
|
||||
# CHECK-NEXT: maxprot: r--
|
||||
# CHECK-NEXT: initprot: r--
|
||||
# CHECK-NOT: Cmd: LC_SEGMENT_64
|
||||
# CHECK-NOT: Cmd: LC_SEGMENT[[SUFFIX]]{{$}}
|
||||
|
||||
# CHECK-LABEL: Total file size
|
||||
# CHECK-NEXT: [[#%u, LINKEDIT_OFF + LINKEDIT_SIZE]]
|
||||
|
@ -60,7 +68,6 @@
|
|||
.text
|
||||
.global _main
|
||||
_main:
|
||||
mov $0, %rax
|
||||
ret
|
||||
|
||||
.section maxlen_16ch_name,foo
|
||||
|
|
Loading…
Reference in New Issue