[lld-macho] Remove partially supported 32-bit ARM arch
We never really supported 32-bit ARM arch entirely, and partial support was added for very specific features. Regardless, it fails to even link the most basic applications that at this point, it might be better to move this arch as unsupported. Given that Apple will be moving towards arm64 long term, I don't see any reason for anyone to invest time in supporting this either, and for those who still need it should use apple's ld64 linker. Fixes #62691 Reviewed By: #lld-macho, int3 Differential Revision: https://reviews.llvm.org/D150544
This commit is contained in:
parent
ac73c48e09
commit
ed59b8a11c
@ -1,214 +0,0 @@
|
|||||||
//===- ARM.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 "InputFiles.h"
|
|
||||||
#include "Symbols.h"
|
|
||||||
#include "SyntheticSections.h"
|
|
||||||
#include "Target.h"
|
|
||||||
|
|
||||||
#include "lld/Common/ErrorHandler.h"
|
|
||||||
#include "llvm/ADT/Bitfields.h"
|
|
||||||
#include "llvm/BinaryFormat/MachO.h"
|
|
||||||
#include "llvm/Support/Endian.h"
|
|
||||||
|
|
||||||
using namespace llvm;
|
|
||||||
using namespace llvm::MachO;
|
|
||||||
using namespace llvm::support::endian;
|
|
||||||
using namespace lld;
|
|
||||||
using namespace lld::macho;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct ARM : TargetInfo {
|
|
||||||
ARM(uint32_t cpuSubtype);
|
|
||||||
|
|
||||||
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 &, uint64_t) const override;
|
|
||||||
void writeStubHelperHeader(uint8_t *buf) const override;
|
|
||||||
void writeStubHelperEntry(uint8_t *buf, const Symbol &,
|
|
||||||
uint64_t entryAddr) const override;
|
|
||||||
|
|
||||||
void writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
|
|
||||||
uint64_t stubOffset, uint64_t selrefsVA,
|
|
||||||
uint64_t selectorIndex, uint64_t gotAddr,
|
|
||||||
uint64_t msgSendIndex) const override;
|
|
||||||
|
|
||||||
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
|
|
||||||
uint64_t getPageSize() const override { return 4 * 1024; }
|
|
||||||
|
|
||||||
void handleDtraceReloc(const Symbol *sym, const Reloc &r,
|
|
||||||
uint8_t *loc) const override;
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
static constexpr std::array<RelocAttrs, 10> relocAttrsArray{{
|
|
||||||
#define B(x) RelocAttrBits::x
|
|
||||||
{"VANILLA", /* FIXME populate this */ B(_0)},
|
|
||||||
{"PAIR", /* FIXME populate this */ B(_0)},
|
|
||||||
{"SECTDIFF", /* FIXME populate this */ B(_0)},
|
|
||||||
{"LOCAL_SECTDIFF", /* FIXME populate this */ B(_0)},
|
|
||||||
{"PB_LA_PTR", /* FIXME populate this */ B(_0)},
|
|
||||||
{"BR24", B(PCREL) | B(LOCAL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
|
|
||||||
{"BR22", B(PCREL) | B(LOCAL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
|
|
||||||
{"32BIT_BRANCH", /* FIXME populate this */ B(_0)},
|
|
||||||
{"HALF", /* FIXME populate this */ B(_0)},
|
|
||||||
{"HALF_SECTDIFF", /* FIXME populate this */ B(_0)},
|
|
||||||
#undef B
|
|
||||||
}};
|
|
||||||
|
|
||||||
int64_t ARM::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
|
|
||||||
relocation_info rel) const {
|
|
||||||
// FIXME: implement this
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <int N> using BitfieldFlag = Bitfield::Element<bool, N, 1>;
|
|
||||||
|
|
||||||
// ARM BL encoding:
|
|
||||||
//
|
|
||||||
// 30 28 24 0
|
|
||||||
// +---------+---------+----------------------------------------------+
|
|
||||||
// | cond | 1 0 1 1 | imm24 |
|
|
||||||
// +---------+---------+----------------------------------------------+
|
|
||||||
//
|
|
||||||
// `cond` here varies depending on whether we have bleq, blne, etc.
|
|
||||||
// `imm24` encodes a 26-bit pcrel offset -- last 2 bits are zero as ARM
|
|
||||||
// functions are 4-byte-aligned.
|
|
||||||
//
|
|
||||||
// ARM BLX encoding:
|
|
||||||
//
|
|
||||||
// 30 28 24 0
|
|
||||||
// +---------+---------+----------------------------------------------+
|
|
||||||
// | 1 1 1 1 | 1 0 1 H | imm24 |
|
|
||||||
// +---------+---------+----------------------------------------------+
|
|
||||||
//
|
|
||||||
// Since Thumb functions are 2-byte-aligned, we need one extra bit to encode
|
|
||||||
// the offset -- that is the H bit.
|
|
||||||
//
|
|
||||||
// BLX is always unconditional, so while we can convert directly from BLX to BL,
|
|
||||||
// we need to insert a shim if a BL's target is a Thumb function.
|
|
||||||
//
|
|
||||||
// Helper aliases for decoding BL / BLX:
|
|
||||||
using Cond = Bitfield::Element<uint32_t, 28, 4>;
|
|
||||||
using Imm24 = Bitfield::Element<int32_t, 0, 24>;
|
|
||||||
|
|
||||||
void ARM::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
|
|
||||||
uint64_t pc) const {
|
|
||||||
switch (r.type) {
|
|
||||||
case ARM_RELOC_BR24: {
|
|
||||||
uint32_t base = read32le(loc);
|
|
||||||
bool isBlx = Bitfield::get<Cond>(base) == 0xf;
|
|
||||||
const Symbol *sym = r.referent.get<Symbol *>();
|
|
||||||
int32_t offset = value - (pc + 8);
|
|
||||||
|
|
||||||
if (auto *defined = dyn_cast<Defined>(sym)) {
|
|
||||||
if (!isBlx && defined->thumb) {
|
|
||||||
error("TODO: implement interworking shim");
|
|
||||||
return;
|
|
||||||
} else if (isBlx && !defined->thumb) {
|
|
||||||
Bitfield::set<Cond>(base, 0xe); // unconditional BL
|
|
||||||
Bitfield::set<BitfieldFlag<24>>(base, true);
|
|
||||||
isBlx = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error("TODO: Implement ARM_RELOC_BR24 for dylib symbols");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBlx) {
|
|
||||||
assert((0x1 & value) == 0);
|
|
||||||
Bitfield::set<Imm24>(base, offset >> 2);
|
|
||||||
Bitfield::set<BitfieldFlag<24>>(base, (offset >> 1) & 1); // H bit
|
|
||||||
} else {
|
|
||||||
assert((0x3 & value) == 0);
|
|
||||||
Bitfield::set<Imm24>(base, offset >> 2);
|
|
||||||
}
|
|
||||||
write32le(loc, base);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fatal("unhandled relocation type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM::writeStub(uint8_t *buf, const Symbol &sym, uint64_t) const {
|
|
||||||
fatal("TODO: implement this");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM::writeStubHelperHeader(uint8_t *buf) const {
|
|
||||||
fatal("TODO: implement this");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM::writeStubHelperEntry(uint8_t *buf, const Symbol &sym,
|
|
||||||
uint64_t entryAddr) const {
|
|
||||||
fatal("TODO: implement this");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM::writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
|
|
||||||
uint64_t stubOffset, uint64_t selrefsVA,
|
|
||||||
uint64_t selectorIndex, uint64_t gotAddr,
|
|
||||||
uint64_t msgSendIndex) const {
|
|
||||||
fatal("TODO: implement this");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM::relaxGotLoad(uint8_t *loc, uint8_t type) const {
|
|
||||||
fatal("TODO: implement this");
|
|
||||||
}
|
|
||||||
|
|
||||||
ARM::ARM(uint32_t cpuSubtype) : TargetInfo(ILP32()) {
|
|
||||||
cpuType = CPU_TYPE_ARM;
|
|
||||||
this->cpuSubtype = cpuSubtype;
|
|
||||||
|
|
||||||
stubSize = 0 /* FIXME */;
|
|
||||||
stubHelperHeaderSize = 0 /* FIXME */;
|
|
||||||
stubHelperEntrySize = 0 /* FIXME */;
|
|
||||||
|
|
||||||
relocAttrs = {relocAttrsArray.data(), relocAttrsArray.size()};
|
|
||||||
}
|
|
||||||
|
|
||||||
TargetInfo *macho::createARMTargetInfo(uint32_t cpuSubtype) {
|
|
||||||
static ARM t(cpuSubtype);
|
|
||||||
return &t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM::handleDtraceReloc(const Symbol *sym, const Reloc &r,
|
|
||||||
uint8_t *loc) const {
|
|
||||||
if (config->outputType == MH_OBJECT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (r.type) {
|
|
||||||
case ARM_RELOC_BR24:
|
|
||||||
if (sym->getName().startswith("___dtrace_probe")) {
|
|
||||||
// change call site to a NOP
|
|
||||||
write32le(loc, 0xE1A00000);
|
|
||||||
} else if (sym->getName().startswith("___dtrace_isenabled")) {
|
|
||||||
// change call site to 'eor r0, r0, r0'
|
|
||||||
write32le(loc, 0xE0200000);
|
|
||||||
} else {
|
|
||||||
error("Unrecognized dtrace symbol prefix: " + toString(*sym));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ARM_THUMB_RELOC_BR22:
|
|
||||||
if (sym->getName().startswith("___dtrace_probe")) {
|
|
||||||
// change 32-bit blx call site to two thumb NOPs
|
|
||||||
write32le(loc, 0x46C046C0);
|
|
||||||
} else if (sym->getName().startswith("___dtrace_isenabled")) {
|
|
||||||
// change 32-bit blx call site to 'nop', 'eor r0, r0'
|
|
||||||
write32le(loc, 0x46C04040);
|
|
||||||
} else {
|
|
||||||
error("Unrecognized dtrace symbol prefix: " + toString(*sym));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
llvm_unreachable("Unsupported dtrace relocation type for ARM");
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,6 @@ add_public_tablegen_target(MachOOptionsTableGen)
|
|||||||
include_directories(${LLVM_MAIN_SRC_DIR}/../libunwind/include)
|
include_directories(${LLVM_MAIN_SRC_DIR}/../libunwind/include)
|
||||||
|
|
||||||
add_lld_library(lldMachO
|
add_lld_library(lldMachO
|
||||||
Arch/ARM.cpp
|
|
||||||
Arch/ARM64.cpp
|
Arch/ARM64.cpp
|
||||||
Arch/ARM64Common.cpp
|
Arch/ARM64Common.cpp
|
||||||
Arch/ARM64_32.cpp
|
Arch/ARM64_32.cpp
|
||||||
|
@ -335,15 +335,14 @@ void TextOutputSection::finalize() {
|
|||||||
r.referent = thunkInfo.sym = symtab->addDefined(
|
r.referent = thunkInfo.sym = symtab->addDefined(
|
||||||
thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0, thunkSize,
|
thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0, thunkSize,
|
||||||
/*isWeakDef=*/false, /*isPrivateExtern=*/true,
|
/*isWeakDef=*/false, /*isPrivateExtern=*/true,
|
||||||
/*isThumb=*/false, /*isReferencedDynamically=*/false,
|
/*isReferencedDynamically=*/false, /*noDeadStrip=*/false,
|
||||||
/*noDeadStrip=*/false, /*isWeakDefCanBeHidden=*/false);
|
/*isWeakDefCanBeHidden=*/false);
|
||||||
} else {
|
} else {
|
||||||
r.referent = thunkInfo.sym = make<Defined>(
|
r.referent = thunkInfo.sym = make<Defined>(
|
||||||
thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0, thunkSize,
|
thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0, thunkSize,
|
||||||
/*isWeakDef=*/false, /*isExternal=*/false, /*isPrivateExtern=*/true,
|
/*isWeakDef=*/false, /*isExternal=*/false, /*isPrivateExtern=*/true,
|
||||||
/*includeInSymtab=*/true, /*isThumb=*/false,
|
/*includeInSymtab=*/true, /*isReferencedDynamically=*/false,
|
||||||
/*isReferencedDynamically=*/false, /*noDeadStrip=*/false,
|
/*noDeadStrip=*/false, /*isWeakDefCanBeHidden=*/false);
|
||||||
/*isWeakDefCanBeHidden=*/false);
|
|
||||||
}
|
}
|
||||||
thunkInfo.sym->used = true;
|
thunkInfo.sym->used = true;
|
||||||
target->populateThunk(thunkInfo.isec, funcSym);
|
target->populateThunk(thunkInfo.isec, funcSym);
|
||||||
|
@ -596,8 +596,8 @@ static void replaceCommonSymbols() {
|
|||||||
replaceSymbol<Defined>(
|
replaceSymbol<Defined>(
|
||||||
sym, sym->getName(), common->getFile(), isec, /*value=*/0, common->size,
|
sym, sym->getName(), common->getFile(), isec, /*value=*/0, common->size,
|
||||||
/*isWeakDef=*/false, /*isExternal=*/true, common->privateExtern,
|
/*isWeakDef=*/false, /*isExternal=*/true, common->privateExtern,
|
||||||
/*includeInSymtab=*/true, /*isThumb=*/false,
|
/*includeInSymtab=*/true, /*isReferencedDynamically=*/false,
|
||||||
/*isReferencedDynamically=*/false, /*noDeadStrip=*/false);
|
/*noDeadStrip=*/false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,8 +752,6 @@ static TargetInfo *createTargetInfo(InputArgList &args) {
|
|||||||
return createARM64TargetInfo();
|
return createARM64TargetInfo();
|
||||||
case CPU_TYPE_ARM64_32:
|
case CPU_TYPE_ARM64_32:
|
||||||
return createARM64_32TargetInfo();
|
return createARM64_32TargetInfo();
|
||||||
case CPU_TYPE_ARM:
|
|
||||||
return createARMTargetInfo(cpuSubtype);
|
|
||||||
default:
|
default:
|
||||||
error("missing or unsupported -arch " + archName);
|
error("missing or unsupported -arch " + archName);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -655,6 +655,8 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
|
|||||||
bool isWeakDefCanBeHidden =
|
bool isWeakDefCanBeHidden =
|
||||||
(sym.n_desc & (N_WEAK_DEF | N_WEAK_REF)) == (N_WEAK_DEF | N_WEAK_REF);
|
(sym.n_desc & (N_WEAK_DEF | N_WEAK_REF)) == (N_WEAK_DEF | N_WEAK_REF);
|
||||||
|
|
||||||
|
assert(!(sym.n_desc & N_ARM_THUMB_DEF) && "ARM32 arch is not supported");
|
||||||
|
|
||||||
if (sym.n_type & N_EXT) {
|
if (sym.n_type & N_EXT) {
|
||||||
// -load_hidden makes us treat global symbols as linkage unit scoped.
|
// -load_hidden makes us treat global symbols as linkage unit scoped.
|
||||||
// Duplicates are reported but the symbol does not go in the export trie.
|
// Duplicates are reported but the symbol does not go in the export trie.
|
||||||
@ -697,16 +699,14 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
|
|||||||
isPrivateExtern = true;
|
isPrivateExtern = true;
|
||||||
return symtab->addDefined(
|
return symtab->addDefined(
|
||||||
name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
|
name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
|
||||||
isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF,
|
isPrivateExtern, sym.n_desc & REFERENCED_DYNAMICALLY,
|
||||||
sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP,
|
sym.n_desc & N_NO_DEAD_STRIP, isWeakDefCanBeHidden);
|
||||||
isWeakDefCanBeHidden);
|
|
||||||
}
|
}
|
||||||
bool includeInSymtab = !isPrivateLabel(name) && !isEhFrameSection(isec);
|
bool includeInSymtab = !isPrivateLabel(name) && !isEhFrameSection(isec);
|
||||||
return make<Defined>(
|
return make<Defined>(
|
||||||
name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
|
name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
|
||||||
/*isExternal=*/false, /*isPrivateExtern=*/false, includeInSymtab,
|
/*isExternal=*/false, /*isPrivateExtern=*/false, includeInSymtab,
|
||||||
sym.n_desc & N_ARM_THUMB_DEF, sym.n_desc & REFERENCED_DYNAMICALLY,
|
sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP);
|
||||||
sym.n_desc & N_NO_DEAD_STRIP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute symbols are defined symbols that do not have an associated
|
// Absolute symbols are defined symbols that do not have an associated
|
||||||
@ -714,18 +714,20 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
|
|||||||
template <class NList>
|
template <class NList>
|
||||||
static macho::Symbol *createAbsolute(const NList &sym, InputFile *file,
|
static macho::Symbol *createAbsolute(const NList &sym, InputFile *file,
|
||||||
StringRef name, bool forceHidden) {
|
StringRef name, bool forceHidden) {
|
||||||
|
assert(!(sym.n_desc & N_ARM_THUMB_DEF) && "ARM32 arch is not supported");
|
||||||
|
|
||||||
if (sym.n_type & N_EXT) {
|
if (sym.n_type & N_EXT) {
|
||||||
bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
|
bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
|
||||||
return symtab->addDefined(
|
return symtab->addDefined(name, file, nullptr, sym.n_value, /*size=*/0,
|
||||||
name, file, nullptr, sym.n_value, /*size=*/0,
|
/*isWeakDef=*/false, isPrivateExtern,
|
||||||
/*isWeakDef=*/false, isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF,
|
/*isReferencedDynamically=*/false,
|
||||||
/*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP,
|
sym.n_desc & N_NO_DEAD_STRIP,
|
||||||
/*isWeakDefCanBeHidden=*/false);
|
/*isWeakDefCanBeHidden=*/false);
|
||||||
}
|
}
|
||||||
return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0,
|
return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0,
|
||||||
/*isWeakDef=*/false,
|
/*isWeakDef=*/false,
|
||||||
/*isExternal=*/false, /*isPrivateExtern=*/false,
|
/*isExternal=*/false, /*isPrivateExtern=*/false,
|
||||||
/*includeInSymtab=*/true, sym.n_desc & N_ARM_THUMB_DEF,
|
/*includeInSymtab=*/true,
|
||||||
/*isReferencedDynamically=*/false,
|
/*isReferencedDynamically=*/false,
|
||||||
sym.n_desc & N_NO_DEAD_STRIP);
|
sym.n_desc & N_NO_DEAD_STRIP);
|
||||||
}
|
}
|
||||||
@ -1366,7 +1368,7 @@ void ObjFile::registerEhFrames(Section &ehFrameSection) {
|
|||||||
make<Defined>("EH_Frame", isec->getFile(), isec, /*value=*/0,
|
make<Defined>("EH_Frame", isec->getFile(), isec, /*value=*/0,
|
||||||
isec->getSize(), /*isWeakDef=*/false, /*isExternal=*/false,
|
isec->getSize(), /*isWeakDef=*/false, /*isExternal=*/false,
|
||||||
/*isPrivateExtern=*/false, /*includeInSymtab=*/false,
|
/*isPrivateExtern=*/false, /*includeInSymtab=*/false,
|
||||||
/*isThumb=*/false, /*isReferencedDynamically=*/false,
|
/*isReferencedDynamically=*/false,
|
||||||
/*noDeadStrip=*/false);
|
/*noDeadStrip=*/false);
|
||||||
else if (isec->symbols[0]->value != 0)
|
else if (isec->symbols[0]->value != 0)
|
||||||
fatal("found symbol at unexpected offset in __eh_frame");
|
fatal("found symbol at unexpected offset in __eh_frame");
|
||||||
@ -2184,7 +2186,6 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
|
|||||||
|
|
||||||
return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0,
|
return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0,
|
||||||
/*size=*/0, objSym.isWeak(), isPrivateExtern,
|
/*size=*/0, objSym.isWeak(), isPrivateExtern,
|
||||||
/*isThumb=*/false,
|
|
||||||
/*isReferencedDynamically=*/false,
|
/*isReferencedDynamically=*/false,
|
||||||
/*noDeadStrip=*/false,
|
/*noDeadStrip=*/false,
|
||||||
/*isWeakDefCanBeHidden=*/false);
|
/*isWeakDefCanBeHidden=*/false);
|
||||||
|
@ -96,7 +96,7 @@ static void transplantSymbolsAtOffset(InputSection *fromIsec,
|
|||||||
Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
|
Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
|
||||||
InputSection *isec, uint64_t value,
|
InputSection *isec, uint64_t value,
|
||||||
uint64_t size, bool isWeakDef,
|
uint64_t size, bool isWeakDef,
|
||||||
bool isPrivateExtern, bool isThumb,
|
bool isPrivateExtern,
|
||||||
bool isReferencedDynamically, bool noDeadStrip,
|
bool isReferencedDynamically, bool noDeadStrip,
|
||||||
bool isWeakDefCanBeHidden) {
|
bool isWeakDefCanBeHidden) {
|
||||||
bool overridesWeakDef = false;
|
bool overridesWeakDef = false;
|
||||||
@ -166,9 +166,8 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
|
|||||||
!isPrivateExtern;
|
!isPrivateExtern;
|
||||||
Defined *defined = replaceSymbol<Defined>(
|
Defined *defined = replaceSymbol<Defined>(
|
||||||
s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
|
s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
|
||||||
isPrivateExtern, /*includeInSymtab=*/true, isThumb,
|
isPrivateExtern, /*includeInSymtab=*/true, isReferencedDynamically,
|
||||||
isReferencedDynamically, noDeadStrip, overridesWeakDef,
|
noDeadStrip, overridesWeakDef, isWeakDefCanBeHidden, interposable);
|
||||||
isWeakDefCanBeHidden, interposable);
|
|
||||||
return defined;
|
return defined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +175,7 @@ Defined *SymbolTable::aliasDefined(Defined *src, StringRef target,
|
|||||||
InputFile *newFile, bool makePrivateExtern) {
|
InputFile *newFile, bool makePrivateExtern) {
|
||||||
bool isPrivateExtern = makePrivateExtern || src->privateExtern;
|
bool isPrivateExtern = makePrivateExtern || src->privateExtern;
|
||||||
return addDefined(target, newFile, src->isec, src->value, src->size,
|
return addDefined(target, newFile, src->isec, src->value, src->size,
|
||||||
src->isWeakDef(), isPrivateExtern, src->thumb,
|
src->isWeakDef(), isPrivateExtern,
|
||||||
src->referencedDynamically, src->noDeadStrip,
|
src->referencedDynamically, src->noDeadStrip,
|
||||||
src->weakDefCanBeHidden);
|
src->weakDefCanBeHidden);
|
||||||
}
|
}
|
||||||
@ -295,9 +294,8 @@ Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
|
|||||||
bool includeInSymtab,
|
bool includeInSymtab,
|
||||||
bool referencedDynamically) {
|
bool referencedDynamically) {
|
||||||
assert(!isec || !isec->getFile()); // See makeSyntheticInputSection().
|
assert(!isec || !isec->getFile()); // See makeSyntheticInputSection().
|
||||||
Defined *s =
|
Defined *s = addDefined(name, /*file=*/nullptr, isec, value, /*size=*/0,
|
||||||
addDefined(name, /*file=*/nullptr, isec, value, /*size=*/0,
|
/*isWeakDef=*/false, isPrivateExtern,
|
||||||
/*isWeakDef=*/false, isPrivateExtern, /*isThumb=*/false,
|
|
||||||
referencedDynamically, /*noDeadStrip=*/false,
|
referencedDynamically, /*noDeadStrip=*/false,
|
||||||
/*isWeakDefCanBeHidden=*/false);
|
/*isWeakDefCanBeHidden=*/false);
|
||||||
s->includeInSymtab = includeInSymtab;
|
s->includeInSymtab = includeInSymtab;
|
||||||
|
@ -38,9 +38,8 @@ class SymbolTable {
|
|||||||
public:
|
public:
|
||||||
Defined *addDefined(StringRef name, InputFile *, InputSection *,
|
Defined *addDefined(StringRef name, InputFile *, InputSection *,
|
||||||
uint64_t value, uint64_t size, bool isWeakDef,
|
uint64_t value, uint64_t size, bool isWeakDef,
|
||||||
bool isPrivateExtern, bool isThumb,
|
bool isPrivateExtern, bool isReferencedDynamically,
|
||||||
bool isReferencedDynamically, bool noDeadStrip,
|
bool noDeadStrip, bool isWeakDefCanBeHidden);
|
||||||
bool isWeakDefCanBeHidden);
|
|
||||||
|
|
||||||
Defined *aliasDefined(Defined *src, StringRef target, InputFile *newFile,
|
Defined *aliasDefined(Defined *src, StringRef target, InputFile *newFile,
|
||||||
bool makePrivateExtern = false);
|
bool makePrivateExtern = false);
|
||||||
|
@ -54,13 +54,13 @@ uint64_t Symbol::getTlvVA() const { return in.tlvPointers->getVA(gotIndex); }
|
|||||||
|
|
||||||
Defined::Defined(StringRefZ name, InputFile *file, InputSection *isec,
|
Defined::Defined(StringRefZ name, InputFile *file, InputSection *isec,
|
||||||
uint64_t value, uint64_t size, bool isWeakDef, bool isExternal,
|
uint64_t value, uint64_t size, bool isWeakDef, bool isExternal,
|
||||||
bool isPrivateExtern, bool includeInSymtab, bool isThumb,
|
bool isPrivateExtern, bool includeInSymtab,
|
||||||
bool isReferencedDynamically, bool noDeadStrip,
|
bool isReferencedDynamically, bool noDeadStrip,
|
||||||
bool canOverrideWeakDef, bool isWeakDefCanBeHidden,
|
bool canOverrideWeakDef, bool isWeakDefCanBeHidden,
|
||||||
bool interposable)
|
bool interposable)
|
||||||
: Symbol(DefinedKind, name, file), overridesWeakDef(canOverrideWeakDef),
|
: Symbol(DefinedKind, name, file), overridesWeakDef(canOverrideWeakDef),
|
||||||
privateExtern(isPrivateExtern), includeInSymtab(includeInSymtab),
|
privateExtern(isPrivateExtern), includeInSymtab(includeInSymtab),
|
||||||
wasIdenticalCodeFolded(false), thumb(isThumb),
|
wasIdenticalCodeFolded(false),
|
||||||
referencedDynamically(isReferencedDynamically), noDeadStrip(noDeadStrip),
|
referencedDynamically(isReferencedDynamically), noDeadStrip(noDeadStrip),
|
||||||
interposable(interposable), weakDefCanBeHidden(isWeakDefCanBeHidden),
|
interposable(interposable), weakDefCanBeHidden(isWeakDefCanBeHidden),
|
||||||
weakDef(isWeakDef), external(isExternal), isec(isec), value(value),
|
weakDef(isWeakDef), external(isExternal), isec(isec), value(value),
|
||||||
|
@ -118,9 +118,9 @@ class Defined : public Symbol {
|
|||||||
public:
|
public:
|
||||||
Defined(StringRefZ name, InputFile *file, InputSection *isec, uint64_t value,
|
Defined(StringRefZ name, InputFile *file, InputSection *isec, uint64_t value,
|
||||||
uint64_t size, bool isWeakDef, bool isExternal, bool isPrivateExtern,
|
uint64_t size, bool isWeakDef, bool isExternal, bool isPrivateExtern,
|
||||||
bool includeInSymtab, bool isThumb, bool isReferencedDynamically,
|
bool includeInSymtab, bool isReferencedDynamically, bool noDeadStrip,
|
||||||
bool noDeadStrip, bool canOverrideWeakDef = false,
|
bool canOverrideWeakDef = false, bool isWeakDefCanBeHidden = false,
|
||||||
bool isWeakDefCanBeHidden = false, bool interposable = false);
|
bool interposable = false);
|
||||||
|
|
||||||
bool isWeakDef() const override { return weakDef; }
|
bool isWeakDef() const override { return weakDef; }
|
||||||
bool isExternalWeakDef() const {
|
bool isExternalWeakDef() const {
|
||||||
@ -154,8 +154,6 @@ public:
|
|||||||
bool includeInSymtab : 1;
|
bool includeInSymtab : 1;
|
||||||
// Whether this symbol was folded into a different symbol during ICF.
|
// Whether this symbol was folded into a different symbol during ICF.
|
||||||
bool wasIdenticalCodeFolded : 1;
|
bool wasIdenticalCodeFolded : 1;
|
||||||
// Only relevant when compiling for Thumb-supporting arm32 archs.
|
|
||||||
bool thumb : 1;
|
|
||||||
// Symbols marked referencedDynamically won't be removed from the output's
|
// Symbols marked referencedDynamically won't be removed from the output's
|
||||||
// symbol table by tools like strip. In theory, this could be set on arbitrary
|
// symbol table by tools like strip. In theory, this could be set on arbitrary
|
||||||
// symbols in input object files. In practice, it's used solely for the
|
// symbols in input object files. In practice, it's used solely for the
|
||||||
|
@ -808,7 +808,7 @@ void StubHelperSection::setUp() {
|
|||||||
/*isWeakDef=*/false,
|
/*isWeakDef=*/false,
|
||||||
/*isExternal=*/false, /*isPrivateExtern=*/false,
|
/*isExternal=*/false, /*isPrivateExtern=*/false,
|
||||||
/*includeInSymtab=*/true,
|
/*includeInSymtab=*/true,
|
||||||
/*isThumb=*/false, /*isReferencedDynamically=*/false,
|
/*isReferencedDynamically=*/false,
|
||||||
/*noDeadStrip=*/false);
|
/*noDeadStrip=*/false);
|
||||||
dyldPrivate->used = true;
|
dyldPrivate->used = true;
|
||||||
}
|
}
|
||||||
@ -829,8 +829,8 @@ void ObjCStubsSection::addEntry(Symbol *sym) {
|
|||||||
/*value=*/symbols.size() * target->objcStubsFastSize,
|
/*value=*/symbols.size() * target->objcStubsFastSize,
|
||||||
/*size=*/target->objcStubsFastSize,
|
/*size=*/target->objcStubsFastSize,
|
||||||
/*isWeakDef=*/false, /*isExternal=*/true, /*isPrivateExtern=*/true,
|
/*isWeakDef=*/false, /*isExternal=*/true, /*isPrivateExtern=*/true,
|
||||||
/*includeInSymtab=*/true, /*isThumb=*/false,
|
/*includeInSymtab=*/true, /*isReferencedDynamically=*/false,
|
||||||
/*isReferencedDynamically=*/false, /*noDeadStrip=*/false);
|
/*noDeadStrip=*/false);
|
||||||
symbols.push_back(newSym);
|
symbols.push_back(newSym);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1064,8 +1064,6 @@ void FunctionStartsSection::finalizeContents() {
|
|||||||
if (!defined->isec || !isCodeSection(defined->isec) ||
|
if (!defined->isec || !isCodeSection(defined->isec) ||
|
||||||
!defined->isLive())
|
!defined->isLive())
|
||||||
continue;
|
continue;
|
||||||
// TODO: Add support for thumbs, in that case
|
|
||||||
// the lowest bit of nextAddr needs to be set to 1.
|
|
||||||
addrs.push_back(defined->getVA());
|
addrs.push_back(defined->getVA());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1347,7 +1345,6 @@ template <class LP> void SymtabSectionImpl<LP>::writeTo(uint8_t *buf) const {
|
|||||||
// For the N_SECT symbol type, n_value is the address of the symbol
|
// For the N_SECT symbol type, n_value is the address of the symbol
|
||||||
nList->n_value = defined->getVA();
|
nList->n_value = defined->getVA();
|
||||||
}
|
}
|
||||||
nList->n_desc |= defined->thumb ? N_ARM_THUMB_DEF : 0;
|
|
||||||
nList->n_desc |= defined->isExternalWeakDef() ? N_WEAK_DEF : 0;
|
nList->n_desc |= defined->isExternalWeakDef() ? N_WEAK_DEF : 0;
|
||||||
nList->n_desc |=
|
nList->n_desc |=
|
||||||
defined->referencedDynamically ? REFERENCED_DYNAMICALLY : 0;
|
defined->referencedDynamically ? REFERENCED_DYNAMICALLY : 0;
|
||||||
|
@ -145,7 +145,6 @@ public:
|
|||||||
TargetInfo *createX86_64TargetInfo();
|
TargetInfo *createX86_64TargetInfo();
|
||||||
TargetInfo *createARM64TargetInfo();
|
TargetInfo *createARM64TargetInfo();
|
||||||
TargetInfo *createARM64_32TargetInfo();
|
TargetInfo *createARM64_32TargetInfo();
|
||||||
TargetInfo *createARMTargetInfo(uint32_t cpuSubtype);
|
|
||||||
|
|
||||||
struct LP64 {
|
struct LP64 {
|
||||||
using mach_header = llvm::MachO::mach_header_64;
|
using mach_header = llvm::MachO::mach_header_64;
|
||||||
|
@ -307,7 +307,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
|
|||||||
r.addend, /*size=*/0, /*isWeakDef=*/false,
|
r.addend, /*size=*/0, /*isWeakDef=*/false,
|
||||||
/*isExternal=*/false, /*isPrivateExtern=*/false,
|
/*isExternal=*/false, /*isPrivateExtern=*/false,
|
||||||
/*includeInSymtab=*/true,
|
/*includeInSymtab=*/true,
|
||||||
/*isThumb=*/false, /*isReferencedDynamically=*/false,
|
/*isReferencedDynamically=*/false,
|
||||||
/*noDeadStrip=*/false);
|
/*noDeadStrip=*/false);
|
||||||
s->used = true;
|
s->used = true;
|
||||||
in.got->addEntry(s);
|
in.got->addEntry(s);
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
# REQUIRES: arm
|
|
||||||
# RUN: llvm-mc -filetype=obj -triple=armv7-apple-watchos %s -o %t.o
|
|
||||||
# RUN: %lld-watchos -dylib -arch armv7 -lSystem -o %t %t.o
|
|
||||||
# RUN: llvm-objdump --macho -d %t | FileCheck %s
|
|
||||||
|
|
||||||
# CHECK: _arm:
|
|
||||||
# CHECK-NEXT: blx _thumb_1
|
|
||||||
# CHECK-NEXT: blx _thumb_2
|
|
||||||
# CHECK-NEXT: bl _arm
|
|
||||||
# CHECK-NEXT: bl _arm
|
|
||||||
|
|
||||||
.globl _arm, _thumb_1, _thumb_2
|
|
||||||
.syntax unified
|
|
||||||
.thumb_func _thumb_1
|
|
||||||
.thumb_func _thumb_2
|
|
||||||
|
|
||||||
.p2align 2
|
|
||||||
|
|
||||||
.code 16
|
|
||||||
## These two thumb functions are exactly 2 bytes apart in order to test that we
|
|
||||||
## set the H bit correctly in the BLX instruction.
|
|
||||||
_thumb_1:
|
|
||||||
nop
|
|
||||||
|
|
||||||
_thumb_2:
|
|
||||||
nop
|
|
||||||
|
|
||||||
.code 32
|
|
||||||
_arm:
|
|
||||||
blx _thumb_1
|
|
||||||
blx _thumb_2
|
|
||||||
bl _arm
|
|
||||||
blx _arm
|
|
@ -1,47 +0,0 @@
|
|||||||
# REQUIRES: arm
|
|
||||||
# RUN: rm -rf %t; split-file %s %t
|
|
||||||
|
|
||||||
# TODO: Replace %no-lsystem-lld with %lld
|
|
||||||
|
|
||||||
# RUN: llvm-mc -filetype=obj -triple=armv4t-apple-darwin %t/armv4t-dtrace.s -o %t/armv4t-dtrace.o
|
|
||||||
# RUN: %no-lsystem-lld -arch armv4t -o %t/armv4t-dtrace %t/armv4t-dtrace.o
|
|
||||||
|
|
||||||
## If references of dtrace symbols are handled by lld, their relocation should be replaced with the following instructions
|
|
||||||
# RUN: llvm-objdump --macho -D %t/armv4t-dtrace | FileCheck %s --check-prefix=CHECK-armv4t
|
|
||||||
|
|
||||||
# CHECK-armv4t: 00 00 20 e0 eor r0, r0, r0
|
|
||||||
|
|
||||||
# CHECK-armv4t: 00 00 a0 e1 mov r0, r0
|
|
||||||
|
|
||||||
# RUN: llvm-mc -filetype=obj -triple=thumbv7-apple-darwin %t/armv7-dtrace.s -o %t/armv7-dtrace.o
|
|
||||||
# RUN: %no-lsystem-lld -arch armv7 -o %t/armv7-dtrace %t/armv7-dtrace.o
|
|
||||||
|
|
||||||
## If references of dtrace symbols are handled by lld, their relocation should be replaced with the following instructions
|
|
||||||
# RUN: llvm-objdump --macho -D %t/armv7-dtrace | FileCheck %s --check-prefix=CHECK-armv7
|
|
||||||
|
|
||||||
# CHECK-armv7: 40 40 eors r0, r0
|
|
||||||
# CHECK-armv7-NEXT: c0 46 mov r8, r8
|
|
||||||
|
|
||||||
# CHECK-armv7: c0 46 mov r8, r8
|
|
||||||
# CHECK-armv7-NEXT: c0 46 mov r8, r8
|
|
||||||
|
|
||||||
;--- armv4t-dtrace.s
|
|
||||||
.globl _main
|
|
||||||
_main:
|
|
||||||
bl ___dtrace_isenabled$Foo$added$v1
|
|
||||||
.reference ___dtrace_typedefs$Foo$v2
|
|
||||||
bl ___dtrace_probe$Foo$added$v1$696e74
|
|
||||||
.reference ___dtrace_stability$Foo$v1$1_1_0_1_1_0_1_1_0_1_1_0_1_1_0
|
|
||||||
|
|
||||||
.subsections_via_symbols
|
|
||||||
|
|
||||||
;--- armv7-dtrace.s
|
|
||||||
.globl _main
|
|
||||||
.thumb_func _main
|
|
||||||
_main:
|
|
||||||
bl ___dtrace_isenabled$Foo$added$v1
|
|
||||||
.reference ___dtrace_typedefs$Foo$v2
|
|
||||||
bl ___dtrace_probe$Foo$added$v1$696e74
|
|
||||||
.reference ___dtrace_stability$Foo$v1$1_1_0_1_1_0_1_1_0_1_1_0_1_1_0
|
|
||||||
|
|
||||||
.subsections_via_symbols
|
|
@ -1,15 +1,13 @@
|
|||||||
# REQUIRES: x86, aarch64, arm
|
# REQUIRES: x86, aarch64
|
||||||
# RUN: rm -rf %t && mkdir -p %t
|
# 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: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t/arm64-test.o
|
||||||
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %s -o %t/arm64-32-test.o
|
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %s -o %t/arm64-32-test.o
|
||||||
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %s -o %t/arm64-32-test.o
|
# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %s -o %t/arm64-32-test.o
|
||||||
# RUN: llvm-mc -filetype=obj -triple=armv7-apple-watchos %s -o %t/arm-test.o
|
|
||||||
|
|
||||||
# RUN: %lld -lSystem -arch x86_64 -o %t/x86-64-executable %t/x86-64-test.o
|
# RUN: %lld -lSystem -arch x86_64 -o %t/x86-64-executable %t/x86-64-test.o
|
||||||
# RUN: %lld -lSystem -arch arm64 -o %t/arm64-executable %t/arm64-test.o
|
# RUN: %lld -lSystem -arch arm64 -o %t/arm64-executable %t/arm64-test.o
|
||||||
# RUN: %lld-watchos -lSystem -o %t/arm64-32-executable %t/arm64-32-test.o
|
# RUN: %lld-watchos -lSystem -o %t/arm64-32-executable %t/arm64-32-test.o
|
||||||
# RUN: %lld-watchos -lSystem -arch armv7 -o %t/arm-executable %t/arm-test.o
|
|
||||||
|
|
||||||
# RUN: %lld -arch x86_64 -dylib -o %t/x86-64-dylib %t/x86-64-test.o
|
# RUN: %lld -arch x86_64 -dylib -o %t/x86-64-dylib %t/x86-64-test.o
|
||||||
|
|
||||||
@ -17,7 +15,6 @@
|
|||||||
# RUN: llvm-objdump --macho --private-header %t/x86-64-executable | FileCheck %s --check-prefix=EXEC -DCPU=X86_64 -DSUBTYPE=ALL -DCAPS=LIB64
|
# RUN: llvm-objdump --macho --private-header %t/x86-64-executable | FileCheck %s --check-prefix=EXEC -DCPU=X86_64 -DSUBTYPE=ALL -DCAPS=LIB64
|
||||||
# RUN: llvm-objdump --macho --private-header %t/arm64-executable | FileCheck %s --check-prefix=EXEC -DCPU=ARM64 -DSUBTYPE=ALL -DCAPS=0x00
|
# RUN: llvm-objdump --macho --private-header %t/arm64-executable | FileCheck %s --check-prefix=EXEC -DCPU=ARM64 -DSUBTYPE=ALL -DCAPS=0x00
|
||||||
# RUN: llvm-objdump --macho --private-header %t/arm64-32-executable | FileCheck %s --check-prefix=EXEC -DCPU=ARM64_32 -DSUBTYPE=V8 -DCAPS=0x00
|
# RUN: llvm-objdump --macho --private-header %t/arm64-32-executable | FileCheck %s --check-prefix=EXEC -DCPU=ARM64_32 -DSUBTYPE=V8 -DCAPS=0x00
|
||||||
# RUN: llvm-objdump --macho --private-header %t/arm-executable | FileCheck %s --check-prefix=EXEC -DCPU=ARM -DSUBTYPE=V7 -DCAPS=0x00
|
|
||||||
|
|
||||||
# RUN: llvm-objdump --macho --private-header %t/x86-64-dylib | FileCheck %s --check-prefix=DYLIB -DCPU=X86_64 -DSUBTYPE=ALL -DCAPS=0x00
|
# RUN: llvm-objdump --macho --private-header %t/x86-64-dylib | FileCheck %s --check-prefix=DYLIB -DCPU=X86_64 -DSUBTYPE=ALL -DCAPS=0x00
|
||||||
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
# REQUIRES: arm
|
|
||||||
# RUN: rm -rf %t; split-file %s %t
|
|
||||||
# RUN: llvm-mc -filetype=obj -triple=armv7-apple-watchos %t/thumb-foo.s -o %t/thumb-foo.o
|
|
||||||
# RUN: llvm-mc -filetype=obj -triple=armv7-apple-watchos %t/arm-foo.s -o %t/arm-foo.o
|
|
||||||
# RUN: %lld-watchos -arch armv7 -dylib %t/arm-foo.o %t/thumb-foo.o -o %t/arm-foo
|
|
||||||
# RUN: %lld-watchos -arch armv7 -dylib %t/thumb-foo.o %t/arm-foo.o -o %t/thumb-foo
|
|
||||||
# RUN: llvm-nm -m %t/arm-foo | FileCheck %s --check-prefix=ARM
|
|
||||||
# RUN: llvm-nm -m %t/thumb-foo | FileCheck %s --check-prefix=THUMB
|
|
||||||
|
|
||||||
## Check that we preserve the .thumb_def flag if we pick the thumb definition of
|
|
||||||
## _foo.
|
|
||||||
# ARM: (__TEXT,arm) weak external _foo
|
|
||||||
# THUMB: (__TEXT,thumb) weak external [Thumb] _foo
|
|
||||||
|
|
||||||
#--- thumb-foo.s
|
|
||||||
.section __TEXT,thumb
|
|
||||||
.globl _foo
|
|
||||||
.weak_definition _foo
|
|
||||||
.thumb_func _foo
|
|
||||||
.p2align 2
|
|
||||||
_foo:
|
|
||||||
|
|
||||||
#--- arm-foo.s
|
|
||||||
.section __TEXT,arm
|
|
||||||
.globl _foo
|
|
||||||
.weak_definition _foo
|
|
||||||
.p2align 2
|
|
||||||
_foo:
|
|
Loading…
x
Reference in New Issue
Block a user