解读《x64 deep dive》 2

来源:互联网 发布:电脑桌面软件 编辑:程序博客网 时间:2024/06/08 07:53

1. All registers on the X64 CPU, with the exception of the segment registers and the EFlags register, are 64-bits which implies that all fetches from memory are 64-bit wide.

2. Fastcall is the default calling convention on X64 where in the first 4 parameters are passed via the registers RCX, RDX, R8, R9.

3. RBP is no longer used as frame pointer. It is now a general purpose register like any of the other registers like RBX, RCX etc. The debugger can no longer use the RBP register to walk the call stack.

4. The X64 compiler performs inline expansion of functions by which if certain criteria is met, it replaces the call to a function with the body of the callee. Although in-lining is not unique to X64, the X64 compiler is over zealous about in-lining functions. In-lining at a source file level is controlled by compiler's /Ob flag and in-lining can be disabled on a per function basis by __declspec(noinline).

5. X64 compiler can optimize the last call made from a function by replacing it with a jump to the callee. This avoids the overhead of setting up the stack frame for the callee.(哪些情况可以优化,需要进一步研究)

6. X64 uses the RSP register both as a stack pointer and a frame pointer(An exception to this rule are functions that use alloca() to dynamically allocate space on the stack. Such functions will use the RBP register as a frame pointer, as they did with EBP on the X86.)

7.all stack references on X64 are performed based on RSP. Due to this, functions on X64 depend on the RSP register being static throughout the function body, serving as a frame of reference for accessing locals and parameters.The fact that the stack pointer does not change at all between the prolog and the epilog is a characteristic feature of X64 functions,

8. In the x64 version of the function, however, there is no indication that the function uses structured exception handling, since no stack based exception frames are built at runtime.

9. On x86, when the high level language (C/C++) code contains structured exception handling constructs like __try/__except, the compiler generates special code in the prolog and epilog of the function that builds the exception frame on the stack at runtime.

10. When the function generates an exception, the OS scans the memory mapped copy of the PE file looking for a RUNTIME_FUNCTION structure whose extents include the current instruction address. The UnwindData field of the RUNTIME_FUNCTION structure contains the offset of another structure that tells the OS runtime as to how it should go about unwinding the stack, this is the UNWIND_INFO structure.

11. Other than this one issue with retrieving parameters, x64 debugging is not that different from x86 debugging.

12. Although the first four parameters are passed via registers, there is still space allocated on the stack for these four parameters. This is called the parameter homing space, The minimum size of this homing space is 0x20 bytes or four 64-bit slots, even if the function takes less than 4 parameters.When the homing space is not used to store parameter values, the compiler uses it to save non-volatile registers.

13. The register based parameter homing space exists only for non-leaf functions. It contains space for four parameters even if there isn't a single callee that takes that many parameters.

14. The value of the Child-SP register displayed by the debugger's "k" command represents the address at which the stack pointer (RSP) points to, as the point where the function displayed in that frame, has finished executing its prolog.

15. On the X86 CPU, the debugger follows the frame pointer (EBP) chain to walk the call stack from the most recent function frame to the least recent one

16. this frame pointer chain can be broken under certain circumstances, like when functions have their frame pointer omitted (FPO). In these cases, the debugger needs the symbols of the module to be able to accurately walk the call stack.

17. The debugger locates the RUNTIME_FUNCTION, UNWIND_INFO and UNWIND_CODE structures to compute the stack space utilization for every function in the call stack and adds these values to the Child-SPs to compute the value of subsequent Child-SPs.The UNWIND_CODE structures indicate the number of non-volatile registers that are pushed on the stack and the amount of space allocated for the locals and the parameters.

18. The debugger's "knf" command displays the call stack along with the amount of stack space utilized by every frame in the stack. This stack space utilization is listed under the "Memory" column.(需要注意的是,frame n占用的栈空间容量显示在frame n+1的Memory列中)。

19. Non-volatile registers that are moved (UWOP_SAVE_NONVOL), as opposed to pushed (UWOP_PUSH_NONVOL) on to the stack, don't contribute towards consumption of stack space.

0 0
原创粉丝点击