[lld] 77e204c - [lld-macho][arm64] implement -objc_stubs_small (#78665)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 23 07:31:38 PST 2024
Author: Kyungwoo Lee
Date: 2024-01-23T07:31:34-08:00
New Revision: 77e204c7b04f1f516db9a1dd5602e4a853bb0d1c
URL: https://github.com/llvm/llvm-project/commit/77e204c7b04f1f516db9a1dd5602e4a853bb0d1c
DIFF: https://github.com/llvm/llvm-project/commit/77e204c7b04f1f516db9a1dd5602e4a853bb0d1c.diff
LOG: [lld-macho][arm64] implement -objc_stubs_small (#78665)
This patch implements `-objc_stubs_small` targeting arm64, aiming to
align with ld64's behavior.
1. `-objc_stubs_fast`: As previously implemented, this always uses the
Global Offset Table (GOT) to invoke `objc_msgSend`. The alignment of the
objc stub is 32 bytes.
2. `-objc_stubs_small`: This behavior depends on whether `objc_msgSend`
is defined. If it is, it directly jumps to `objc_msgSend`. If not, it
creates another stub to indirectly jump to `objc_msgSend`, minimizing
the size. The alignment of the objc stub in this case is 4 bytes.
Added:
lld/test/MachO/arm64-objc-stubs-dyn.s
Modified:
lld/MachO/Arch/ARM64.cpp
lld/MachO/Arch/ARM64Common.h
lld/MachO/Arch/ARM64_32.cpp
lld/MachO/Arch/X86_64.cpp
lld/MachO/Driver.cpp
lld/MachO/SyntheticSections.cpp
lld/MachO/SyntheticSections.h
lld/MachO/Target.h
lld/test/MachO/arm64-objc-stubs.s
lld/test/MachO/x86-64-objc-stubs.s
Removed:
################################################################################
diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp
index e3781763c6102b5..2741df9c3070ebd 100644
--- a/lld/MachO/Arch/ARM64.cpp
+++ b/lld/MachO/Arch/ARM64.cpp
@@ -37,9 +37,9 @@ struct ARM64 : ARM64Common {
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;
+ uint64_t &stubOffset, uint64_t selrefsVA,
+ uint64_t selectorIndex,
+ Symbol *objcMsgSend) const override;
void populateThunk(InputSection *thunk, Symbol *funcSym) override;
void applyOptimizationHints(uint8_t *, const ObjFile &) const override;
};
@@ -117,13 +117,42 @@ static constexpr uint32_t objcStubsFastCode[] = {
0xd4200020, // brk #0x1
};
+static constexpr uint32_t objcStubsSmallCode[] = {
+ 0x90000001, // adrp x1, __objc_selrefs at page
+ 0xf9400021, // ldr x1, [x1, @selector("foo")@pageoff]
+ 0x14000000, // b _objc_msgSend
+};
+
void ARM64::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 {
- ::writeObjCMsgSendStub<LP64>(buf, objcStubsFastCode, sym, stubsAddr,
- stubOffset, selrefsVA, selectorIndex, gotAddr,
- msgSendIndex);
+ uint64_t &stubOffset, uint64_t selrefsVA,
+ uint64_t selectorIndex,
+ Symbol *objcMsgSend) const {
+ uint64_t objcMsgSendAddr;
+ uint64_t objcStubSize;
+ uint64_t objcMsgSendIndex;
+
+ if (config->objcStubsMode == ObjCStubsMode::fast) {
+ objcStubSize = target->objcStubsFastSize;
+ objcMsgSendAddr = in.got->addr;
+ objcMsgSendIndex = objcMsgSend->gotIndex;
+ ::writeObjCMsgSendFastStub<LP64>(buf, objcStubsFastCode, sym, stubsAddr,
+ stubOffset, selrefsVA, selectorIndex,
+ objcMsgSendAddr, objcMsgSendIndex);
+ } else {
+ assert(config->objcStubsMode == ObjCStubsMode::small);
+ objcStubSize = target->objcStubsSmallSize;
+ if (auto *d = dyn_cast<Defined>(objcMsgSend)) {
+ objcMsgSendAddr = d->getVA();
+ objcMsgSendIndex = 0;
+ } else {
+ objcMsgSendAddr = in.stubs->addr;
+ objcMsgSendIndex = objcMsgSend->stubsIndex;
+ }
+ ::writeObjCMsgSendSmallStub<LP64>(buf, objcStubsSmallCode, sym, stubsAddr,
+ stubOffset, selrefsVA, selectorIndex,
+ objcMsgSendAddr, objcMsgSendIndex);
+ }
+ stubOffset += objcStubSize;
}
// A thunk is the relaxed variation of stubCode. We don't need the
@@ -157,7 +186,9 @@ ARM64::ARM64() : ARM64Common(LP64()) {
thunkSize = sizeof(thunkCode);
objcStubsFastSize = sizeof(objcStubsFastCode);
- objcStubsAlignment = 32;
+ objcStubsFastAlignment = 32;
+ objcStubsSmallSize = sizeof(objcStubsSmallCode);
+ objcStubsSmallAlignment = 4;
// Branch immediate is two's complement 26 bits, which is implicitly
// multiplied by 4 (since all functions are 4-aligned: The branch range
diff --git a/lld/MachO/Arch/ARM64Common.h b/lld/MachO/Arch/ARM64Common.h
index 9cfccb6cec76142..b038b6200f4d571 100644
--- a/lld/MachO/Arch/ARM64Common.h
+++ b/lld/MachO/Arch/ARM64Common.h
@@ -154,10 +154,10 @@ inline void writeStubHelperEntry(uint8_t *buf8,
template <class LP>
inline void
-writeObjCMsgSendStub(uint8_t *buf, const uint32_t objcStubsFastCode[8],
- Symbol *sym, uint64_t stubsAddr, uint64_t stubOffset,
- uint64_t selrefsVA, uint64_t selectorIndex,
- uint64_t gotAddr, uint64_t msgSendIndex) {
+writeObjCMsgSendFastStub(uint8_t *buf, const uint32_t objcStubsFastCode[8],
+ Symbol *sym, uint64_t stubsAddr, uint64_t stubOffset,
+ uint64_t selrefsVA, uint64_t selectorIndex,
+ uint64_t gotAddr, uint64_t msgSendIndex) {
SymbolDiagnostic d = {sym, sym->getName()};
auto *buf32 = reinterpret_cast<uint32_t *>(buf);
@@ -180,6 +180,30 @@ writeObjCMsgSendStub(uint8_t *buf, const uint32_t objcStubsFastCode[8],
buf32[7] = objcStubsFastCode[7];
}
+template <class LP>
+inline void
+writeObjCMsgSendSmallStub(uint8_t *buf, const uint32_t objcStubsSmallCode[3],
+ Symbol *sym, uint64_t stubsAddr, uint64_t stubOffset,
+ uint64_t selrefsVA, uint64_t selectorIndex,
+ uint64_t msgSendAddr, uint64_t msgSendIndex) {
+ SymbolDiagnostic d = {sym, sym->getName()};
+ auto *buf32 = reinterpret_cast<uint32_t *>(buf);
+
+ auto pcPageBits = [stubsAddr, stubOffset](int i) {
+ return pageBits(stubsAddr + stubOffset + i * sizeof(uint32_t));
+ };
+
+ uint64_t selectorOffset = selectorIndex * LP::wordSize;
+ encodePage21(&buf32[0], d, objcStubsSmallCode[0],
+ pageBits(selrefsVA + selectorOffset) - pcPageBits(0));
+ encodePageOff12(&buf32[1], d, objcStubsSmallCode[1],
+ selrefsVA + selectorOffset);
+ uint64_t msgSendStubVA = msgSendAddr + msgSendIndex * target->stubSize;
+ uint64_t pcVA = stubsAddr + stubOffset + 2 * sizeof(uint32_t);
+ encodeBranch26(&buf32[2], {nullptr, "objc_msgSend stub"},
+ objcStubsSmallCode[2], msgSendStubVA - pcVA);
+}
+
} // namespace lld::macho
#endif
diff --git a/lld/MachO/Arch/ARM64_32.cpp b/lld/MachO/Arch/ARM64_32.cpp
index c6bb6ee6c1c7d21..16c7cbee9ba7e55 100644
--- a/lld/MachO/Arch/ARM64_32.cpp
+++ b/lld/MachO/Arch/ARM64_32.cpp
@@ -34,9 +34,9 @@ struct ARM64_32 : ARM64Common {
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;
+ uint64_t &stubOffset, uint64_t selrefsVA,
+ uint64_t selectorIndex,
+ Symbol *objcMsgSend) const override;
};
} // namespace
@@ -100,10 +100,9 @@ void ARM64_32::writeStubHelperEntry(uint8_t *buf8, const Symbol &sym,
}
void ARM64_32::writeObjCMsgSendStub(uint8_t *buf, Symbol *sym,
- uint64_t stubsAddr, uint64_t stubOffset,
+ uint64_t stubsAddr, uint64_t &stubOffset,
uint64_t selrefsVA, uint64_t selectorIndex,
- uint64_t gotAddr,
- uint64_t msgSendIndex) const {
+ Symbol *objcMsgSend) const {
fatal("TODO: implement this");
}
diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index a0d4e1a28a14a26..9e8e1d01e493aca 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -38,9 +38,9 @@ struct X86_64 : TargetInfo {
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;
+ uint64_t &stubOffset, uint64_t selrefsVA,
+ uint64_t selectorIndex,
+ Symbol *objcMsgSend) const override;
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
uint64_t getPageSize() const override { return 4 * 1024; }
@@ -182,16 +182,20 @@ static constexpr uint8_t objcStubsFastCode[] = {
};
void X86_64::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 {
+ uint64_t &stubOffset, uint64_t selrefsVA,
+ uint64_t selectorIndex,
+ Symbol *objcMsgSend) const {
+ uint64_t objcMsgSendAddr = in.got->addr;
+ uint64_t objcMsgSendIndex = objcMsgSend->gotIndex;
+
memcpy(buf, objcStubsFastCode, sizeof(objcStubsFastCode));
SymbolDiagnostic d = {sym, sym->getName()};
uint64_t stubAddr = stubsAddr + stubOffset;
writeRipRelative(d, buf, stubAddr, 7,
selrefsVA + selectorIndex * LP64::wordSize);
writeRipRelative(d, buf, stubAddr, 0xd,
- gotAddr + msgSendIndex * LP64::wordSize);
+ objcMsgSendAddr + objcMsgSendIndex * LP64::wordSize);
+ stubOffset += target->objcStubsFastSize;
}
void X86_64::relaxGotLoad(uint8_t *loc, uint8_t type) const {
@@ -214,7 +218,7 @@ X86_64::X86_64() : TargetInfo(LP64()) {
stubHelperEntrySize = sizeof(stubHelperEntry);
objcStubsFastSize = sizeof(objcStubsFastCode);
- objcStubsAlignment = 1;
+ objcStubsFastAlignment = 1;
relocAttrs = {relocAttrsArray.data(), relocAttrsArray.size()};
}
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 7ac3f51cec103f6..411fbcfcf233eb8 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -827,9 +827,13 @@ static ObjCStubsMode getObjCStubsMode(const ArgList &args) {
if (!arg)
return ObjCStubsMode::fast;
- if (arg->getOption().getID() == OPT_objc_stubs_small)
- warn("-objc_stubs_small is not yet implemented, defaulting to "
- "-objc_stubs_fast");
+ if (arg->getOption().getID() == OPT_objc_stubs_small) {
+ if (is_contained({AK_arm64e, AK_arm64}, config->arch()))
+ return ObjCStubsMode::small;
+ else
+ warn("-objc_stubs_small is not yet implemented, defaulting to "
+ "-objc_stubs_fast");
+ }
return ObjCStubsMode::fast;
}
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index e123dcb6803c1e2..53220ad04b842c1 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -809,7 +809,9 @@ void StubHelperSection::setUp() {
ObjCStubsSection::ObjCStubsSection()
: SyntheticSection(segment_names::text, section_names::objcStubs) {
flags = S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
- align = target->objcStubsAlignment;
+ align = config->objcStubsMode == ObjCStubsMode::fast
+ ? target->objcStubsFastAlignment
+ : target->objcStubsSmallAlignment;
}
void ObjCStubsSection::addEntry(Symbol *sym) {
@@ -817,10 +819,14 @@ void ObjCStubsSection::addEntry(Symbol *sym) {
StringRef methname = sym->getName().drop_front(symbolPrefix.size());
offsets.push_back(
in.objcMethnameSection->getStringOffset(methname).outSecOff);
+
+ auto stubSize = config->objcStubsMode == ObjCStubsMode::fast
+ ? target->objcStubsFastSize
+ : target->objcStubsSmallSize;
Defined *newSym = replaceSymbol<Defined>(
sym, sym->getName(), nullptr, isec,
- /*value=*/symbols.size() * target->objcStubsFastSize,
- /*size=*/target->objcStubsFastSize,
+ /*value=*/symbols.size() * stubSize,
+ /*size=*/stubSize,
/*isWeakDef=*/false, /*isExternal=*/true, /*isPrivateExtern=*/true,
/*includeInSymtab=*/true, /*isReferencedDynamically=*/false,
/*noDeadStrip=*/false);
@@ -828,12 +834,24 @@ void ObjCStubsSection::addEntry(Symbol *sym) {
}
void ObjCStubsSection::setUp() {
- Symbol *objcMsgSend = symtab->addUndefined("_objc_msgSend", /*file=*/nullptr,
- /*isWeakRef=*/false);
+ objcMsgSend = symtab->addUndefined("_objc_msgSend", /*file=*/nullptr,
+ /*isWeakRef=*/false);
+ if (auto *undefined = dyn_cast<Undefined>(objcMsgSend))
+ treatUndefinedSymbol(*undefined,
+ "lazy binding (normally in libobjc.dylib)");
objcMsgSend->used = true;
- in.got->addEntry(objcMsgSend);
- assert(objcMsgSend->isInGot());
- objcMsgSendGotIndex = objcMsgSend->gotIndex;
+ if (config->objcStubsMode == ObjCStubsMode::fast) {
+ in.got->addEntry(objcMsgSend);
+ assert(objcMsgSend->isInGot());
+ } else {
+ assert(config->objcStubsMode == ObjCStubsMode::small);
+ // In line with ld64's behavior, when objc_msgSend is a direct symbol,
+ // we directly reference it.
+ // In other cases, typically when binding in libobjc.dylib,
+ // we generate a stub to invoke objc_msgSend.
+ if (!isa<Defined>(objcMsgSend))
+ in.stubs->addEntry(objcMsgSend);
+ }
size_t size = offsets.size() * target->wordSize;
uint8_t *selrefsData = bAlloc().Allocate<uint8_t>(size);
@@ -863,7 +881,10 @@ void ObjCStubsSection::setUp() {
}
uint64_t ObjCStubsSection::getSize() const {
- return target->objcStubsFastSize * symbols.size();
+ auto stubSize = config->objcStubsMode == ObjCStubsMode::fast
+ ? target->objcStubsFastSize
+ : target->objcStubsSmallSize;
+ return stubSize * symbols.size();
}
void ObjCStubsSection::writeTo(uint8_t *buf) const {
@@ -875,8 +896,7 @@ void ObjCStubsSection::writeTo(uint8_t *buf) const {
Defined *sym = symbols[i];
target->writeObjCMsgSendStub(buf + stubOffset, sym, in.objcStubs->addr,
stubOffset, in.objcSelrefs->getVA(), i,
- in.got->addr, objcMsgSendGotIndex);
- stubOffset += target->objcStubsFastSize;
+ objcMsgSend);
}
}
diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index e9d564f3c836158..5fb7b6e09e8e63e 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -336,7 +336,7 @@ class ObjCStubsSection final : public SyntheticSection {
private:
std::vector<Defined *> symbols;
std::vector<uint32_t> offsets;
- int objcMsgSendGotIndex = 0;
+ Symbol *objcMsgSend = nullptr;
};
// Note that this section may also be targeted by non-lazy bindings. In
diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h
index bc7e09d394d24fb..b07967d0abb7c50 100644
--- a/lld/MachO/Target.h
+++ b/lld/MachO/Target.h
@@ -70,10 +70,9 @@ class TargetInfo {
uint64_t entryAddr) const = 0;
virtual void writeObjCMsgSendStub(uint8_t *buf, Symbol *sym,
- uint64_t stubsAddr, uint64_t stubOffset,
+ uint64_t stubsAddr, uint64_t &stubOffset,
uint64_t selrefsVA, uint64_t selectorIndex,
- uint64_t gotAddr,
- uint64_t msgSendIndex) const = 0;
+ Symbol *objcMsgSend) const = 0;
// Symbols may be referenced via either the GOT or the stubs section,
// depending on the relocation type. prepareSymbolRelocation() will set up the
@@ -121,7 +120,9 @@ class TargetInfo {
size_t stubHelperHeaderSize;
size_t stubHelperEntrySize;
size_t objcStubsFastSize;
- size_t objcStubsAlignment;
+ size_t objcStubsSmallSize;
+ size_t objcStubsFastAlignment;
+ size_t objcStubsSmallAlignment;
uint8_t p2WordSize;
size_t wordSize;
diff --git a/lld/test/MachO/arm64-objc-stubs-dyn.s b/lld/test/MachO/arm64-objc-stubs-dyn.s
new file mode 100644
index 000000000000000..9358fc5b31c2ba5
--- /dev/null
+++ b/lld/test/MachO/arm64-objc-stubs-dyn.s
@@ -0,0 +1,76 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
+# RUN: %lld -arch arm64 -lSystem -U _objc_msgSend -o %t.out %t.o
+# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
+# RUN: %lld -arch arm64 -lSystem -U _objc_msgSend -o %t.out %t.o -dead_strip
+# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
+# RUN: %lld -arch arm64 -lSystem -U _objc_msgSend -o %t.out %t.o -objc_stubs_fast
+# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
+# RUN: %lld -arch arm64 -lSystem -U _objc_msgSend -o %t.out %t.o -objc_stubs_small
+# RUN: llvm-otool -vs __TEXT __stubs %t.out | FileCheck %s --check-prefix=STUB
+# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s --check-prefix=SMALL
+
+# Unlike arm64-objc-stubs.s, in this test, _objc_msgSend is not defined,
+# which usually binds with libobjc.dylib.
+# 1. -objc_stubs_fast: No change as it uses GOT.
+# 2. -objc_stubs_small: Create a (shared) stub to invoke _objc_msgSend, to minimize the size.
+
+# CHECK: Contents of (__TEXT,__objc_stubs) section
+
+# CHECK-NEXT: _objc_msgSend$foo:
+# CHECK-NEXT: adrp x1, 8 ; 0x100008000
+# CHECK-NEXT: ldr x1, [x1, #0x10]
+# CHECK-NEXT: adrp x16, 4 ; 0x100004000
+# CHECK-NEXT: ldr x16, [x16]
+# CHECK-NEXT: br x16
+# CHECK-NEXT: brk #0x1
+# CHECK-NEXT: brk #0x1
+# CHECK-NEXT: brk #0x1
+
+# CHECK-NEXT: _objc_msgSend$length:
+# CHECK-NEXT: adrp x1, 8 ; 0x100008000
+# CHECK-NEXT: ldr x1, [x1, #0x18]
+# CHECK-NEXT: adrp x16, 4 ; 0x100004000
+# CHECK-NEXT: ldr x16, [x16]
+# CHECK-NEXT: br x16
+# CHECK-NEXT: brk #0x1
+# CHECK-NEXT: brk #0x1
+# CHECK-NEXT: brk #0x1
+
+# CHECK-EMPTY:
+
+# STUB: Contents of (__TEXT,__stubs) section
+# STUB-NEXT: adrp x16, 8 ; 0x100008000
+# STUB-NEXT: ldr x16, [x16]
+# STUB-NEXT: br x16
+
+# SMALL: Contents of (__TEXT,__objc_stubs) section
+# SMALL-NEXT: _objc_msgSend$foo:
+# SMALL-NEXT: adrp x1, 8 ; 0x100008000
+# SMALL-NEXT: ldr x1, [x1, #0x18]
+# SMALL-NEXT: b
+# SMALL-NEXT: _objc_msgSend$length:
+# SMALL-NEXT: adrp x1, 8 ; 0x100008000
+# SMALL-NEXT: ldr x1, [x1, #0x20]
+# SMALL-NEXT: b
+
+.section __TEXT,__objc_methname,cstring_literals
+lselref1:
+ .asciz "foo"
+lselref2:
+ .asciz "bar"
+
+.section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
+.p2align 3
+.quad lselref1
+.quad lselref2
+
+.text
+
+.globl _main
+_main:
+ bl _objc_msgSend$length
+ bl _objc_msgSend$foo
+ bl _objc_msgSend$foo
+ ret
diff --git a/lld/test/MachO/arm64-objc-stubs.s b/lld/test/MachO/arm64-objc-stubs.s
index feba40ac36d8405..1b8ebff92430045 100644
--- a/lld/test/MachO/arm64-objc-stubs.s
+++ b/lld/test/MachO/arm64-objc-stubs.s
@@ -7,10 +7,10 @@
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_fast
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
-# RUN: %no-fatal-warnings-lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small 2>&1 | FileCheck %s --check-prefix=WARNING
-# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
-
-# WARNING: warning: -objc_stubs_small is not yet implemented, defaulting to -objc_stubs_fast
+# RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=FASTALIGN
+# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small
+# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s --check-prefix=SMALL
+# RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=SMALLALIGN
# CHECK: Contents of (__TEXT,__objc_stubs) section
@@ -36,6 +36,30 @@
# CHECK-EMPTY:
+# FASTALIGN: sectname __objc_stubs
+# FASTALIGN-NEXT: segname __TEXT
+# FASTALIGN-NEXT: addr
+# FASTALIGN-NEXT: size
+# FASTALIGN-NEXT: offset
+# FASTALIGN-NEXT: align 2^5 (32)
+
+# SMALL: _objc_msgSend$foo:
+# SMALL-NEXT: adrp x1, 4 ; 0x100004000
+# SMALL-NEXT: ldr x1, [x1, #0x10]
+# SMALL-NEXT: b
+
+# SMALL-NEXT: _objc_msgSend$length:
+# SMALL-NEXT: adrp x1, 4 ; 0x100004000
+# SMALL-NEXT: ldr x1, [x1, #0x18]
+# SMALL-NEXT: b
+
+# SMALLALIGN: sectname __objc_stubs
+# SMALLALIGN-NEXT: segname __TEXT
+# SMALLALIGN-NEXT: addr
+# SMALLALIGN-NEXT: size
+# SMALLALIGN-NEXT: offset
+# SMALLALIGN-NEXT: align 2^2 (4)
+
.section __TEXT,__objc_methname,cstring_literals
lselref1:
.asciz "foo"
diff --git a/lld/test/MachO/x86-64-objc-stubs.s b/lld/test/MachO/x86-64-objc-stubs.s
index 5e8b9fb165f25a1..2dd8d559377156b 100644
--- a/lld/test/MachO/x86-64-objc-stubs.s
+++ b/lld/test/MachO/x86-64-objc-stubs.s
@@ -6,6 +6,9 @@
# RUN: llvm-otool -vs __DATA __objc_selrefs %t.out >> %t.txt
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out >> %t.txt
# RUN: FileCheck %s < %t.txt
+# RUN: %no-fatal-warnings-lld -arch x86_64 -lSystem -o %t.out %t.o -objc_stubs_small 2>&1 | FileCheck %s --check-prefix=WARNING
+
+# WARNING: warning: -objc_stubs_small is not yet implemented, defaulting to -objc_stubs_fast
# CHECK: Sections:
# CHECK: __got {{[0-9a-f]*}} [[#%x, GOTSTART:]] DATA
More information about the llvm-commits
mailing list