Jump to content

New tool available that recalulates the jump offsets automatically


Bertilsson

Recommended Posts

Targeting another goto statement isn't a viable candidate, as multiply nested if/else statement can result in goto statements targeting other goto statements, as the nested set of if/else's unwinds.

 

I'm thinking that the way the UE Explorer resolves the difference between a break statement and an else statement is based upon some logic involving multiple destinations.

 

The goto that implements the outer else statement jumps to 0xDA. In order for an if/else to be nested within that else statement any jump offsets have to be less than that offset. However the goto statement in question has a target of 0xE8, which is outside of the scope of the current else block. UE Explorer must be detecting this and thus doesn't attempt to label the inner goto statement as an else but instead labels it as an explicit break.

 

I think the easiest way to handle this would be to track the valid offset range (i.e. 'scope') for each if/else block. The way the UE Explorer labels the //end 0x### before each type of jump statement shows that it is tracking the scope of each such jump statement.

Link to comment
Share on other sites

  • Replies 45
  • Created
  • Last Reply

Top Posters In This Topic

How about this rule?

 

Else-candidates are disqualified when:

  • Else-candidate target > target of any switch/case/foreach/while/if/else section in which the else-candidate exist (not counting the if-section that makes the else-candidate a candidate).

This would be valid:

1. switch/case/foreach/while/if/else  //Target 4
   {
2.   if (x)  //Target 4
     { 
3.     goto 4  //Else
     }
   }
4. Some code

Would translate to:

1. switch/case/foreach/while/if/else  //Target 4
   {
2.   if (x)  //Target 4 (Bracket presented as target 3 due to else-token)
     {
     } 
3.   else //Target 4
     {
     }
   }
4. Some code

In the previously discussed example:

...
    else
    {
      // End:0xDA
      if(!bExactClass && DamageTypeToHitEffectMap[FoundIndex].DamageTypeClass.IsA(DamageType.Name))
      {
        // [Explicit Break]
        goto J0xE8;  <<-- this is not an else since it has bigger target than the outer else section
      }
    } <-- Smaller than J0xE8
    ++ FoundIndex;
    J0xE8:

If the rule is valid then it should be relatively easy to implement (except for Switch and default case sections which are currently not identified)

Edited by Bertilsson
Link to comment
Share on other sites

I have now implemented the above logic and it seems to be working as intended.

http://hem.bredband.net/bertrich/XCOM/Temp/RepairTool092.png

 

Next on the list of things to do is to remove the duplicate status, offset and address values as a result of also moving the dropdowns to the end of each code-line again.

 

After that it is time for major code cleanup before adding any more features.

Edited by Bertilsson
Link to comment
Share on other sites

I have now:

  • Corrected a bug that destroyed any code which had a foreach-token present
    • I had forgotten to implement that foreach targets are defined in the end of the byte-string :wallbash:
  • Added a few warnings, including warning when a foreach token is present and has ")." in the object code-line.
    • Not sure how accurate this is...
  • Added some basic keyword highlighting

The only features I still miss are:

  1. Improved logic to separate else from break
    • Breaks at the end of if statements which are targeting end of loops are incorrectly interpreted as else statements
      • I have not yet figured out how to logically separate this from valid else statements. Need to collect more sample data before I can figure it out.
      • Example can be found near the end of XComGame.upk --> XComUnitPawn.AttachItem()
  2. Auto-correction of foreach loop internal context size (if really needed?)
  3. Improved error-handling when the user is not doing things exactly the way I expected.
  4. Drop-down to select indentation size (currently fixed at 2 spaces)
  5. Button to delete entire code-lines
  6. Buttons to move entire code-lines up or down
  7. Button to insert goto-tokens

1-2 should probably be addressed before v1.0.

3 Is a bit meeh, as I am not affected personally and I am close to 100% of the total user base :)

3-7 are more of the nature not really needed.

 

Regarding 2: After I fixed the code-breaking bug, I have not been able to break the foreach loop in XComGame.upk --> XComUnitPawn.AttachItem()

 

Original token-paragraph:

(052/036) [2F 19 00 32 37 00 00 2F 01 00 00 00 00 00 1C 7B FC FF FF 20 1A FE FF FF 00 2E 37 00 00 16 89 01]
	I(52/32) -> C(49/29) -> LV(9/5) -> FF(28/16) -> OC(9/5) -> LV(9/5) -> EFP(1/1)
	foreach A.ComponentList(class'MeshComponent', MeshComp)

I have tested changing 2F 01 to just about anything from 2F 00 to FF FF without any complaints from the game.

I have also changed the interior of the loop without any consequences. The code inside runs fine, and I have verified in-game that I can see the modified code results.

 

Can anyone point me to a foreach loop, which is simple to test, where problem occurs if the local context size is not correctly adjusted?

Link to comment
Share on other sites

Hmmm, that's an interesting foreach loop. I hadn't ever seen one before in which the second parameter (MeshComp in your example) wasn't a no-parameter token.

 

One other interesting feature of the example you gave is that there is no return value. The four bytes immediately following the 2F 01 context size are all zero, indicating that the ComponentList function has no return value.

 

It may well be that the context size is only actually used by the run-time engine if there is a return value.

 

A good example piece of code to test would be in the strategy game, with the new alien base code in XGFacility_SituationRoom.OnCodeCracked :

function OnCodeCracked()
{
    local int iMission;

    // End:0x103
    foreach World().m_arrCountries(kCountry,)
    {
        // End:0x102
        if(kCountry.m_bSecretPact)
        {
            // End:0x102
            if(kCountry.HasSatelliteCoverage())
            {
                AI().AddToAssets(byte(kCountry.GetID()), arrAssets);
                // End:0x102
                if(!m_bCodeCracked)
                {
                    m_bCodeCracked = true;
                    IsCodeActive();
                    PRES().UIObjectiveDisplay(4);
                }
            }
        }        
    }    
    Achieve(19);
    PushNarrativeHeadline(2);                
    //return;    
}

This code will be run in two cases : after the outsider shard research is completed (immediately), and after any satellite reaches orbit when the outsider shard research is complete.

 

I recall that this code would not execute until I patched up the context size. The UE Explorer token view for the foreach line:

(000/000) [58 19 1B 9C 2C 00 00 00 00 00 00 16 ED 00 EF 46 00 00 00 01 EF 46 00 00 00 DD 42 00 00 00 4A 03 01]
	AI(45/33) -> C(31/23) -> VF(10/10) -> EFP(1/1) -> IV(9/5) -> LV(9/5) -> NP(1/1)
	foreach World().m_arrCountries(kCountry,)

In this case the context size is ED 00 and the return value is identical to the m_arrCountries reference -- EF 46 00 00.

Link to comment
Share on other sites

  • 1 month later...

I have now made a minimal update to make the tool compatible with view tokens from UE Explorer 1.2.5.0 (it no longer expects 4 extra lines to ignore in the end).

I also changed the warning message when byte code and token view bytes doesn't seem to add up (which is incorrectly triggered by 0B tokens inside the function).

Edited by Bertilsson
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...