@@ -353,7 +353,7 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
353353 break ;
354354
355355 case Machine . LoongArch64 :
356- //TODO-LoongArch64: maybe should add ProbeLoongArch64Quirks. At least it's unused now.
356+ ProbeLoongArch64Quirks ( rtf , imageOffset , rtfOffset , ref fixedTranslatedLine ) ;
357357 break ;
358358
359359 case Machine . ArmThumb2 :
@@ -1392,6 +1392,212 @@ private void AnalyzeRiscV64Itype(uint instruction, out uint rd, out uint rs1, ou
13921392 imm = unchecked ( ( int ) instruction ) >> 20 ;
13931393 }
13941394
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+
13951601 /// <summary>
13961602 /// Determine whether a given character is an ASCII digit.
13971603 /// </summary>
0 commit comments