1515
1616import java .util .ArrayList ;
1717import java .util .Arrays ;
18+ import java .util .Collection ;
1819import java .util .Collections ;
1920import java .util .HashSet ;
2021import java .util .List ;
2122import java .util .Set ;
23+ import java .util .regex .Pattern ;
2224import java .util .stream .Collectors ;
2325
2426import ghidra .app .analyzers .relocations .emitters .BundleRelocationEmitter ;
2527import ghidra .app .analyzers .relocations .emitters .FunctionInstructionSink ;
2628import ghidra .app .analyzers .relocations .emitters .InstructionRelocationEmitter ;
2729import ghidra .app .analyzers .relocations .emitters .RelativeNextInstructionRelocationEmitter ;
2830import ghidra .app .analyzers .relocations .emitters .SymbolRelativeInstructionRelocationEmitter ;
29- import ghidra .app .analyzers .relocations .utils .FunctionInstructionSinkCodeRelocationSynthesizer ;
31+ import ghidra .app .analyzers .relocations .patterns .FixedOperandMatcher ;
32+ import ghidra .app .analyzers .relocations .patterns .OperandMatch ;
33+ import ghidra .app .analyzers .relocations .patterns .OperandMatcher ;
34+ import ghidra .app .analyzers .relocations .synthesizers .FunctionInstructionSinkCodeRelocationSynthesizer ;
3035import ghidra .app .analyzers .relocations .utils .SymbolWithOffset ;
3136import ghidra .app .util .importer .MessageLog ;
3237import ghidra .program .model .address .Address ;
38+ import ghidra .program .model .address .AddressSet ;
3339import ghidra .program .model .block .BasicBlockModel ;
3440import ghidra .program .model .block .CodeBlock ;
3541import ghidra .program .model .block .CodeBlockIterator ;
4854import ghidra .program .model .symbol .FlowType ;
4955import ghidra .program .model .symbol .Reference ;
5056import ghidra .program .model .symbol .Symbol ;
51- import ghidra .program .model .symbol .SymbolIterator ;
5257import ghidra .program .model .symbol .SymbolTable ;
5358import ghidra .program .util .ProgramUtilities ;
5459import ghidra .util .DataConverter ;
5762
5863public class MipsCodeRelocationSynthesizer
5964 extends FunctionInstructionSinkCodeRelocationSynthesizer {
65+ public static final Pattern GP_SYMBOLS_PATTERN = Pattern .compile ("^_gp$" );
66+
6067 private static class MIPS_26_InstructionRelocationEmitter extends InstructionRelocationEmitter {
61- private static final List <Byte > OPMASK_JTYPE = Arrays .asList (new Byte [] { -1 , -1 , -1 , 3 });
68+ private static final OperandMatcher MATCHER_LITTLE_ENDIAN =
69+ new JtypeOperandMatcher (new Byte [] { -1 , -1 , -1 , 3 }, 0x3ffffff );
70+
71+ private static class JtypeOperandMatcher extends FixedOperandMatcher {
72+ private final long bitmask ;
73+
74+ public JtypeOperandMatcher (Byte [] operandMask , long bitmask ) {
75+ super (operandMask );
76+
77+ this .bitmask = bitmask ;
78+ }
79+
80+ @ Override
81+ public OperandMatch createMatch (Instruction instruction , int operandIndex )
82+ throws MemoryAccessException {
83+ DataConverter dc = ProgramUtilities .getDataConverter (instruction .getProgram ());
84+ long value = (dc .getInt (instruction .getBytes ()) & bitmask ) << 2 ;
85+
86+ return new OperandMatch (operandIndex , 0 , 4 , bitmask , value );
87+ }
88+ }
6289
6390 private final Set <Instruction > branchesToShiftByOne ;
6491
@@ -71,53 +98,46 @@ public MIPS_26_InstructionRelocationEmitter(Program program,
7198 }
7299
73100 @ Override
74- public List <List <Byte >> getMasks () {
75- return List .of (OPMASK_JTYPE );
76- }
77-
78- @ Override
79- public long computeValue (Instruction instruction , int operandIndex , Reference reference ,
80- int offset , List <Byte > mask ) throws MemoryAccessException {
81- DataConverter dc = ProgramUtilities .getDataConverter (instruction .getProgram ());
82- long value = dc .getValue (instruction .getBytes (), offset , getSizeFromMask (mask ));
83- return (value & 0x3ffffff ) << 2 ;
84- }
85-
86- @ Override
87- public boolean matches (Instruction instruction , int operandIndex , Reference reference ,
88- int offset , List <Byte > mask ) throws MemoryAccessException {
89- long origin = instruction .getAddress ().getUnsignedOffset () & 0xfffffffff0000000L ;
90- long value = computeValue (instruction , operandIndex , reference , offset , mask );
101+ public boolean evaluate (Instruction instruction , OperandMatch match ,
102+ SymbolWithOffset symbol , Reference reference ) throws MemoryAccessException {
103+ Address fromAddress = instruction .getAddress ();
104+ long origin = fromAddress .getUnsignedOffset () & 0xfffffffff0000000L ;
91105 long target = reference .getToAddress ().getUnsignedOffset ();
106+ long addend = computeAddend (instruction , match , symbol , reference );
92107
93- return (origin | value ) == target ;
94- }
108+ if (addend < -0x4000000 || addend > 0x3ffffff || ((addend & 3 ) != 0 )) {
109+ return false ;
110+ }
95111
96- @ Override
97- public long computeAddend (Instruction instruction , int operandIndex ,
98- SymbolWithOffset symbol , Reference reference , int offset , List <Byte > mask )
99- throws MemoryAccessException {
100- return symbol .offset >> 2 ;
112+ return (origin | match .getValue ()) == target ;
101113 }
102114
103115 @ Override
104- public boolean emitRelocation (Instruction instruction , int operandIndex ,
105- SymbolWithOffset symbol , Reference reference , int offset , List <Byte > mask ,
106- long addend ) throws MemoryAccessException {
116+ protected void emit (Instruction instruction , OperandMatch match , SymbolWithOffset symbol ,
117+ Reference reference ) {
118+ RelocationTable relocationTable = getRelocationTable ();
119+ Address address = instruction .getAddress ();
120+ long addend = computeAddend (instruction , match , symbol , reference );
121+
107122 if (branchesToShiftByOne .contains (instruction )) {
108- logBranchDelaySlotWithHI16 ( instruction . getAddress (), getMessageLog ()) ;
109- addend -= 1 ;
123+ addend -= 4 ;
124+ logBranchDelaySlotWithHI16 ( address , getMessageLog ()) ;
110125 }
111126
112- if (addend < -0x4000000 || addend > 0x3ffffff ) {
113- return false ;
114- }
127+ relocationTable .addMIPS26 (address , symbol .name , addend );
128+ }
115129
116- RelocationTable relocationTable = getRelocationTable ();
117- Address fromAddress = instruction .getAddress ();
130+ private long computeAddend (Instruction instruction , OperandMatch match ,
131+ SymbolWithOffset symbol , Reference reference ) {
132+ long origin = instruction .getAddress ().getUnsignedOffset () & 0xfffffffff0000000L ;
133+ long addend = (origin | match .getValue ()) - symbol .address ;
118134
119- relocationTable .addMIPS26 (fromAddress .add (offset ), symbol .name , addend );
120- return true ;
135+ return addend ;
136+ }
137+
138+ @ Override
139+ public Collection <OperandMatcher > getOperandMatchers () {
140+ return List .of (MATCHER_LITTLE_ENDIAN );
121141 }
122142 }
123143
@@ -350,6 +370,27 @@ private Register getOutputRegister(Instruction instruction) {
350370 */
351371 private static class MIPS_PC16_InstructionRelocationEmitter
352372 extends RelativeNextInstructionRelocationEmitter {
373+ private static final OperandMatcher MATCHER_LITTLE_ENDIAN =
374+ new ItypeOperandMatcher (new Byte [] { -1 , -1 , 0 , 0 }, 0x0000ffffL );
375+
376+ private static class ItypeOperandMatcher extends FixedOperandMatcher {
377+ private final long bitmask ;
378+
379+ public ItypeOperandMatcher (Byte [] operandMask , long bitmask ) {
380+ super (operandMask );
381+
382+ this .bitmask = bitmask ;
383+ }
384+
385+ @ Override
386+ public OperandMatch createMatch (Instruction instruction , int operandIndex )
387+ throws MemoryAccessException {
388+ DataConverter dc = ProgramUtilities .getDataConverter (instruction .getProgram ());
389+ long value = ((long ) (short ) (dc .getInt (instruction .getBytes ()) & bitmask )) << 2 ;
390+
391+ return new OperandMatch (operandIndex , 0 , 4 , bitmask , value );
392+ }
393+ }
353394
354395 private final Set <Instruction > branchesToShiftByOne ;
355396
@@ -362,46 +403,60 @@ public MIPS_PC16_InstructionRelocationEmitter(Program program,
362403 }
363404
364405 @ Override
365- public long computeAddend (Instruction instruction , int operandIndex ,
366- SymbolWithOffset symbol , Reference reference , int offset , List <Byte > mask )
367- throws MemoryAccessException {
368- return super .computeAddend (instruction , operandIndex , symbol , reference , offset ,
369- mask ) >> 2 ;
406+ public boolean evaluate (Instruction instruction , OperandMatch match ,
407+ SymbolWithOffset symbol , Reference reference ) throws MemoryAccessException {
408+ return ((match .getValue () & 3 ) == 0 ) &&
409+ super .evaluate (instruction , match , symbol , reference );
370410 }
371411
372412 @ Override
373- public long computeValue (Instruction instruction , int operandIndex , Reference reference ,
374- int offset , List <Byte > mask ) throws MemoryAccessException {
375- return super .computeValue (instruction , operandIndex , reference , offset , mask ) << 2 ;
376- }
413+ public void emit (Instruction instruction , OperandMatch match , SymbolWithOffset symbol ,
414+ Reference reference ) {
415+ RelocationTable relocationTable = getRelocationTable ();
416+ Address address = instruction .getAddress ().add (match .getOffset ());
417+ long addend = address .getUnsignedOffset () - symbol .address + match .getValue ();
418+ boolean isTransparent = true ;
377419
378- @ Override
379- public boolean emitRelocation (Instruction instruction , int operandIndex ,
380- SymbolWithOffset symbol , Reference reference , int offset , List <Byte > mask ,
381- long addend ) throws MemoryAccessException {
382420 if (branchesToShiftByOne .contains (instruction )) {
383- // FIXME: clean up hack job for branch delay slots with HI16.
384421 logBranchDelaySlotWithHI16 (instruction .getAddress (), getMessageLog ());
385- addend -= 1 ;
422+ addend -= 4 ;
423+ isTransparent = false ;
424+ }
386425
387- RelocationTable relocationTable = getRelocationTable ();
388- Address fromAddress = instruction .getAddress ();
426+ relocationTable .addRelativePC (address , match .getSize (), match .getBitmask (), symbol .name ,
427+ addend , isTransparent );
428+ }
389429
390- relocationTable .addRelativePC (fromAddress .add (offset ), getSizeFromMask (mask ),
391- symbol .name , addend , false );
392- return true ;
393- }
394- else {
395- return super .emitRelocation (instruction , operandIndex , symbol , reference , offset ,
396- mask , addend );
397- }
430+ @ Override
431+ public Collection <OperandMatcher > getOperandMatchers () {
432+ return List .of (MATCHER_LITTLE_ENDIAN );
398433 }
399434 }
400435
401436 private static class MIPS_GPREL16_InstructionRelocationEmitter
402437 extends SymbolRelativeInstructionRelocationEmitter {
403- private static final List <Byte > OPMASK_LOAD_STORE =
404- Arrays .asList (new Byte [] { -1 , -1 , -32 , 3 });
438+ private static final OperandMatcher MATCHER_LITTLE_ENDIAN =
439+ new LoadStoreOperandMatcher (new Byte [] { -1 , -1 , -32 , 3 }, 0x0000ffffL );
440+
441+ private static class LoadStoreOperandMatcher extends FixedOperandMatcher {
442+ private final long bitmask ;
443+
444+ public LoadStoreOperandMatcher (Byte [] bytes , long bitmask ) {
445+ super (bytes );
446+
447+ this .bitmask = bitmask ;
448+ }
449+
450+ @ Override
451+ public OperandMatch createMatch (Instruction instruction , int operandIndex )
452+ throws MemoryAccessException {
453+ int size = getMaskLength ();
454+ DataConverter dc = ProgramUtilities .getDataConverter (instruction .getProgram ());
455+ long value = (short ) (dc .getInt (instruction .getBytes ()) & bitmask );
456+
457+ return new OperandMatch (operandIndex , 0 , size , bitmask , value );
458+ }
459+ }
405460
406461 private final Register gp ;
407462
@@ -414,24 +469,19 @@ public MIPS_GPREL16_InstructionRelocationEmitter(Program program,
414469 }
415470
416471 @ Override
417- public List <List <Byte >> getMasks () {
418- return List .of (OPMASK_LOAD_STORE );
419- }
420-
421- @ Override
422- public int getSizeFromMask (List <Byte > mask ) {
423- return 2 ;
424- }
425-
426- @ Override
427- public boolean matches (Instruction instruction , int operandIndex , Reference reference ,
428- int offset , List <Byte > mask ) throws MemoryAccessException {
429- Object [] objects = instruction .getOpObjects (operandIndex );
472+ public boolean evaluate (Instruction instruction , OperandMatch match ,
473+ SymbolWithOffset symbol , Reference reference ) throws MemoryAccessException {
474+ Object [] objects = instruction .getOpObjects (match .getOperandIndex ());
430475 if (!Arrays .asList (objects ).contains (gp )) {
431476 return false ;
432477 }
433478
434- return super .matches (instruction , operandIndex , reference , offset , mask );
479+ return super .evaluate (instruction , match , symbol , reference );
480+ }
481+
482+ @ Override
483+ public Collection <OperandMatcher > getOperandMatchers () {
484+ return List .of (MATCHER_LITTLE_ENDIAN );
435485 }
436486 }
437487
@@ -449,11 +499,17 @@ public List<FunctionInstructionSink> getFunctionInstructionSinks(Program program
449499 sinks .add (new MIPS_PC16_InstructionRelocationEmitter (program , relocationTable , function ,
450500 branchesToShiftByOne , monitor , log ));
451501
452- SymbolTable symtab = program .getSymbolTable ();
453- SymbolIterator _gp = symtab .getSymbols ("_gp" );
454- if (_gp .hasNext ()) {
455- sinks .add (new MIPS_GPREL16_InstructionRelocationEmitter (program , relocationTable ,
456- function , _gp .next (), monitor , log ));
502+ SymbolTable symbolTable = program .getSymbolTable ();
503+ AddressSet addressSet = new AddressSet ();
504+ for (Symbol symbol : symbolTable .getSymbolIterator (true )) {
505+ String name = symbol .getName (true );
506+ Address address = symbol .getAddress ();
507+
508+ if (GP_SYMBOLS_PATTERN .matcher (name ).matches () && !addressSet .contains (address )) {
509+ sinks .add (new MIPS_GPREL16_InstructionRelocationEmitter (program , relocationTable ,
510+ function , symbol , monitor , log ));
511+ addressSet .add (address );
512+ }
457513 }
458514
459515 return sinks ;
0 commit comments