美文网首页
UE4对象系统_UFunction_字节码执行

UE4对象系统_UFunction_字节码执行

作者: 蛋求疼 | 来源:发表于2017-08-23 22:17 被阅读0次

    本来想研究一下vm的字节码并写个反汇编工具,结果发现UE4已经有了:-) 。反汇编的工具相关源码有:
    Engine\Source\Editor\UnrealEd\Public\ScriptDisassembler.h
    Engine\Source\Editor\UnrealEd\Private\ScriptDisassembler.cpp
    编辑中的使用方法:

    Paste_Image.png

    然后会在Log窗口中打印出反汇编结果。

    指令集

    //
    // Evaluatable expression item types.
    //
    enum EExprToken
    {
        // Variable references.
        EX_LocalVariable        = 0x00, // A local variable.
        EX_InstanceVariable     = 0x01, // An object variable.
        EX_DefaultVariable      = 0x02, // Default variable for a class context.
        //                      = 0x03,
        EX_Return               = 0x04, // Return from function.
        //                      = 0x05,
        EX_Jump                 = 0x06, // Goto a local address in code.
        EX_JumpIfNot            = 0x07, // Goto if not expression.
        //                      = 0x08,
        EX_Assert               = 0x09, // Assertion.
        //                      = 0x0A,
        EX_Nothing              = 0x0B, // No operation.
        //                      = 0x0C,
        //                      = 0x0D,
        //                      = 0x0E,
        EX_Let                  = 0x0F, // Assign an arbitrary size value to a variable.
        //                      = 0x10,
        //                      = 0x11,
        EX_ClassContext         = 0x12, // Class default object context.
        EX_MetaCast             = 0x13, // Metaclass cast.
        EX_LetBool              = 0x14, // Let boolean variable.
        EX_EndParmValue         = 0x15, // end of default value for optional function parameter
        EX_EndFunctionParms     = 0x16, // End of function call parameters.
        EX_Self                 = 0x17, // Self object.
        EX_Skip                 = 0x18, // Skippable expression.
        EX_Context              = 0x19, // Call a function through an object context.
        EX_Context_FailSilent   = 0x1A, // Call a function through an object context (can fail silently if the context is NULL; only generated for functions that don't have output or return values).
        EX_VirtualFunction      = 0x1B, // A function call with parameters.
        EX_FinalFunction        = 0x1C, // A prebound function call with parameters.
        EX_IntConst             = 0x1D, // Int constant.
        EX_FloatConst           = 0x1E, // Floating point constant.
        EX_StringConst          = 0x1F, // String constant.
        EX_ObjectConst          = 0x20, // An object constant.
        EX_NameConst            = 0x21, // A name constant.
        EX_RotationConst        = 0x22, // A rotation constant.
        EX_VectorConst          = 0x23, // A vector constant.
        EX_ByteConst            = 0x24, // A byte constant.
        EX_IntZero              = 0x25, // Zero.
        EX_IntOne               = 0x26, // One.
        EX_True                 = 0x27, // Bool True.
        EX_False                = 0x28, // Bool False.
        EX_TextConst            = 0x29, // FText constant
        EX_NoObject             = 0x2A, // NoObject.
        EX_TransformConst       = 0x2B, // A transform constant
        EX_IntConstByte         = 0x2C, // Int constant that requires 1 byte.
        EX_NoInterface          = 0x2D, // A null interface (similar to EX_NoObject, but for interfaces)
        EX_DynamicCast          = 0x2E, // Safe dynamic class casting.
        EX_StructConst          = 0x2F, // An arbitrary UStruct constant
        EX_EndStructConst       = 0x30, // End of UStruct constant
        EX_SetArray             = 0x31, // Set the value of arbitrary array
        EX_EndArray             = 0x32,
        //                      = 0x33,
        EX_UnicodeStringConst   = 0x34, // Unicode string constant.
        EX_Int64Const           = 0x35, // 64-bit integer constant.
        EX_UInt64Const          = 0x36, // 64-bit unsigned integer constant.
        //                      = 0x37,
        EX_PrimitiveCast        = 0x38, // A casting operator for primitives which reads the type as the subsequent byte
        EX_SetSet               = 0x39,
        EX_EndSet               = 0x3A,
        EX_SetMap               = 0x3B,
        EX_EndMap               = 0x3C,
        //                      = 0x3D,
        //                      = 0x3E,
        //                      = 0x3F,
        //                      = 0x40,
        //                      = 0x41,
        EX_StructMemberContext  = 0x42, // Context expression to address a property within a struct
        EX_LetMulticastDelegate = 0x43, // Assignment to a multi-cast delegate
        EX_LetDelegate          = 0x44, // Assignment to a delegate
        //                      = 0x45, 
        //                      = 0x46, // CST_ObjectToInterface
        //                      = 0x47, // CST_ObjectToBool
        EX_LocalOutVariable     = 0x48, // local out (pass by reference) function parameter
        //                      = 0x49, // CST_InterfaceToBool
        EX_DeprecatedOp4A       = 0x4A,
        EX_InstanceDelegate     = 0x4B, // const reference to a delegate or normal function object
        EX_PushExecutionFlow    = 0x4C, // push an address on to the execution flow stack for future execution when a EX_PopExecutionFlow is executed.   Execution continues on normally and doesn't change to the pushed address.
        EX_PopExecutionFlow     = 0x4D, // continue execution at the last address previously pushed onto the execution flow stack.
        EX_ComputedJump         = 0x4E, // Goto a local address in code, specified by an integer value.
        EX_PopExecutionFlowIfNot = 0x4F, // continue execution at the last address previously pushed onto the execution flow stack, if the condition is not true.
        EX_Breakpoint           = 0x50, // Breakpoint.  Only observed in the editor, otherwise it behaves like EX_Nothing.
        EX_InterfaceContext     = 0x51, // Call a function through a native interface variable
        EX_ObjToInterfaceCast   = 0x52, // Converting an object reference to native interface variable
        EX_EndOfScript          = 0x53, // Last byte in script code
        EX_CrossInterfaceCast   = 0x54, // Converting an interface variable reference to native interface variable
        EX_InterfaceToObjCast   = 0x55, // Converting an interface variable reference to an object
        //                      = 0x56,
        //                      = 0x57,
        //                      = 0x58,
        //                      = 0x59,
        EX_WireTracepoint       = 0x5A, // Trace point.  Only observed in the editor, otherwise it behaves like EX_Nothing.
        EX_SkipOffsetConst      = 0x5B, // A CodeSizeSkipOffset constant
        EX_AddMulticastDelegate = 0x5C, // Adds a delegate to a multicast delegate's targets
        EX_ClearMulticastDelegate = 0x5D, // Clears all delegates in a multicast target
        EX_Tracepoint           = 0x5E, // Trace point.  Only observed in the editor, otherwise it behaves like EX_Nothing.
        EX_LetObj               = 0x5F, // assign to any object ref pointer
        EX_LetWeakObjPtr        = 0x60, // assign to a weak object pointer
        EX_BindDelegate         = 0x61, // bind object and name to delegate
        EX_RemoveMulticastDelegate = 0x62, // Remove a delegate from a multicast delegate's targets
        EX_CallMulticastDelegate = 0x63, // Call multicast delegate
        EX_LetValueOnPersistentFrame = 0x64,
        EX_ArrayConst           = 0x65,
        EX_EndArrayConst        = 0x66,
        EX_AssetConst           = 0x67,
        EX_CallMath             = 0x68, // static pure function from on local call space
        EX_SwitchValue          = 0x69,
        EX_InstrumentationEvent = 0x6A, // Instrumentation event
        EX_ArrayGetByRef        = 0x6B,
        EX_Max                  = 0x100,
    };
    
    
    enum ECastToken
    {
        CST_ObjectToInterface   = 0x46,
        CST_ObjectToBool        = 0x47,
        CST_InterfaceToBool     = 0x49,
        CST_Max                 = 0xFF,
    };
    

    结合Engine\Source\Editor\UnrealEd\Private\ScriptDisassembler.cppEngine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp中指令解析代码,下面分析部分指令的执行。

    • EX_LocalVariable
    void UObject::execLocalVariable(FFrame& Stack, RESULT_DECL)
    {
        checkSlow(Stack.Object == this);
        checkSlow(Stack.Locals != NULL);
    
        UProperty* VarProperty = Stack.ReadProperty(); // 从指令流中读取局部对象的UProperty
        if (VarProperty == nullptr)
        {
            FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::AccessViolation, LOCTEXT("MissingLocalVariable", "Attempted to access missing local variable. If this is a packaged/cooked build, are you attempting to use an editor-only property?"));
            FBlueprintCoreDelegates::ThrowScriptException(this, Stack, ExceptionInfo);
    
            Stack.MostRecentPropertyAddress = nullptr;
        }
        else
        {
                   // 获得函数local variable的内存地址
            Stack.MostRecentPropertyAddress = VarProperty->ContainerPtrToValuePtr<uint8>(Stack.Locals);
    
            if (RESULT_PARAM)
            {
                VarProperty->CopyCompleteValueToScriptVM(RESULT_PARAM, Stack.MostRecentPropertyAddress);
            }
        }
    }
    
    • EX_InstanceVariable
    void UObject::execInstanceVariable(FFrame& Stack, RESULT_DECL)
    {
            // 读取类实例的成员变量UProperty 
        UProperty* VarProperty = (UProperty*)Stack.ReadObject();
        Stack.MostRecentProperty = VarProperty;
    
        if (VarProperty == nullptr || !IsA((UClass*)VarProperty->GetOuter()))
        {
            FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::AccessViolation, FText::Format(LOCTEXT("MissingProperty", "Attempted to access missing property '{0}'. If this is a packaged/cooked build, are you attempting to use an editor-only property?"), FText::FromString(GetNameSafe(VarProperty))));
            FBlueprintCoreDelegates::ThrowScriptException(this, Stack, ExceptionInfo);
    
            Stack.MostRecentPropertyAddress = nullptr;
        }
        else
        {
                    // 获取对象成员变量的地址
            Stack.MostRecentPropertyAddress = VarProperty->ContainerPtrToValuePtr<uint8>(this);
    
            if (RESULT_PARAM)
            {
                VarProperty->CopyCompleteValueToScriptVM(RESULT_PARAM, Stack.MostRecentPropertyAddress);
            }
        }
    }
    
    • EX_DefaultVariable
    void UObject::execDefaultVariable(FFrame& Stack, RESULT_DECL)
    {
        UProperty* VarProperty = (UProperty*)Stack.ReadObject();
        Stack.MostRecentProperty = VarProperty;
        Stack.MostRecentPropertyAddress = nullptr;
    
        UObject* DefaultObject = nullptr;
        if (HasAnyFlags(RF_ClassDefaultObject))
        {
            DefaultObject = this;
        }
        else
        {
            // @todo - allow access to archetype properties through object references?
        }
    
        if (VarProperty == nullptr || (DefaultObject && !DefaultObject->IsA((UClass*)VarProperty->GetOuter())))
        {
            FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::AccessViolation, LOCTEXT("MissingPropertyDefaultObject", "Attempted to access a missing property on a CDO. If this is a packaged/cooked build, are you attempting to use an editor-only property?"));
            FBlueprintCoreDelegates::ThrowScriptException(this, Stack, ExceptionInfo);
        }
        else
        {
            if(DefaultObject != nullptr)
            {
                Stack.MostRecentPropertyAddress = VarProperty->ContainerPtrToValuePtr<uint8>(DefaultObject);
                if(RESULT_PARAM)
                {
                    VarProperty->CopyCompleteValueToScriptVM(RESULT_PARAM, Stack.MostRecentPropertyAddress);
                }
            }
            else
            {
                FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::AccessViolation, LOCTEXT("AccessNoneDefaultObject", "Accessed None attempting to read a default property"));
                FBlueprintCoreDelegates::ThrowScriptException(this, Stack, ExceptionInfo);
            }
        }
    }
    
    • EX_LocalOutVariable
    void UObject::execLocalOutVariable(FFrame& Stack, RESULT_DECL)
    {
        checkSlow(Stack.Object == this);
    
        // get the property we need to find
        // 函数返回值的UProperty
        UProperty* VarProperty = Stack.ReadProperty();
        
        // look through the out parameter infos and find the one that has the address of this property
        FOutParmRec* Out = Stack.OutParms;
        checkSlow(Out);
        while (Out->Property != VarProperty)
        {
            Out = Out->NextOutParm;
            checkSlow(Out);
        }
            // 获取返回值地址
        Stack.MostRecentPropertyAddress = Out->PropAddr;
    
        // if desired, copy the value in that address to Result
        if (RESULT_PARAM && RESULT_PARAM != Stack.MostRecentPropertyAddress)
        {
            VarProperty->CopyCompleteValueToScriptVM(RESULT_PARAM, Stack.MostRecentPropertyAddress);
        }
    }
    
    • EX_InterfaceContext
    void UObject::execInterfaceContext(FFrame& Stack, RESULT_DECL)
    {
        // get the value of the interface variable
        FScriptInterface InterfaceValue;
        Stack.Step(this, &InterfaceValue);
    
        if (RESULT_PARAM != NULL)
        {
            // copy the UObject pointer to Result
            *(UObject**)RESULT_PARAM = InterfaceValue.GetObject();
        }
    }
    
    • EX_Let
      普通类型赋值
    void UObject::execLet(FFrame& Stack, RESULT_DECL)
    {
        Stack.MostRecentProperty = nullptr;
        UProperty* LocallyKnownProperty = Stack.ReadPropertyUnchecked();
    
        // Get variable address.
        Stack.MostRecentProperty = nullptr;
        Stack.MostRecentPropertyAddress = nullptr;
        Stack.Step(Stack.Object, nullptr); // Evaluate variable.  获取目的地址,存放在Stack.MostRecentPropertyAddress
    
        uint8* LocalTempResult = nullptr;
        if (Stack.MostRecentPropertyAddress == nullptr)
        {
            FBlueprintExceptionInfo ExceptionInfo(
                EBlueprintExceptionType::AccessViolation, 
                LOCTEXT("LetAccessNone", "Attempted to assign to None"));
            FBlueprintCoreDelegates::ThrowScriptException(this, Stack, ExceptionInfo);
    
            if (LocallyKnownProperty)
            {
                LocalTempResult = (uint8*)FMemory_Alloca(LocallyKnownProperty->GetSize());
                LocallyKnownProperty->InitializeValue(LocalTempResult);
                Stack.MostRecentPropertyAddress = LocalTempResult;
            }
            else
            {
                Stack.MostRecentPropertyAddress = (uint8*)FMemory_Alloca(1024);
                FMemory::Memzero(Stack.MostRecentPropertyAddress, sizeof(FString));
            }
        }
    
        // Evaluate expression into variable.  获取Src地址,并拷贝值到Stack.MostRecentPropertyAddress中
        Stack.Step(Stack.Object, Stack.MostRecentPropertyAddress);
    
        if (LocalTempResult && LocallyKnownProperty)
        {
            LocallyKnownProperty->DestroyValue(LocalTempResult);
        }
    }
    
    • EX_CallMath
      调用数学函数
    void UObject::execCallMathFunction(FFrame& Stack, RESULT_DECL)
    {
        UFunction* Function = (UFunction*)Stack.ReadObject();
        checkSlow(Function);
        checkSlow(Function->FunctionFlags & FUNC_Native);
        UObject* NewContext = Function->GetOuterUClass()->GetDefaultObject(false);
        checkSlow(NewContext);
        {
            FScopeCycleCounterUObject ContextScope(Stack.Object);
            FScopeCycleCounterUObject FunctionScope(Function);
    
            // CurrentNativeFunction is used so far only by FLuaContext::InvokeScriptFunction
            // TGuardValue<UFunction*> NativeFuncGuard(Stack.CurrentNativeFunction, Function);
            
            Native Func = Function->GetNativeFunc();
            checkSlow(Func);
            (NewContext->*Func)(Stack, RESULT_PARAM);
        }
    }
    
    • EX_VirtualFunction
    void UObject::execVirtualFunction( FFrame& Stack, RESULT_DECL )
    {
        // Call the virtual function.
        CallFunction( Stack, RESULT_PARAM, FindFunctionChecked(Stack.ReadName()) );
    }
    
    • EX_FinalFunction
    void UObject::execFinalFunction( FFrame& Stack, RESULT_DECL )
    {
        // Call the final function.
        CallFunction( Stack, RESULT_PARAM, (UFunction*)Stack.ReadObject() );
    }
    
    • EX_Jump
    void UObject::execJump( FFrame& Stack, RESULT_DECL )
    {
        CHECK_RUNAWAY;
    
        // Jump immediate.
        CodeSkipSizeType Offset = Stack.ReadCodeSkipCount();
        Stack.Code = &Stack.Node->Script[Offset];
    }
    
    • EX_ComputedJump
    void UObject::execComputedJump( FFrame& Stack, RESULT_DECL )
    {
        CHECK_RUNAWAY;
    
        // Get the jump offset expression
        int32 ComputedOffset = 0;
        Stack.Step( Stack.Object, &ComputedOffset );
        check((ComputedOffset < Stack.Node->Script.Num()) && (ComputedOffset >= 0));
    
        // Jump to the new offset
        Stack.Code = &Stack.Node->Script[ComputedOffset];
    }
    
    • EX_JumpIfNot
    void UObject::execJumpIfNot( FFrame& Stack, RESULT_DECL )
    {
        CHECK_RUNAWAY;
    
        // Get code offset.
        CodeSkipSizeType Offset = Stack.ReadCodeSkipCount();
    
        // Get boolean test value.
        bool Value=0;
        Stack.Step( Stack.Object, &Value );
    
        // Jump if false.
        if( !Value )
        {
            Stack.Code = &Stack.Node->Script[ Offset ];
        }
    }
    

    案例分析

    下图为一个蓝图FirstPersonProjectile:

    Paste_Image.png
    • EventHit 函数


      Paste_Image.png
    • CalculateTotalDamage函数

    Paste_Image.png

    执行console命令: DisasmScript FirstPersonProjectile_C:
    说明: Label_xxx为字节码在函数体内的位置号.

    • CalculateTotalDamage函数
      Processing function CalculateTotalDamage (256 bytes)
    Label_0x0:
             EX_Tracepoint(5E): .. debug site ..
    Label_0x1:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0x2:  // GetActorLocation到临时变量中
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_K2_GetActorLocation_ReturnValue
                 Expression:
                     EX_FinalFunction(1C): Final Function (stack node Actor::K2_GetActorLocation)
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x1E: // 执行InHitLocation - CallFunc_K2_GetActorLocation_ReturnValue 保存结果到临时变量中
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_Subtract_VectorVector_ReturnValue
                 Expression:
                     EX_CallMath(68): Call Math (stack node KismetMathLibrary::Subtract_VectorVector)
                         EX_LocalVariable(0): Local variable named InHitLocation
                         EX_LocalVariable(0): Local variable named CallFunc_K2_GetActorLocation_ReturnValue
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x4C: // 执行VectorLength到临时变量中
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_VSize_ReturnValue
                 Expression: // 调用VSize函数
                     EX_CallMath(68): Call Math (stack node KismetMathLibrary::VSize)
                         EX_LocalVariable(0): Local variable named CallFunc_Subtract_VectorVector_ReturnValue
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x71:  // 执行 >= 运算,结果放入临时变量
             EX_LetBool(14): LetBool (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_GreaterEqual_FloatFloat_ReturnValue
                 Expression:
                     EX_CallMath(68): Call Math (stack node KismetMathLibrary::GreaterEqual_FloatFloat)
                         EX_LocalVariable(0): Local variable named CallFunc_VSize_ReturnValue
                         EX_FloatConst(1E): literal float 10.000000
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x93:
             EX_Tracepoint(5E): .. debug site ..
    Label_0x94:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0x95:  // Branch语句
             EX_JumpIfNot(7): Jump to offset 0xDF if not expr:
                 EX_LocalVariable(0): Local variable named CallFunc_GreaterEqual_FloatFloat_ReturnValue
    Label_0xA3:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0xA4:
             EX_Tracepoint(5E): .. debug site ..
    Label_0xA5: // TotalVal = 100.0
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named TotalVal
                 Expression:
                     EX_FloatConst(1E): literal float 100.000000
    Label_0xBC:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0xBD:
             EX_Tracepoint(5E): .. debug site ..
    Label_0xBE:  //将TotalVal赋予返回值local out variable DamageVal
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalOutVariable(48): Local out variable named DamageVal
                 Expression:
                     EX_LocalVariable(0): Local variable named TotalVal
    Label_0xD9:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0xDA:
             EX_Jump(6): Jump to offset 0xFD
    Label_0xDF:
             EX_Tracepoint(5E): .. debug site ..
    Label_0xE0:  // 执行TotalVal = 200.0
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named TotalVal
                 Expression:
                     EX_FloatConst(1E): literal float 200.000000
    Label_0xF7:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0xF8:
             EX_Jump(6): Jump to offset 0xBD
    Label_0xFD:  // 函数返回
             EX_Return(4): Return expression
                 EX_Nothing(B): EX_Nothing
    Label_0xFF:
             EX_EndOfScript(53): EX_EndOfScript
    
    • EventHit函数
      Processing function ReceiveHit (166 bytes)
    Label_0x0:  // 将函数参数copy到临时变量中
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_MyComp, offset: 8
                 Expression:
                     EX_LocalVariable(0): Local variable named MyComp
    Label_0x12:
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_Other, offset: 16
                 Expression:
                     EX_LocalVariable(0): Local variable named Other
    Label_0x24:
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_OtherComp, offset: 24
                 Expression:
                     EX_LocalVariable(0): Local variable named OtherComp
    Label_0x36:
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_bSelfMoved, offset: 32
                 Expression:
                     EX_LocalVariable(0): Local variable named bSelfMoved
    Label_0x48:
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_HitLocation, offset: 36
                 Expression:
                     EX_LocalVariable(0): Local variable named HitLocation
    Label_0x5A:
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_HitNormal, offset: 48
                 Expression:
                     EX_LocalVariable(0): Local variable named HitNormal
    Label_0x6C:
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_NormalImpulse, offset: 60
                 Expression:
                     EX_LocalVariable(0): Local variable named NormalImpulse
    Label_0x7E:
             EX_LetValueOnPersistentFrame(64): LetValueOnPersistentFrame
                 Destination variable: K2Node_Event_Hit, offset: 72
                 Expression:
                     EX_LocalOutVariable(48): Local out variable named Hit
    
    Label_0x90: // 调用下面的函数
             EX_VirtualFunction(1B): Virtual Function named ExecuteUbergraph_FirstPersonProjectile
                 EX_IntConst(1D): literal int32 10
                 EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0xA3:
             EX_Return(4): Return expression
                 EX_Nothing(B): EX_Nothing
    Label_0xA5:
             EX_EndOfScript(53): EX_EndOfScript
    
    
    ===========================================================================
    // 被方框封起来的部分, 单独搞了个函数
      Processing function ExecuteUbergraph_FirstPersonProjectile (340 bytes)
    Label_0x0:
             EX_ComputedJump(4E): Computed Jump, offset specified by expression:
                     EX_LocalVariable(0): Local variable named EntryPoint
    Label_0xA:
             EX_Tracepoint(5E): .. debug site ..
    Label_0xB:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0xC:
             EX_LetBool(14): LetBool (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_IsSimulatingPhysics_ReturnValue
                 Expression:
                     $19: EX_Context      // 执行对象的成员函数
                         ObjectExpression:  // 获取pObj
                             EX_LocalVariable(0): Local variable named K2Node_Event_OtherComp
                         Skip Bytes: 0x1B
                         R-Value Property: CallFunc_IsSimulatingPhysics_ReturnValue
                         ContextExpression:  // 函数对象
                             EX_VirtualFunction(1B): Virtual Function named IsSimulatingPhysics
                                 EX_NameConst(21): literal name None 参数
                                 EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x47:
             EX_Tracepoint(5E): .. debug site ..
    Label_0x48:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0x49:
             EX_JumpIfNot(7): Jump to offset 0x151 if not expr:
                 EX_LocalVariable(0): Local variable named CallFunc_IsSimulatingPhysics_ReturnValue
    Label_0x57:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0x58:
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_K2_GetActorLocation_ReturnValue
                 Expression:
                     EX_FinalFunction(1C): Final Function (stack node Actor::K2_GetActorLocation)
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x74:
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_GetVelocity_ReturnValue
                 Expression:
                     EX_VirtualFunction(1B): Virtual Function named GetVelocity
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x94:
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_Multiply_VectorFloat_ReturnValue
                 Expression:
                     EX_CallMath(68): Call Math (stack node KismetMathLibrary::Multiply_VectorFloat)
                         EX_LocalVariable(0): Local variable named CallFunc_GetVelocity_ReturnValue
                         EX_FloatConst(1E): literal float 100.000000
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0xBE:
             EX_Tracepoint(5E): .. debug site ..
    Label_0xBF:
             $19: EX_Context
                 ObjectExpression:
                     EX_LocalVariable(0): Local variable named K2Node_Event_OtherComp
                 Skip Bytes: 0x2D
                 R-Value Property: (null)
                 ContextExpression:
                     EX_VirtualFunction(1B): Virtual Function named AddImpulseAtLocation
                         EX_LocalVariable(0): Local variable named CallFunc_Multiply_VectorFloat_ReturnValue
                         EX_LocalVariable(0): Local variable named CallFunc_K2_GetActorLocation_ReturnValue
                         EX_NameConst(21): literal name None
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x102:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0x103:
             EX_Tracepoint(5E): .. debug site ..
    Label_0x104:
             EX_VirtualFunction(1B): Virtual Function named K2_DestroyActor
                 EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x112:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0x113:
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_K2_GetActorLocation_ReturnValue
                 Expression:
                     EX_FinalFunction(1C): Final Function (stack node Actor::K2_GetActorLocation)
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x12F:
             EX_Tracepoint(5E): .. debug site ..
    Label_0x130:
             // 调用CalculateTotalDamage函数
             EX_VirtualFunction(1B): Virtual Function named CalculateTotalDamage
                 EX_LocalVariable(0): Local variable named CallFunc_K2_GetActorLocation_ReturnValue
                 EX_LocalVariable(0): Local variable named CallFunc_CalculateTotalDamage_DamageVal
                 EX_EndFunctionParms(16): EX_EndFunctionParms
    Label_0x150:
             EX_WireTracepoint(5A): .. wire debug site ..
    Label_0x151:
             EX_Return(4): Return expression
                 EX_Nothing(B): EX_Nothing
    Label_0x153:
             EX_EndOfScript(53): EX_EndOfScript
    

    从上述的字节码可以看出,UE的VM指令流的布局与Intel CPU上的指令布局是不一样的,比如EX_Let指令后面可以跟随其它指令,这些指令来实现variable,和expression功能,所以在字节码执行时会发生递归调解释器函数(Step)。而Intel的不一样,它是线性式的,表达式语句肯定是安排在前面执行的。


    现在看一下函数的参数传递情况(解决上一节的遗留疑问)。

    1. Call MathFunction
    Label_0x4C: // 执行VectorLength到临时变量中
             EX_Let(F): Let (Variable = Expression)
                 Variable:
                     EX_LocalVariable(0): Local variable named CallFunc_VSize_ReturnValue
                 Expression: // 调用VSize函数
                     EX_CallMath(68): Call Math (stack node KismetMathLibrary::VSize)
                         EX_LocalVariable(0): Local variable named CallFunc_Subtract_VectorVector_ReturnValue
                         EX_EndFunctionParms(16): EX_EndFunctionParms
    
    Paste_Image.png

    在KismetMathLibrary.generated.h中找到:

        DECLARE_FUNCTION(execVSize) \
        { \
            P_GET_STRUCT(FVector,Z_Param_A); \
            P_FINISH; \
            P_NATIVE_BEGIN; \
            *(float*)Z_Param__Result=UKismetMathLibrary::VSize(Z_Param_A); \
            P_NATIVE_END; \
        } \
    

    相关宏为:

    #define P_GET_STRUCT(StructType,ParamName)          PARAM_PASSED_BY_VAL(ParamName, UStructProperty, StructType)
    
    #define PARAM_PASSED_BY_VAL(ParamName, PropertyType, ParamType)                                 \
        ParamType ParamName;                                                                        \
        Stack.StepCompiledIn<PropertyType>(&ParamName);
    
    /**
     * Replacement for Step that checks the for byte code, and if none exists, then PropertyChainForCompiledIn is used.
     * Also makes an effort to verify that the params are in the correct order and the types are compatible.
     **/
    template<class TProperty>
    FORCEINLINE_DEBUGGABLE void FFrame::StepCompiledIn(void*const Result)
    {
        if (Code)
        {
            Step(Object, Result);
        }
        else
        {
            checkSlow(dynamic_cast<TProperty*>(PropertyChainForCompiledIn) && dynamic_cast<UProperty*>(PropertyChainForCompiledIn));
            TProperty* Property = (TProperty*)PropertyChainForCompiledIn;
            PropertyChainForCompiledIn = Property->Next;
            StepExplicitProperty(Result, Property);
        }
    }
    

    在FFrame::StepCompiledIn中Step()会执行EX_LocalVariable语句,通过Result返回结果。

    1. Call CalculateTotalDamage
    Label_0x130:
             // 调用CalculateTotalDamage函数
             EX_VirtualFunction(1B): Virtual Function named CalculateTotalDamage
                 EX_LocalVariable(0): Local variable named CallFunc_K2_GetActorLocation_ReturnValue
                 EX_LocalVariable(0): Local variable named CallFunc_CalculateTotalDamage_DamageVal
                 EX_EndFunctionParms(16): EX_EndFunctionParms
    
    Paste_Image.png Paste_Image.png Paste_Image.png Paste_Image.png

    相关文章

      网友评论

          本文标题:UE4对象系统_UFunction_字节码执行

          本文链接:https://www.haomeiwen.com/subject/fitddxtx.html