@@ -298,22 +298,24 @@ struct DiffData
298
298
CompileResult* cr2;
299
299
300
300
// Details of the first block
301
- size_t blocksize1;
302
- size_t datablock1;
303
- size_t datablockSize1;
304
- size_t originalBlock1;
305
- size_t originalDataBlock1;
306
- size_t otherCodeBlock1;
307
- size_t otherCodeBlockSize1;
301
+ unsigned char * block1;
302
+ size_t blocksize1;
303
+ unsigned char * datablock1;
304
+ size_t datablockSize1;
305
+ size_t originalBlock1;
306
+ size_t originalDataBlock1;
307
+ size_t otherCodeBlock1;
308
+ size_t otherCodeBlockSize1;
308
309
309
310
// Details of the second block
310
- size_t blocksize2;
311
- size_t datablock2;
312
- size_t datablockSize2;
313
- size_t originalBlock2;
314
- size_t originalDataBlock2;
315
- size_t otherCodeBlock2;
316
- size_t otherCodeBlockSize2;
311
+ unsigned char * block2;
312
+ size_t blocksize2;
313
+ unsigned char * datablock2;
314
+ size_t datablockSize2;
315
+ size_t originalBlock2;
316
+ size_t originalDataBlock2;
317
+ size_t otherCodeBlock2;
318
+ size_t otherCodeBlockSize2;
317
319
};
318
320
319
321
//
@@ -330,6 +332,7 @@ bool NearDiffer::compareOffsets(
330
332
return true ;
331
333
}
332
334
335
+ const SPMI_TARGET_ARCHITECTURE targetArch = GetSpmiTargetArchitecture ();
333
336
const DiffData* data = (const DiffData*)payload;
334
337
size_t ip1 = data->originalBlock1 + blockOffset;
335
338
size_t ip2 = data->originalBlock2 + blockOffset;
@@ -435,6 +438,99 @@ bool NearDiffer::compareOffsets(
435
438
if ((mapped1 == mapped2) && (mapped1 != (size_t )-1 ))
436
439
return true ;
437
440
441
+ // There are some cases on arm64 where we generate multiple instruction register construction of addresses
442
+ // but we don't have a relocation for them (so they aren't handled by `applyRelocs`). One case is
443
+ // allocPgoInstrumentationBySchema(), which returns an address into which the JIT writes PGO probe data.
444
+ // The instruction sequence is something like this:
445
+ // mov x0, #63408
446
+ // movk x0, #23602, lsl #16
447
+ // movk x0, #606, lsl #32
448
+ //
449
+ // Here, we try to match this sequence and look it up in the address map.
450
+ //
451
+ // Some version of this logic might apply to ARM as well.
452
+ //
453
+ if (targetArch == SPMI_TARGET_ARCHITECTURE_ARM64)
454
+ {
455
+ bool movk2 = false , movk3 = false ;
456
+ unsigned reg1_1, reg1_2, reg2_1, reg2_2, reg3_1, reg3_2, reg4_1, reg4_2;
457
+ unsigned con1_1, con1_2, con2_1, con2_2, con3_1, con3_2, con4_1, con4_2;
458
+ unsigned shift2_1, shift2_2, shift3_1, shift3_2, shift4_1, shift4_2;
459
+ UINT32* iaddr1 = (UINT32*)(data->block1 + blockOffset);
460
+ UINT32* iaddr2 = (UINT32*)(data->block2 + blockOffset);
461
+ UINT32* iaddr1end = (UINT32*)(data->block1 + data->blocksize1 );
462
+ UINT32* iaddr2end = (UINT32*)(data->block2 + data->blocksize2 );
463
+
464
+ // We're assuming that a mov/movk isn't the last instruction in the instruction buffer.
465
+ if ((iaddr1 < iaddr1end) &&
466
+ (iaddr2 < iaddr2end) &&
467
+ GetArm64MovConstant (iaddr1, ®1_1, &con1_1) &&
468
+ GetArm64MovConstant (iaddr2, ®1_2, &con1_2) &&
469
+ (reg1_1 == reg1_2))
470
+ {
471
+ if ((iaddr1 + 1 < iaddr1end) &&
472
+ (iaddr2 + 1 < iaddr2end) &&
473
+ GetArm64MovkConstant (iaddr1 + 1 , ®2_1, &con2_1, &shift2_1) &&
474
+ GetArm64MovkConstant (iaddr2 + 1 , ®2_2, &con2_2, &shift2_2) &&
475
+ (reg2_1 == reg2_2) &&
476
+ (shift2_1 == shift2_2) &&
477
+ (shift2_1 == 16 ))
478
+ {
479
+ // We currently assume the address requires at least 2 'movk' instructions, thus, is >4GB.
480
+ // The 3rd 'movk' is optional.
481
+ if ((iaddr1 + 2 < iaddr1end) &&
482
+ (iaddr2 + 2 < iaddr2end) &&
483
+ GetArm64MovkConstant (iaddr1 + 2 , ®3_1, &con3_1, &shift3_1) &&
484
+ GetArm64MovkConstant (iaddr2 + 2 , ®3_2, &con3_2, &shift3_2) &&
485
+ (reg3_1 == reg3_2) &&
486
+ (shift3_1 == shift3_2) &&
487
+ (shift3_1 == 32 ))
488
+ {
489
+ movk2 = true ;
490
+ // Note: this only works if size_t is 64-bit.
491
+ size_t addr1 = (size_t )con1_1 + ((size_t )con2_1 << 16 ) + ((size_t )con3_1 << 32 );
492
+ size_t addr2 = (size_t )con1_2 + ((size_t )con2_2 << 16 ) + ((size_t )con3_2 << 32 );
493
+ if ((iaddr1 + 3 < iaddr1end) &&
494
+ (iaddr2 + 3 < iaddr2end) &&
495
+ GetArm64MovkConstant (iaddr1 + 3 , ®4_1, &con4_1, &shift4_1) &&
496
+ GetArm64MovkConstant (iaddr2 + 3 , ®4_2, &con4_2, &shift4_2) &&
497
+ (reg4_1 == reg4_2) &&
498
+ (shift4_1 == shift4_2) &&
499
+ (shift4_1 == 48 ))
500
+ {
501
+ movk3 = true ;
502
+ addr1 += (size_t )con4_1 << 48 ;
503
+ addr2 += (size_t )con4_2 << 48 ;
504
+ }
505
+
506
+ // Check the constants! We don't need to check 'addr1 == addr2' because if that were
507
+ // true we wouldn't have gotten here.
508
+
509
+ size_t mapped1 = (size_t )data->cr1 ->searchAddressMap ((void *)addr1);
510
+ size_t mapped2 = (size_t )data->cr2 ->searchAddressMap ((void *)addr2);
511
+ if ((mapped1 == mapped2) && (mapped1 != (size_t )-1 ))
512
+ {
513
+ // Now, zero out the constants in the `movk` instructions so when the disassembler
514
+ // gets to them, they compare equal.
515
+ PutArm64MovkConstant (iaddr1 + 1 , 0 );
516
+ PutArm64MovkConstant (iaddr2 + 1 , 0 );
517
+ if (movk2)
518
+ {
519
+ PutArm64MovkConstant (iaddr1 + 2 , 0 );
520
+ PutArm64MovkConstant (iaddr2 + 2 , 0 );
521
+ }
522
+ if (movk3)
523
+ {
524
+ PutArm64MovkConstant (iaddr1 + 3 , 0 );
525
+ PutArm64MovkConstant (iaddr2 + 3 , 0 );
526
+ }
527
+ return true ;
528
+ }
529
+ }
530
+ }
531
+ }
532
+ }
533
+
438
534
return false ;
439
535
}
440
536
@@ -513,11 +609,11 @@ bool NearDiffer::compareCodeSection(MethodContext* mc,
513
609
cr2,
514
610
515
611
// Details of the first block
516
- (size_t )blocksize1, ( size_t ) datablock1, (size_t )datablockSize1, (size_t )originalBlock1,
612
+ block1, (size_t )blocksize1, datablock1, (size_t )datablockSize1, (size_t )originalBlock1,
517
613
(size_t )originalDataBlock1, (size_t )otherCodeBlock1, (size_t )otherCodeBlockSize1,
518
614
519
615
// Details of the second block
520
- (size_t )blocksize2, ( size_t ) datablock2, (size_t )datablockSize2, (size_t )originalBlock2,
616
+ block2, (size_t )blocksize2, datablock2, (size_t )datablockSize2, (size_t )originalBlock2,
521
617
(size_t )originalDataBlock2, (size_t )otherCodeBlock2, (size_t )otherCodeBlockSize2};
522
618
523
619
#ifdef USE_COREDISTOOLS
0 commit comments