@@ -98,6 +98,24 @@ static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
98
98
static uint16_t highest (uint64_t V) { return V >> 48 ; }
99
99
static uint16_t highesta (uint64_t V) { return (V + 0x8000 ) >> 48 ; }
100
100
101
+ // Extracts the 'PO' field of an instruction encoding.
102
+ static uint8_t getPrimaryOpCode (uint32_t Encoding) { return (Encoding >> 26 ); }
103
+
104
+ static bool isDQFormInstruction (uint32_t Encoding) {
105
+ switch (getPrimaryOpCode (Encoding)) {
106
+ default :
107
+ return false ;
108
+ case 56 :
109
+ // The only instruction with a primary opcode of 56 is `lq`.
110
+ return true ;
111
+ case 61 :
112
+ // There are both DS and DQ instruction forms with this primary opcode.
113
+ // Namely `lxv` and `stxv` are the DQ-forms that use it.
114
+ // The DS 'XO' bits being set to 01 is restricted to DQ form.
115
+ return (Encoding & 3 ) == 0x1 ;
116
+ }
117
+ }
118
+
101
119
PPC64::PPC64 () {
102
120
GotRel = R_PPC64_GLOB_DAT;
103
121
PltRel = R_PPC64_JMP_SLOT;
@@ -298,7 +316,7 @@ void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
298
316
break ;
299
317
}
300
318
case R_PPC64_TLS: {
301
- uint32_t PrimaryOp = (read32 (Loc) & 0xFC000000 ) >> 26 ; // bits 0-5
319
+ uint32_t PrimaryOp = getPrimaryOpCode (read32 (Loc));
302
320
if (PrimaryOp != 31 )
303
321
error (" unrecognized instruction for IE to LE R_PPC64_TLS" );
304
322
uint32_t SecondaryOp = (read32 (Loc) & 0x000007FE ) >> 1 ; // bits 21-30
@@ -506,10 +524,15 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
506
524
write16 (Loc, Val);
507
525
break ;
508
526
case R_PPC64_ADDR16_DS:
509
- case R_PPC64_TPREL16_DS:
527
+ case R_PPC64_TPREL16_DS: {
510
528
checkInt (Loc, Val, 16 , Type);
511
- write16 (Loc, (read16 (Loc) & 3 ) | (Val & ~3 ));
512
- break ;
529
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
530
+ // DS-form instructions only use bits 30-31.
531
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U ;
532
+ uint16_t Mask = isDQFormInstruction (read32 (Loc - EndianOffset)) ? 0xF : 0x3 ;
533
+ checkAlignment (Loc, lo (Val), Mask + 1 , Type);
534
+ write16 (Loc, (read16 (Loc) & Mask) | lo (Val));
535
+ } break ;
513
536
case R_PPC64_ADDR16_HA:
514
537
case R_PPC64_REL16_HA:
515
538
case R_PPC64_TPREL16_HA:
@@ -542,9 +565,14 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
542
565
write16 (Loc, lo (Val));
543
566
break ;
544
567
case R_PPC64_ADDR16_LO_DS:
545
- case R_PPC64_TPREL16_LO_DS:
546
- write16 (Loc, (read16 (Loc) & 3 ) | (lo (Val) & ~3 ));
547
- break ;
568
+ case R_PPC64_TPREL16_LO_DS: {
569
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
570
+ // DS-form instructions only use bits 30-31.
571
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U ;
572
+ uint16_t Mask = isDQFormInstruction (read32 (Loc - EndianOffset)) ? 0xF : 0x3 ;
573
+ checkAlignment (Loc, lo (Val), Mask + 1 , Type);
574
+ write16 (Loc, (read16 (Loc) & Mask) | lo (Val));
575
+ } break ;
548
576
case R_PPC64_ADDR32:
549
577
case R_PPC64_REL32:
550
578
checkInt (Loc, Val, 32 , Type);
0 commit comments