@@ -282,6 +282,7 @@ struct BindIR {
282
282
// scream instead of accidentally writing "valid" values.
283
283
uint8_t opcode = 0xF0 ;
284
284
uint64_t data = 0 ;
285
+ uint64_t consecutiveCount = 0 ;
285
286
};
286
287
} // namespace
287
288
@@ -297,46 +298,77 @@ static void encodeBinding(const OutputSection *osec, uint64_t outSecOff,
297
298
OutputSegment *seg = osec->parent ;
298
299
uint64_t offset = osec->getSegmentOffset () + outSecOff;
299
300
if (lastBinding.segment != seg) {
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);
301
+ opcodes.push_back (
302
+ {static_cast <uint8_t >(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB |
303
+ seg->index ),
304
+ offset});
306
305
lastBinding.segment = seg;
307
306
lastBinding.offset = offset;
308
307
} else if (lastBinding.offset != offset) {
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);
308
+ opcodes.push_back ({BIND_OPCODE_ADD_ADDR_ULEB, offset - lastBinding.offset });
314
309
lastBinding.offset = offset;
315
310
}
316
311
317
312
if (lastBinding.addend != addend) {
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);
313
+ opcodes.push_back (
314
+ {BIND_OPCODE_SET_ADDEND_SLEB, static_cast <uint64_t >(addend)});
323
315
lastBinding.addend = addend;
324
316
}
325
317
326
- BindIR op = {
327
- static_cast <uint8_t >(BIND_OPCODE_DO_BIND), // opcode
328
- 0 // data
329
- };
330
- opcodes.push_back (op);
318
+ opcodes.push_back ({BIND_OPCODE_DO_BIND, 0 });
331
319
// DO_BIND causes dyld to both perform the binding and increment the offset
332
320
lastBinding.offset += target->wordSize ;
333
321
}
334
322
323
+ static void optimizeOpcodes (std::vector<BindIR> &opcodes) {
324
+ // Pass 1: Combine bind/add pairs
325
+ size_t i;
326
+ int pWrite = 0 ;
327
+ for (i = 1 ; i < opcodes.size (); ++i, ++pWrite) {
328
+ if ((opcodes[i].opcode == BIND_OPCODE_ADD_ADDR_ULEB) &&
329
+ (opcodes[i - 1 ].opcode == BIND_OPCODE_DO_BIND)) {
330
+ opcodes[pWrite].opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
331
+ opcodes[pWrite].data = opcodes[i].data ;
332
+ ++i;
333
+ } else {
334
+ opcodes[pWrite] = opcodes[i - 1 ];
335
+ }
336
+ }
337
+ if (i == opcodes.size ())
338
+ opcodes[pWrite] = opcodes[i - 1 ];
339
+ opcodes.resize (pWrite + 1 );
340
+
341
+ // Pass 2: Compress two or more bind_add opcodes
342
+ pWrite = 0 ;
343
+ for (i = 1 ; i < opcodes.size (); ++i, ++pWrite) {
344
+ if ((opcodes[i].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) &&
345
+ (opcodes[i - 1 ].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) &&
346
+ (opcodes[i].data == opcodes[i - 1 ].data )) {
347
+ opcodes[pWrite].opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
348
+ opcodes[pWrite].consecutiveCount = 2 ;
349
+ opcodes[pWrite].data = opcodes[i].data ;
350
+ ++i;
351
+ while (i < opcodes.size () &&
352
+ (opcodes[i].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) &&
353
+ (opcodes[i].data == opcodes[i - 1 ].data )) {
354
+ opcodes[pWrite].consecutiveCount ++;
355
+ ++i;
356
+ }
357
+ } else {
358
+ opcodes[pWrite] = opcodes[i - 1 ];
359
+ }
360
+ }
361
+ if (i == opcodes.size ())
362
+ opcodes[pWrite] = opcodes[i - 1 ];
363
+ opcodes.resize (pWrite + 1 );
364
+ }
365
+
335
366
static void flushOpcodes (const BindIR &op, raw_svector_ostream &os) {
336
367
uint8_t opcode = op.opcode & BIND_OPCODE_MASK;
337
368
switch (opcode) {
338
369
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
339
370
case BIND_OPCODE_ADD_ADDR_ULEB:
371
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
340
372
os << op.opcode ;
341
373
encodeULEB128 (op.data , os);
342
374
break ;
@@ -347,6 +379,11 @@ static void flushOpcodes(const BindIR &op, raw_svector_ostream &os) {
347
379
case BIND_OPCODE_DO_BIND:
348
380
os << op.opcode ;
349
381
break ;
382
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
383
+ os << op.opcode ;
384
+ encodeULEB128 (op.consecutiveCount , os);
385
+ encodeULEB128 (op.data , os);
386
+ break ;
350
387
default :
351
388
llvm_unreachable (" cannot bind to an unrecognized symbol" );
352
389
}
@@ -446,6 +483,8 @@ void BindingSection::finalizeContents() {
446
483
encodeBinding (b.target .isec ->parent ,
447
484
b.target .isec ->getOffset (b.target .offset ), b.addend ,
448
485
lastBinding, opcodes);
486
+ if (config->optimize > 1 )
487
+ optimizeOpcodes (opcodes);
449
488
for (const auto &op : opcodes)
450
489
flushOpcodes (op, os);
451
490
}
@@ -478,6 +517,8 @@ void WeakBindingSection::finalizeContents() {
478
517
encodeBinding (b.target .isec ->parent ,
479
518
b.target .isec ->getOffset (b.target .offset ), b.addend ,
480
519
lastBinding, opcodes);
520
+ if (config->optimize > 1 )
521
+ optimizeOpcodes (opcodes);
481
522
for (const auto &op : opcodes)
482
523
flushOpcodes (op, os);
483
524
}
0 commit comments