@@ -353,7 +353,7 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
353
353
break ;
354
354
355
355
case Machine . LoongArch64 :
356
- //TODO-LoongArch64: maybe should add ProbeLoongArch64Quirks. At least it's unused now.
356
+ ProbeLoongArch64Quirks ( rtf , imageOffset , rtfOffset , ref fixedTranslatedLine ) ;
357
357
break ;
358
358
359
359
case Machine . ArmThumb2 :
@@ -1392,6 +1392,212 @@ private void AnalyzeRiscV64Itype(uint instruction, out uint rd, out uint rs1, ou
1392
1392
imm = unchecked ( ( int ) instruction ) >> 20 ;
1393
1393
}
1394
1394
1395
+ /// <summary>
1396
+ /// Improves disassembler output for LoongArch64.
1397
+ /// </summary>
1398
+ /// <param name="rtf">Runtime function</param>
1399
+ /// <param name="imageOffset">Offset within the image byte array</param>
1400
+ /// <param name="rtfOffset">Offset within the runtime function</param>
1401
+ /// <param name="instruction">Textual representation of the instruction</param>
1402
+ private void ProbeLoongArch64Quirks ( RuntimeFunction rtf , int imageOffset , int rtfOffset , ref string instruction )
1403
+ {
1404
+ const int InstructionSize = 4 ;
1405
+ uint instr = BitConverter . ToUInt32 ( _reader . Image , imageOffset + rtfOffset ) ;
1406
+
1407
+ // The list of PC-relative instructions: BCond(BEQ, BNE, BLT[U], BGE[U]), BEQZ, BNEZ, BCEQZ, BCNEZ, B, BL, JIRL.
1408
+
1409
+ // Handle a B, BL, BCond(BEQ, BNE, BLT[U], BGE[U]), BZ(BEQZ, BNEZ, BCEQZ, BCNEZ) instruction
1410
+ if ( IsLoongArch64BCondInstruction ( instr , out int offs ) ||
1411
+ IsLoongArch64BOrBlInstruction ( instr , out offs ) ||
1412
+ IsLoongArch64BZInstruction ( instr , out offs ) )
1413
+ {
1414
+ ReplaceRelativeOffset ( ref instruction , rtf . StartAddress + rtfOffset + offs , rtf ) ;
1415
+ }
1416
+ else if ( IsLoongArch64JirlRAInstruction ( instr , out uint rj , out int imm ) )
1417
+ {
1418
+ // Common Pattern:
1419
+ // pcaddu12i
1420
+ // ld.d
1421
+ // jirl ra, rj, 0
1422
+ //
1423
+ // pcaddu12i
1424
+ // addi.d
1425
+ // ld.d
1426
+ // jirl ra, rj, 0
1427
+ // There may exist some irrelevant instructions between pcaddu12i and jirl.
1428
+ // We need to find relevant instructions based on rj to calculate the jump address.
1429
+ uint register = rj ;
1430
+ int immediate = imm ;
1431
+ bool isFound = false ;
1432
+ int currentInsOffs = rtfOffset - InstructionSize ;
1433
+ int currentPC = rtf . StartAddress + currentInsOffs ;
1434
+
1435
+ do
1436
+ {
1437
+ instr = BitConverter . ToUInt32 ( _reader . Image , imageOffset + currentInsOffs ) ;
1438
+
1439
+ if ( IsLoongArch64Ld_dOrAddi_dInstruction ( instr , out uint rd , out rj , out imm ) )
1440
+ {
1441
+ if ( rd == register )
1442
+ {
1443
+ register = rj ;
1444
+ immediate += imm ;
1445
+ }
1446
+ }
1447
+ else if ( IsLoongArch64Pcaddu12iInstruction ( instr , out rd , out imm ) )
1448
+ {
1449
+ if ( rd == register )
1450
+ {
1451
+ immediate += currentPC + imm ;
1452
+ isFound = true ;
1453
+ break ;
1454
+ }
1455
+ }
1456
+ else
1457
+ {
1458
+ // check if target register is using by an unexpected instruction.
1459
+ rd = ( instr & 0x1f ) ;
1460
+ if ( ( rd == register ) && ! IsLoongArch64Fld_dInstruction ( instr ) )
1461
+ {
1462
+ break ;
1463
+ }
1464
+ }
1465
+
1466
+ currentInsOffs -= InstructionSize ;
1467
+ currentPC -= InstructionSize ;
1468
+ } while ( currentInsOffs > 0 ) ;
1469
+
1470
+ if ( isFound )
1471
+ {
1472
+ if ( ! TryGetImportCellName ( immediate , out string targetName ) || string . IsNullOrWhiteSpace ( targetName ) )
1473
+ {
1474
+ return ;
1475
+ }
1476
+
1477
+ instruction = $ "{ instruction } // { targetName } ";
1478
+ }
1479
+ }
1480
+ }
1481
+
1482
+ /// <summary>
1483
+ /// Determine whether a given instruction is a BCond(BEQ, BNE, BLT[U], BGE[U]).
1484
+ /// </summary>
1485
+ /// <param name="ins">Assembly code of instruction</param>
1486
+ private bool IsLoongArch64BCondInstruction ( uint ins , out int offs )
1487
+ {
1488
+ uint Opcode = ( ins >> 26 ) & 0x3f ;
1489
+ offs = 0 ;
1490
+ if ( ( Opcode == 0x16 ) || ( Opcode == 0x17 ) || ( Opcode == 0x18 ) || ( Opcode == 0x19 ) || ( Opcode == 0x1a ) || ( Opcode == 0x1b ) )
1491
+ {
1492
+ offs = ( short ) ( ( ins >> 10 ) & 0xffff ) ;
1493
+ offs <<= 2 ;
1494
+ return true ;
1495
+ }
1496
+ return false ;
1497
+ }
1498
+
1499
+ /// <summary>
1500
+ /// Determine whether a given instruction is a B or a BL.
1501
+ /// </summary>
1502
+ /// <param name="ins">Assembly code of instruction</param>
1503
+ private bool IsLoongArch64BOrBlInstruction ( uint ins , out int offs )
1504
+ {
1505
+ uint Opcode = ( ins >> 26 ) & 0x3f ;
1506
+ offs = 0 ;
1507
+ if ( ( Opcode == 0x14 ) || ( Opcode == 0x15 ) )
1508
+ {
1509
+ offs = ( int ) ( ( ( ins >> 10 ) & 0xffff ) | ( ( ins & 0x3ff ) << 16 ) ) << 6 ;
1510
+ offs >>= 4 ;
1511
+ return true ;
1512
+ }
1513
+ return false ;
1514
+ }
1515
+
1516
+ /// <summary>
1517
+ /// Determine whether a given instruction is a BZ(BEQZ, BNEZ, BCEQZ, BCNEZ).
1518
+ /// </summary>
1519
+ /// <param name="ins">Assembly code of instruction</param>
1520
+ private bool IsLoongArch64BZInstruction ( uint ins , out int offs )
1521
+ {
1522
+ uint Opcode = ( ins >> 26 ) & 0x3f ;
1523
+ offs = 0 ;
1524
+ if ( ( Opcode == 0x10 ) || ( Opcode == 0x11 ) || ( Opcode == 0x12 ) )
1525
+ {
1526
+ offs = ( int ) ( ( ( ( ins >> 10 ) & 0xffff ) | ( ( ins & 0x1f ) << 16 ) ) << 11 ) ;
1527
+ offs >>= 9 ;
1528
+ return true ;
1529
+ }
1530
+ return false ;
1531
+ }
1532
+
1533
+ /// <summary>
1534
+ /// Determine whether a given instruction is a JIRL RA.
1535
+ /// </summary>
1536
+ /// <param name="ins">Assembly code of instruction</param>
1537
+ private bool IsLoongArch64JirlRAInstruction ( uint ins , out uint rj , out int offs )
1538
+ {
1539
+ rj = 0 ;
1540
+ offs = 0 ;
1541
+ if ( ( ( ( ins >> 26 ) & 0x3f ) == 0x13 ) && ( ( ins & 0x1f ) == 1 ) )
1542
+ {
1543
+ rj = ( ins >> 5 ) & 0x1f ;
1544
+ offs = ( short ) ( ( ins >> 10 ) & 0xffff ) ;
1545
+ offs <<= 2 ;
1546
+ return true ;
1547
+ }
1548
+ return false ;
1549
+ }
1550
+
1551
+ /// <summary>
1552
+ /// Determine whether a given instruction is a PCADDU12I.
1553
+ /// </summary>
1554
+ /// <param name="ins">Assembly code of instruction</param>
1555
+ private bool IsLoongArch64Pcaddu12iInstruction ( uint ins , out uint rd , out int imm )
1556
+ {
1557
+ rd = 0 ;
1558
+ imm = 0 ;
1559
+ if ( ( ( ins >> 25 ) & 0x3f ) == 0xe )
1560
+ {
1561
+ rd = ins & 0x1f ;
1562
+ imm = ( int ) ( ( ins >> 5 ) & 0xfffff ) << 12 ;
1563
+ return true ;
1564
+ }
1565
+ return false ;
1566
+ }
1567
+
1568
+ /// <summary>
1569
+ /// Determine whether a given instruction is a LD.D or ADDI.D.
1570
+ /// </summary>
1571
+ /// <param name="ins">Assembly code of instruction</param>
1572
+ private bool IsLoongArch64Ld_dOrAddi_dInstruction ( uint ins , out uint rd , out uint rj , out int imm )
1573
+ {
1574
+ imm = 0 ;
1575
+ rd = rj = 0 ;
1576
+
1577
+ if ( ( ( ( ins >> 22 ) & 0x3ff ) == 0xa3 ) || ( ( ( ins >> 22 ) & 0x3ff ) == 0xb ) )
1578
+ {
1579
+ rd = ins & 0x1f ;
1580
+ rj = ( ins >> 5 ) & 0x1f ;
1581
+ imm = ( int ) ( ( ins >> 10 ) & 0xfff ) << 20 ;
1582
+ imm >>= 20 ;
1583
+ return true ;
1584
+ }
1585
+ return false ;
1586
+ }
1587
+
1588
+ /// <summary>
1589
+ /// Determine whether a given instruction is a FLD.D.
1590
+ /// </summary>
1591
+ /// <param name="ins">Assembly code of instruction</param>
1592
+ private bool IsLoongArch64Fld_dInstruction ( uint ins )
1593
+ {
1594
+ if ( ( ( ins >> 22 ) & 0x3ff ) == 0xae )
1595
+ {
1596
+ return true ;
1597
+ }
1598
+ return false ;
1599
+ }
1600
+
1395
1601
/// <summary>
1396
1602
/// Determine whether a given character is an ASCII digit.
1397
1603
/// </summary>
0 commit comments