Skip to content

Commit 453102a

Browse files
committed
[lld-macho][re-land] Warn on method name collisions from category definitions
This implements ld64's checks for duplicate method names in categories & classes. In addition, this sets us up for implementing Obj-C category merging. This diff handles the most of the parsing work; what's left is rewriting those category / class structures. Numbers for chromium_framework: base diff difference (95% CI) sys_time 2.182 ± 0.027 2.200 ± 0.047 [ -0.2% .. +1.8%] user_time 6.451 ± 0.034 6.479 ± 0.062 [ -0.0% .. +0.9%] wall_time 6.841 ± 0.048 6.885 ± 0.105 [ -0.1% .. +1.4%] samples 33 22 Fixes llvm#54912. Issues seen with the previous land will be fixed in the next commit. Reviewed By: #lld-macho, thevinster, oontvoo Differential Revision: https://reviews.llvm.org/D142916
1 parent 3fbc6fd commit 453102a

File tree

13 files changed

+630
-55
lines changed

13 files changed

+630
-55
lines changed

lld/MachO/Driver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,8 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
19211921
if (config->deadStrip)
19221922
markLive();
19231923

1924+
objc::checkCategories();
1925+
19241926
// ICF assumes that all literals have been folded already, so we must run
19251927
// foldIdenticalLiterals before foldIdenticalSections.
19261928
foldIdenticalLiterals();

lld/MachO/InputFiles.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,13 +1254,10 @@ static CIE parseCIE(const InputSection *isec, const EhReader &reader,
12541254
}
12551255
}
12561256
if (personalityAddrOff != 0) {
1257-
auto personalityRelocIt =
1258-
llvm::find_if(isec->relocs, [=](const macho::Reloc &r) {
1259-
return r.offset == personalityAddrOff;
1260-
});
1261-
if (personalityRelocIt == isec->relocs.end())
1257+
const auto *personalityReloc = isec->getRelocAt(personalityAddrOff);
1258+
if (!personalityReloc)
12621259
reader.failOn(off, "Failed to locate relocation for personality symbol");
1263-
cie.personalitySymbol = personalityRelocIt->referent.get<macho::Symbol *>();
1260+
cie.personalitySymbol = personalityReloc->referent.get<macho::Symbol *>();
12641261
}
12651262
return cie;
12661263
}

lld/MachO/InputSection.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ std::string InputSection::getSourceLocation(uint64_t off) const {
135135
return {};
136136
}
137137

138+
const Reloc *InputSection::getRelocAt(uint32_t off) const {
139+
auto it = llvm::find_if(
140+
relocs, [=](const macho::Reloc &r) { return r.offset == off; });
141+
if (it == relocs.end())
142+
return nullptr;
143+
return &*it;
144+
}
145+
138146
void ConcatInputSection::foldIdentical(ConcatInputSection *copy) {
139147
align = std::max(align, copy->align);
140148
copy->live = false;
@@ -259,6 +267,15 @@ const StringPiece &CStringInputSection::getStringPiece(uint64_t off) const {
259267
return const_cast<CStringInputSection *>(this)->getStringPiece(off);
260268
}
261269

270+
size_t CStringInputSection::getStringPieceIndex(uint64_t off) const {
271+
if (off >= data.size())
272+
fatal(toString(this) + ": offset is outside the section");
273+
274+
auto it =
275+
partition_point(pieces, [=](StringPiece p) { return p.inSecOff <= off; });
276+
return std::distance(pieces.begin(), it) - 1;
277+
}
278+
262279
uint64_t CStringInputSection::getOffset(uint64_t off) const {
263280
const StringPiece &piece = getStringPiece(off);
264281
uint64_t addend = off - piece.inSecOff;

lld/MachO/InputSection.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class InputSection {
5555
// Return the source line corresponding to an address, or the empty string.
5656
// Format: Source.cpp:123 (/path/to/Source.cpp:123)
5757
std::string getSourceLocation(uint64_t off) const;
58+
// Return the relocation at \p off, if it exists. This does a linear search.
59+
const Reloc *getRelocAt(uint32_t off) const;
5860
// Whether the data at \p off in this InputSection is live.
5961
virtual bool isLive(uint64_t off) const = 0;
6062
virtual void markLive(uint64_t off) = 0;
@@ -218,6 +220,10 @@ class CStringInputSection final : public InputSection {
218220
return toStringRef(data.slice(begin, end - begin));
219221
}
220222

223+
StringRef getStringRefAtOffset(uint64_t off) const {
224+
return getStringRef(getStringPieceIndex(off));
225+
}
226+
221227
// Returns i'th piece as a CachedHashStringRef. This function is very hot when
222228
// string merging is enabled, so we want to inline.
223229
LLVM_ATTRIBUTE_ALWAYS_INLINE
@@ -232,6 +238,9 @@ class CStringInputSection final : public InputSection {
232238

233239
bool deduplicateLiterals = false;
234240
std::vector<StringPiece> pieces;
241+
242+
private:
243+
size_t getStringPieceIndex(uint64_t off) const;
235244
};
236245

237246
class WordLiteralInputSection final : public InputSection {

lld/MachO/Layout.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===- Layout.h -----------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// Convenience macros for obtaining offsets of members in structs.
10+
//
11+
// Usage:
12+
//
13+
// #define FOR_EACH_FOO_FIELD(DO) \
14+
// DO(Ptr, bar) \
15+
// DO(uint32_t, baz) \
16+
// CREATE_LAYOUT_CLASS(Foo, FOR_EACH_FOO_FIELD)
17+
// #undef FOR_EACH_FOO_FIELD
18+
//
19+
// This will generate
20+
//
21+
// struct FooLayout {
22+
// uint32_t barOffset;
23+
// uint32_t bazOffset;
24+
// uint32_t totalSize;
25+
//
26+
// FooLayout(size_t wordSize) {
27+
// if (wordSize == 8)
28+
// init<uint64_t>();
29+
// else {
30+
// assert(wordSize == 4);
31+
// init<uint32_t>();
32+
// }
33+
// }
34+
//
35+
// private:
36+
// template <class Ptr> void init() {
37+
// FOR_EACH_FIELD(_INIT_OFFSET);
38+
// barOffset = offsetof(Layout<Ptr>, bar);
39+
// bazOffset = offsetof(Layout<Ptr>, baz);
40+
// totalSize = sizeof(Layout<Ptr>);
41+
// }
42+
// template <class Ptr> struct Layout {
43+
// Ptr bar;
44+
// uint32_t baz;
45+
// };
46+
// };
47+
48+
#define _OFFSET_FOR_FIELD(_, name) uint32_t name##Offset;
49+
#define _INIT_OFFSET(type, name) name##Offset = offsetof(Layout<Ptr>, name);
50+
#define _LAYOUT_ENTRY(type, name) type name;
51+
52+
#define CREATE_LAYOUT_CLASS(className, FOR_EACH_FIELD) \
53+
struct className##Layout { \
54+
FOR_EACH_FIELD(_OFFSET_FOR_FIELD) \
55+
uint32_t totalSize; \
56+
\
57+
className##Layout(size_t wordSize) { \
58+
if (wordSize == 8) \
59+
init<uint64_t>(); \
60+
else { \
61+
assert(wordSize == 4); \
62+
init<uint32_t>(); \
63+
} \
64+
} \
65+
\
66+
private: \
67+
template <class Ptr> void init() { \
68+
FOR_EACH_FIELD(_INIT_OFFSET); \
69+
totalSize = sizeof(Layout<Ptr>); \
70+
} \
71+
template <class Ptr> struct Layout { \
72+
FOR_EACH_FIELD(_LAYOUT_ENTRY) \
73+
}; \
74+
}

0 commit comments

Comments
 (0)