Skip to content

Commit

Permalink
Address Feedback #1
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex B committed Mar 25, 2024
1 parent d120f34 commit 5c4a8da
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 47 deletions.
57 changes: 29 additions & 28 deletions lld/MachO/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1979,7 +1979,7 @@ void InitOffsetsSection::setUp() {
ObjCMethListSection::ObjCMethListSection()
: SyntheticSection(segment_names::text, section_names::objcMethList) {
flags = S_ATTR_NO_DEAD_STRIP;
align = m_align;
align = relativeOffsetSize;
}

// Go through all input method lists and ensure that we have selrefs for all
Expand All @@ -1993,7 +1993,7 @@ void ObjCMethListSection::setUp() {
uint32_t structSize = structSizeAndFlags & m_structSizeMask;

// Method name is immediately after header
uint32_t methodNameOff = m_methodListHeaderSize;
uint32_t methodNameOff = methodListHeaderSize;

// Loop through all methods, and ensure a selref for each of them exists.
while (methodNameOff < isec->data.size()) {
Expand All @@ -2016,19 +2016,19 @@ void ObjCMethListSection::setUp() {
// Calculate section size and final offsets for where InputSection's need to be
// written.
void ObjCMethListSection::finalize() {
// m_size will be the total size of the __objc_methlist section
m_size = 0;
// sectionSize will be the total size of the __objc_methlist section
sectionSize = 0;
for (ConcatInputSection *isec : inputs) {
// We can also use m_size as write offset for isec
assert(m_size == alignToPowerOf2(m_size, m_align) &&
// We can also use sectionSize as write offset for isec
assert(sectionSize == alignToPowerOf2(sectionSize, relativeOffsetSize) &&
"expected __objc_methlist to be aligned by default with the "
"required section alignment");
isec->outSecOff = m_size;
isec->outSecOff = sectionSize;

isec->isFinal = true;
uint32_t relativeListSize =
methodListSizeToRelativeMethodListSize(isec->data.size());
m_size += relativeListSize;
computeRelativeMethodListSize(isec->data.size());
sectionSize += relativeListSize;

// If encoding the method list in relative offset format shrinks the size,
// then we also need to adjust symbol sizes to match the new size. Note that
Expand Down Expand Up @@ -2061,7 +2061,7 @@ void ObjCMethListSection::writeTo(uint8_t *bufStart) const {
uint32_t writtenSize = writeRelativeMethodList(isec, buf);
buf += writtenSize;
}
assert(buf - bufStart == m_size &&
assert(buf - bufStart == sectionSize &&
"Written size does not match expected section size");
}

Expand Down Expand Up @@ -2122,8 +2122,10 @@ void ObjCMethListSection::writeRelativeOffsetForIsec(
uint32_t delta = symVA - currentVA;
write32le(buf + outSecOff, delta);

// Move one pointer forward in the absolute method list
inSecOff += target->wordSize;
outSecOff += sizeof(uint32_t);
// Move one relative offset forward in the relative method list (32 bits)
outSecOff += relativeOffsetSize;
}

// Write a relative method list to buf, return the size of the written
Expand All @@ -2135,16 +2137,16 @@ ObjCMethListSection::writeRelativeMethodList(const ConcatInputSection *isec,
// value flag
uint32_t structSizeAndFlags = 0, structCount = 0;
readMethodListHeader(isec->data.data(), structSizeAndFlags, structCount);
structSizeAndFlags |= m_relMethodHeaderFlag;
structSizeAndFlags |= relMethodHeaderFlag;
writeMethodListHeader(buf, structSizeAndFlags, structCount);

assert(m_methodListHeaderSize +
(structCount * m_pointersPerStruct * target->wordSize) ==
assert(methodListHeaderSize +
(structCount * pointersPerStruct * target->wordSize) ==
isec->data.size() &&
"Invalid computed ObjC method list size");

uint32_t inSecOff = m_methodListHeaderSize;
uint32_t outSecOff = m_methodListHeaderSize;
uint32_t inSecOff = methodListHeaderSize;
uint32_t outSecOff = methodListHeaderSize;

// Go through the method list and encode input absolute pointers as relative
// offsets. writeRelativeOffsetForIsec will be incrementing inSecOff and
Expand All @@ -2162,27 +2164,26 @@ ObjCMethListSection::writeRelativeMethodList(const ConcatInputSection *isec,
assert(inSecOff == isec->data.size() &&
"Invalid actual ObjC method list size");
assert(
outSecOff == methodListSizeToRelativeMethodListSize(inSecOff) &&
outSecOff == computeRelativeMethodListSize(inSecOff) &&
"Mismatch between input & output size when writing relative method list");
return outSecOff;
}

// Given the size of an ObjC method list InputSection, return the size of the
// method list when encoded in relative offsets format. We can do this without
// decoding the actual data, as it can be directly infered from the size of the
// decoding the actual data, as it can be directly inferred from the size of the
// isec.
uint32_t
ObjCMethListSection::methodListSizeToRelativeMethodListSize(uint32_t iSecSize) {
uint32_t oldPointersSize = iSecSize - m_methodListHeaderSize;
uint32_t ObjCMethListSection::computeRelativeMethodListSize(
uint32_t absoluteMethodListSize) const {
uint32_t oldPointersSize = absoluteMethodListSize - methodListHeaderSize;
uint32_t pointerCount = oldPointersSize / target->wordSize;
assert(((pointerCount % m_pointersPerStruct) == 0) &&
assert(((pointerCount % pointersPerStruct) == 0) &&
"__objc_methlist expects method lists to have multiple-of-3 pointers");

constexpr uint32_t sizeOfRelativeOffset = sizeof(uint32_t);
uint32_t newPointersSize = pointerCount * sizeOfRelativeOffset;
uint32_t newTotalSize = m_methodListHeaderSize + newPointersSize;
uint32_t newPointersSize = pointerCount * relativeOffsetSize;
uint32_t newTotalSize = methodListHeaderSize + newPointersSize;

assert((newTotalSize <= iSecSize) &&
assert((newTotalSize <= absoluteMethodListSize) &&
"Expected relative method list size to be smaller or equal than "
"original size");
return newTotalSize;
Expand All @@ -2191,15 +2192,15 @@ ObjCMethListSection::methodListSizeToRelativeMethodListSize(uint32_t iSecSize) {
// Read a method list header from buf
void ObjCMethListSection::readMethodListHeader(const uint8_t *buf,
uint32_t &structSizeAndFlags,
uint32_t &structCount) {
uint32_t &structCount) const {
structSizeAndFlags = read32le(buf);
structCount = read32le(buf + sizeof(uint32_t));
}

// Write a method list header to buf
void ObjCMethListSection::writeMethodListHeader(uint8_t *buf,
uint32_t structSizeAndFlags,
uint32_t structCount) {
uint32_t structCount) const {
write32le(buf, structSizeAndFlags);
write32le(buf + sizeof(structSizeAndFlags), structCount);
}
Expand Down
23 changes: 11 additions & 12 deletions lld/MachO/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,37 +697,36 @@ class ObjCMethListSection final : public SyntheticSection {
void setUp();
void finalize() override;
bool isNeeded() const override { return !inputs.empty(); }
uint64_t getSize() const override { return m_size; }
uint64_t getSize() const override { return sectionSize; }
void writeTo(uint8_t *bufStart) const override;

private:
static void readMethodListHeader(const uint8_t *buf,
uint32_t &structSizeAndFlags,
uint32_t &structCount);
static void writeMethodListHeader(uint8_t *buf, uint32_t structSizeAndFlags,
uint32_t structCount);
static uint32_t methodListSizeToRelativeMethodListSize(uint32_t iSecSize);
void readMethodListHeader(const uint8_t *buf, uint32_t &structSizeAndFlags,
uint32_t &structCount) const;
void writeMethodListHeader(uint8_t *buf, uint32_t structSizeAndFlags,
uint32_t structCount) const;
uint32_t computeRelativeMethodListSize(uint32_t absoluteMethodListSize) const;
void writeRelativeOffsetForIsec(const ConcatInputSection *isec, uint8_t *buf,
uint32_t &inSecOff, uint32_t &outSecOff,
bool useSelRef) const;
uint32_t writeRelativeMethodList(const ConcatInputSection *isec,
uint8_t *buf) const;

static constexpr uint32_t m_methodListHeaderSize =
static constexpr uint32_t methodListHeaderSize =
/*structSizeAndFlags*/ sizeof(uint32_t) +
/*structCount*/ sizeof(uint32_t);
// Relative method lists are supported only for 3-pointer method lists
static constexpr uint32_t m_pointersPerStruct = 3;
static constexpr uint32_t pointersPerStruct = 3;
// The runtime identifies relative method lists via this magic value
static constexpr uint32_t m_relMethodHeaderFlag = 0x80000000;
static constexpr uint32_t relMethodHeaderFlag = 0x80000000;
// In the method list header, the first 2 bytes are the size of struct
static constexpr uint32_t m_structSizeMask = 0xFFFF;
// Relative method lists have 4 byte alignment as all data in the InputSection
// is 4 byte
static constexpr uint32_t m_align = 4;
static constexpr uint32_t relativeOffsetSize = sizeof(uint32_t);

// The output size of the __objc_methlist section, computed during finalize()
uint32_t m_size = 0;
uint32_t sectionSize = 0;
std::vector<ConcatInputSection *> inputs;
};

Expand Down
6 changes: 2 additions & 4 deletions lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1292,7 +1292,7 @@ template <class LP> void Writer::run() {
scanSymbols();
if (in.objcStubs->isNeeded())
in.objcStubs->setUp();
if (in.objcMethList)
if (in.objcMethList->isNeeded())
in.objcMethList->setUp();
scanRelocations();
if (in.initOffsets->isNeeded())
Expand Down Expand Up @@ -1365,9 +1365,7 @@ void macho::createSyntheticSections() {
in.unwindInfo = makeUnwindInfoSection();
in.objCImageInfo = make<ObjCImageInfoSection>();
in.initOffsets = make<InitOffsetsSection>();
// Only create ObjCMethListSection if we need it
if (config->emitRelativeMethodLists)
in.objcMethList = make<ObjCMethListSection>();
in.objcMethList = make<ObjCMethListSection>();

// This section contains space for just a single word, and will be used by
// dyld to cache an address to the image loader it uses.
Expand Down
40 changes: 37 additions & 3 deletions lld/test/MachO/objc-relative-method-lists-simple.s
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o a64_rel_dylib.o a64_simple_class.s

## Test arm64 + relative method lists
# RUN: ld64.lld a64_rel_dylib.o -o a64_rel_dylib.dylib -map a64_rel_dylib.map -dylib -arch arm64 -platform_version macos 11.0.0 11.0.0 -objc_relative_method_lists
# RUN: %no-lsystem-lld a64_rel_dylib.o -o a64_rel_dylib.dylib -map a64_rel_dylib.map -dylib -arch arm64 -objc_relative_method_lists
# RUN: llvm-objdump --macho --objc-meta-data a64_rel_dylib.dylib | FileCheck %s --check-prefix=CHK_REL

## Test arm64 + traditional method lists (no relative offsets)
# RUN: ld64.lld a64_rel_dylib.o -o a64_rel_dylib.dylib -map a64_rel_dylib.map -dylib -arch arm64 -platform_version macos 11.0.0 11.0.0 -no_objc_relative_method_lists
# RUN: %no-lsystem-lld a64_rel_dylib.o -o a64_rel_dylib.dylib -map a64_rel_dylib.map -dylib -arch arm64 -no_objc_relative_method_lists
# RUN: llvm-objdump --macho --objc-meta-data a64_rel_dylib.dylib | FileCheck %s --check-prefix=CHK_NO_REL

CHK_NO_REL-NOT: (relative)

CHK_REL: Contents of (__DATA_CONST,__objc_classlist) section
CHK_REL-NEXT: _OBJC_CLASS_$_MyClass
Expand Down Expand Up @@ -45,6 +44,41 @@ CHK_REL-NEXT: types 0x{{[0-9a-f]*}} (0x{{[0-9a-f]*}}) v16@0:8
CHK_REL-NEXT: imp 0x{{[0-9a-f]*}} (0x{{[0-9a-f]*}}) +[MyClass class_method_02]


CHK_NO_REL-NOT: (relative)

CHK_NO_REL: Contents of (__DATA_CONST,__objc_classlist) section
CHK_NO_REL-NEXT: _OBJC_CLASS_$_MyClass

CHK_NO_REL: baseMethods 0x80e8 (struct method_list_t *)
CHK_NO_REL-NEXT: entsize 24
CHK_NO_REL-NEXT: count 3
CHK_NO_REL-NEXT: name 0x5b8 instance_method_00
CHK_NO_REL-NEXT: types 0x580 v16@0:8
CHK_NO_REL-NEXT: imp -[MyClass instance_method_00]
CHK_NO_REL-NEXT: name 0x5cb instance_method_01
CHK_NO_REL-NEXT: types 0x580 v16@0:8
CHK_NO_REL-NEXT: imp -[MyClass instance_method_01]
CHK_NO_REL-NEXT: name 0x5de instance_method_02
CHK_NO_REL-NEXT: types 0x580 v16@0:8
CHK_NO_REL-NEXT: imp -[MyClass instance_method_02]


CHK_NO_REL: Meta Class
CHK_NO_REL-NEXT: _OBJC_METACLASS_$_MyClass

CHK_NO_REL: baseMethods 0x8050 (struct method_list_t *)
CHK_NO_REL-NEXT: entsize 24
CHK_NO_REL-NEXT: count 3
CHK_NO_REL-NEXT: name 0x588 class_method_00
CHK_NO_REL-NEXT: types 0x580 v16@0:8
CHK_NO_REL-NEXT: imp +[MyClass class_method_00]
CHK_NO_REL-NEXT: name 0x598 class_method_01
CHK_NO_REL-NEXT: types 0x580 v16@0:8
CHK_NO_REL-NEXT: imp +[MyClass class_method_01]
CHK_NO_REL-NEXT: name 0x5a8 class_method_02
CHK_NO_REL-NEXT: types 0x580 v16@0:8
CHK_NO_REL-NEXT: imp +[MyClass class_method_02]


######################## Generate a64_simple_class.s #########################
# clang -c simple_class.mm -s -o a64_simple_class.s -target arm64-apple-macos -arch arm64 -Oz
Expand Down

0 comments on commit 5c4a8da

Please sign in to comment.