Skip to content

Commit f2b1264

Browse files
committed
[lld-macho] Use intermediate arrays to store opcodes
We want to incorporate some of the optimization passes in bind opcodes from ld64. This revision makes no functional changes but to start storing opcodes in intermediate containers in preparation for implementing the optimization passes in a follow-up revision. Differential Revision: https://reviews.llvm.org/D105866
1 parent 7139497 commit f2b1264

File tree

1 file changed

+56
-14
lines changed

1 file changed

+56
-14
lines changed

lld/MachO/SyntheticSections.cpp

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ struct Binding {
277277
uint64_t offset = 0;
278278
int64_t addend = 0;
279279
};
280+
struct BindIR {
281+
// Default value of 0xF0 is not valid opcode and should make the program
282+
// scream instead of accidentally writing "valid" values.
283+
uint8_t opcode = 0xF0;
284+
uint64_t data = 0;
285+
};
280286
} // namespace
281287

282288
// Encode a sequence of opcodes that tell dyld to write the address of symbol +
@@ -287,32 +293,65 @@ struct Binding {
287293
// lastBinding.
288294
static void encodeBinding(const OutputSection *osec, uint64_t outSecOff,
289295
int64_t addend, Binding &lastBinding,
290-
raw_svector_ostream &os) {
296+
std::vector<BindIR> &opcodes) {
291297
OutputSegment *seg = osec->parent;
292298
uint64_t offset = osec->getSegmentOffset() + outSecOff;
293299
if (lastBinding.segment != seg) {
294-
os << static_cast<uint8_t>(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB |
295-
seg->index);
296-
encodeULEB128(offset, os);
300+
BindIR op = {
301+
static_cast<uint8_t>(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB |
302+
seg->index), // opcode
303+
offset // data
304+
};
305+
opcodes.push_back(op);
297306
lastBinding.segment = seg;
298307
lastBinding.offset = offset;
299308
} else if (lastBinding.offset != offset) {
300-
os << static_cast<uint8_t>(BIND_OPCODE_ADD_ADDR_ULEB);
301-
encodeULEB128(offset - lastBinding.offset, os);
309+
BindIR op = {
310+
static_cast<uint8_t>(BIND_OPCODE_ADD_ADDR_ULEB), // opcode
311+
offset - lastBinding.offset // data
312+
};
313+
opcodes.push_back(op);
302314
lastBinding.offset = offset;
303315
}
304316

305317
if (lastBinding.addend != addend) {
306-
os << static_cast<uint8_t>(BIND_OPCODE_SET_ADDEND_SLEB);
307-
encodeSLEB128(addend, os);
318+
BindIR op = {
319+
static_cast<uint8_t>(BIND_OPCODE_SET_ADDEND_SLEB), // opcode
320+
static_cast<uint64_t>(addend) // data
321+
};
322+
opcodes.push_back(op);
308323
lastBinding.addend = addend;
309324
}
310325

311-
os << static_cast<uint8_t>(BIND_OPCODE_DO_BIND);
326+
BindIR op = {
327+
static_cast<uint8_t>(BIND_OPCODE_DO_BIND), // opcode
328+
0 // data
329+
};
330+
opcodes.push_back(op);
312331
// DO_BIND causes dyld to both perform the binding and increment the offset
313332
lastBinding.offset += target->wordSize;
314333
}
315334

335+
static void flushOpcodes(const BindIR &op, raw_svector_ostream &os) {
336+
uint8_t opcode = op.opcode & BIND_OPCODE_MASK;
337+
switch (opcode) {
338+
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
339+
case BIND_OPCODE_ADD_ADDR_ULEB:
340+
os << op.opcode;
341+
encodeULEB128(op.data, os);
342+
break;
343+
case BIND_OPCODE_SET_ADDEND_SLEB:
344+
os << op.opcode;
345+
encodeSLEB128(static_cast<int64_t>(op.data), os);
346+
break;
347+
case BIND_OPCODE_DO_BIND:
348+
os << op.opcode;
349+
break;
350+
default:
351+
llvm_unreachable("cannot bind to an unrecognized symbol");
352+
}
353+
}
354+
316355
// Non-weak bindings need to have their dylib ordinal encoded as well.
317356
static int16_t ordinalForDylibSymbol(const DylibSymbol &dysym) {
318357
if (config->namespaceKind == NamespaceKind::flat || dysym.isDynamicLookup())
@@ -392,9 +431,6 @@ void BindingSection::finalizeContents() {
392431
for (auto &p : sortBindings(bindingsMap)) {
393432
const DylibSymbol *sym = p.first;
394433
std::vector<BindingEntry> &bindings = p.second;
395-
llvm::sort(bindings, [](const BindingEntry &a, const BindingEntry &b) {
396-
return a.target.getVA() < b.target.getVA();
397-
});
398434
uint8_t flags = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM;
399435
if (sym->isWeakRef())
400436
flags |= BIND_SYMBOL_FLAGS_WEAK_IMPORT;
@@ -405,10 +441,13 @@ void BindingSection::finalizeContents() {
405441
encodeDylibOrdinal(ordinal, os);
406442
lastOrdinal = ordinal;
407443
}
444+
std::vector<BindIR> opcodes;
408445
for (const BindingEntry &b : bindings)
409446
encodeBinding(b.target.isec->parent,
410447
b.target.isec->getOffset(b.target.offset), b.addend,
411-
lastBinding, os);
448+
lastBinding, opcodes);
449+
for (const auto &op : opcodes)
450+
flushOpcodes(op, os);
412451
}
413452
if (!bindingsMap.empty())
414453
os << static_cast<uint8_t>(BIND_OPCODE_DONE);
@@ -434,10 +473,13 @@ void WeakBindingSection::finalizeContents() {
434473
os << static_cast<uint8_t>(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
435474
<< sym->getName() << '\0'
436475
<< static_cast<uint8_t>(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER);
476+
std::vector<BindIR> opcodes;
437477
for (const BindingEntry &b : bindings)
438478
encodeBinding(b.target.isec->parent,
439479
b.target.isec->getOffset(b.target.offset), b.addend,
440-
lastBinding, os);
480+
lastBinding, opcodes);
481+
for (const auto &op : opcodes)
482+
flushOpcodes(op, os);
441483
}
442484
if (!bindingsMap.empty() || !definitions.empty())
443485
os << static_cast<uint8_t>(BIND_OPCODE_DONE);

0 commit comments

Comments
 (0)