首页
论坛
专栏
课程

[翻译]VS2019官方文档_64位异常处理Part1

2019-4-15 08:39 3607

[翻译]VS2019官方文档_64位异常处理Part1

2019-4-15 08:39
3607

最近在学习64位逆向, 于是想深入理解一下异常处理的流程与机制, 查询了官方文档之后发现并没有中文版, 微软官方提供的文档中也只有google翻译自动生成的文章. 于是就站在google机翻的肩膀上, 翻译了异常处理的数据结构介绍部分.

 

有一些地方理解的并不清晰, 如果翻译得有问题希望指正

 

前一段为原文, 后一段为对应的翻译

 

同时上传了PDF版, 后续如果有修改会再次上传

x64 exception handling

文档来源

  • https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=vs-2019
  • https://docs.microsoft.com/en-us/cpp/cpp/cpp-exception-handling?view=vs-2019

An overview of structured exception handling and C++ exception handling coding conventions and behavior on the x64. For general information on exception handling, see . Exception Handling in Visual C++

 

异常处理结构化与C++异常处理在64位系统下的代码行为与调用约定的概述. 对于异常处理的更多介绍, 参考Exception Handling in Visual C++


C++ 中的try-catch 异常Example

The following example throws a char * exception, but does not contain a handler designated to catch exceptions of type char *. The call to set_terminate instructs terminate to call term_func.

 

下面的例子抛出一个char *类型的异常, 但是不包含对应的句柄去处理该类异常. set_terminate 函数命令 terminate 去调用 term_func 函数

// exceptions_Unhandled_Exceptions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void term_func() {
   cout << "term_func was called by terminate." << endl;
   exit( -1 );
}
int main() {
   try
   {
      set_terminate( term_func );
      throw "Out of memory!"; // 没有对应的catch句柄对应该异常
   }
   catch( int )
   {
      cout << "Integer exception raised." << endl;
   }
   return 0;
}

Unwind data for exception handling, debugger support 支持调试器的异常处理的数据展开

Several data structures are required for exception handling and debugging support.

 

为了处理异常并支持调试器, 本段将涉及到一下几个数据结构

struct RUNTIME_FUNCTION

Table-based exception handling requires a table entry for all functions that allocate stack space or call another function (for example, nonleaf functions). Function table entries have the format:

 

函数中, 基于表格的处理异常方式都需要一个表项, 包含所有被置于栈空间中的函数 与 所有调用其他函数的函数 (例如, 非叶函数). 函数表项有如下的布局:

类型 说明 翻译
ULONG Function start address 函数起始地址
ULONG Function end address 函数结束地址
ULONG Unwind info address 展开信息的地址
 

The RUNTIME_FUNCTION structure must be DWORD aligned in memory. All addresses are image relative, that is, they are 32-bit offsets from the starting address of the image that contains the function table entry. These entries are sorted, and put in the .pdata section of a PE32+ image. For dynamically generated functions [JIT compilers], the runtime to support these functions must either use RtlInstallFunctionTableCallback or RtlAddFunctionTable to provide this information to the operating system. Failure to do so will result in unreliable exception handling and debugging of processes.

 

RUNTIME_FUNCTION 结构体在内存中必须为四字节对齐. 所有地址为 整个文件映射到内存中后的地址存储 (RVA方式存储), 也就是说, 从包含函数表项的内存地址处, 第32位偏移开始计算. 这些表项被依次排序, 并放置入PE32+头部内存的.pdata段中. 对于动态生成的函数[JIT 编译器], 想要运行时支持这些函数必须 使用 RtlInstallFunctionTableCallback 或 RtlAddFunctionTable 这两个函数, 将该信息添加进操作系统. 如果不这么做, 将导致不可靠的异常处理与进程调试.


struct UNWIND_INFO

The unwind data info structure is used to record the effects a function has on the stack pointer and where the nonvolatile registers are saved on the stack:

 

展开的数据信息结构被用来记录一个函数对栈指针的影响, 与寄存器保存在堆栈中的位置

类型 说明 翻译
UBYTE: 3 Version 版本
UBYTE: 5 Flags 标志位
UBYTE Size of prolog Prolog的大小
UBYTE Count of unwind codes 展开码的大小
UBYTE: 4 Frame Register 帧寄存器
UBYTE: 4 Frame Register offset (scaled) 帧寄存器偏移(比例)
USHORT * n Unwind codes array 展开码的数组
variable Can either be of form (1) or (2) below 可以是下方的(1)或(2)

(1) Exception Handler 异常处理

类型 说明 翻译
ULONG Address of exception handler 异常处理的地址
variable Language-specific handler data (optional) 特定编程语言的异常处理数据(可选)

(2) Chained Unwind Info 链式展开信息

类型 说明 翻译
ULONG Function start address 函数起始地址
ULONG Function end address 函数结束地址
ULONG Unwind info address 展开信息的地址
 

The UNWIND_INFO structure must be DWORD aligned in memory. Here's what each field means:

 

UNWIND_INFO结构体在内存中必须为四字节对齐, 以下是各成员的含义:

  • Version
    Version number of the unwind data, currently 1.
  • 版本
    展开数据的版本号, 当前为1

  • Flags
    Three flags are currently defined:

  • 标志位
    三个标志位现在被定义为:
类型 说明 翻译
UNW_FLAG_EHANDLER The function has an exception handler that should be called when looking for functions that need to examine exceptions. 当寻找需要检查异常的函数时, 函数需要调用该异常处理程序
UNW_FLAG_UHANDLER The function has a termination handler that should be called when unwinding an exception. 当展开一个异常时,函数应调用该终止处理程序。
UNW_FLAG_CHAININFO This unwind info structure is not the primary one for the procedure. Instead, the chained unwind info entry is the contents of a previous RUNTIME_FUNCTION entry. For informations, see Chained unwind info structures. If this flag is set, then the UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER flags must be cleared. Also, the frame register and fixed-stack allocation fields must have the same values as in the primary unwind info. 此展开信息结构不是主要过程。 链式展开信息项是上一个RUNTIME_FUNCTION结构项的内容。 有关信息,请参阅链式展开信息结构。 如果此标志被设置,那么 UNW_FLAG_EHANDLER 和 UNW_FLAG_UHANDLER 标志必须被清除。 此外,帧寄存器和固定堆栈分配字段必须与主展开信息中具有相同的信息。
  • Size of prolog
    Length of the function prolog in bytes.
  • Prolog的大小
    以字节为单位的 该函数的Prolog的长度

  • Count of unwind codes
    The number of slots in the unwind codes array. Some unwind codes, for example, UWOP_SAVE_NONVOL, require more than one slot in the array.

  • 展开码的大小
    展开码数组中存储的元素个数. 一些展开的代码, 例如UWOP_SAVE_NONVOL, 需要在数组中占据多于一个位置的大小
  • Frame register
    If nonzero, then the function uses a frame pointer (FP), and this field is the number of the nonvolatile register used as the frame pointer, using the same encoding for the operation info field of UNWIND_CODE nodes.
  • 帧寄存器
    如果不为零, 那么该函数使用帧指针(FP), 该字段是非易失性寄存器作为帧指针的个数, 与UNWIND_CODE节的操作信息段使用相同的编码
  • Frame register offset (scaled)
    If the frame register field is nonzero, this field is the scaled offset from RSP that is applied to the FP register when it's established. The actual FP register is set to RSP + 16 * this number, allowing offsets from 0 to 240. This offset permits pointing the FP register into the middle of the local stack allocation for dynamic stack frames, allowing better code density through shorter instructions (more instructions can use the 8-bit signed offset form).
  • 帧寄存器的偏移(比例)
    如果帧寄存器字段为非零值, 该字段则为在FP寄存器建立时, RSP到FP寄存器的偏移量比例. 实际的FP寄存器被设置在 RSP + 16*该数字, 该数字取值在 0 至 240 之间. 该偏移允许FP寄存器指向为动态栈帧开辟的本地堆栈中, 通过更短的指令实现更好的代码密度(更多的指令可以使用8字节有符号偏移的形式实现)
  • Unwind codes array
    An array of items that explains the effect of the prolog on the nonvolatile registers and RSP. See the section on UNWIND_CODE for the meanings of individual items. For alignment purposes, this array always has an even number of entries, and the final entry is potentially unused. In that case, the array is one longer than indicated by the count of unwind codes field.
  • 展开码的数组
    该数组解释了Prolog对于非易失性寄存器与RSP的影响. 具体解释请查询 UNWIND_CODE 结构体部分. 为了对齐考虑, 该数组永远保持偶数个元素, 最后一项可能没有实际意义. 在这种情况下, 该数组的元素个数 = count of unwind codes 字段中的显示的个数 + 1
  • Address of exception handler
    An image-relative pointer to either the function's language-specific exception or termination handler, if flag UNW_FLAG_CHAININFO is clear and one of the flags UNW_FLAG_EHANDLER or UNW_FLAG_UHANDLER is set.
  • 异常处理的地址
    如果标志位 UNW_FLAG_CHAININFO 为空, 并且UNW_FLAG_EHANDLER 或 UNW_FLAG_UHANDLER 两个标志位中的其中一项不为空, 则该地址指向 language-specific exception 或者 termination handler 的地址
  • Language-specific handler data
    The function's language-specific exception handler data. The format of this data is unspecified and completely determined by the specific exception handler in use.
  • 特定编程语言的异常处理数据
    函数的特定编程语言的异常处理数据. 该数据的结构未定义, 由具体的对应异常处理决定
  • Chained Unwind Info
    If flag UNW_FLAG_CHAININFO is set then the UNWIND_INFO structure ends with three UWORDs. These UWORDs represent the RUNTIME_FUNCTION information for the function of the chained unwind.
  • 链式展开信息\
    如果设置了 UNW_FLAG_CHAININFO 标志位, UNWIND_INFO 结构体以三个UWORDs结尾. 这三个UWORDs代表了链式展开函数的 RUNTIME_FUNCTION 信息

struct UNWIND_CODE

The unwind code array is used to record the sequence of operations in the prolog that affect the nonvolatile registers and RSP. Each code item has this format:

 

展开码数组被用作记录 会影响寄存器和RSP的运算序列. 素组中的每一个项元素有以下的格式:

类型 说明 翻译
UBYTE Offset in prolog 在Prolog中的偏移
UBYTE: 4 Unwind operation code 展开的指令代码
UBYTE: 4 Operation info 操作信息
 

The array is sorted by descending order of offset in the prolog.

 

该数组在Prolog中以降序排列

Offset in prolog 在Prolog中的偏移

Offset from the beginning of the prolog of the end of the instruction that performs this operation, plus 1 (that is, the offset of the start of the next instruction).

 

从Prolog起始处到执行了该运算的指令的结尾, 再 + 1 (也就是说, 是下一个指令的偏移)

Unwind operation code 展开的指令代码

Note: Certain operation codes require an unsigned offset to a value in the local stack frame. This offset is from the start, that is, the lowest address of the fixed stack allocation. If the Frame Register field in the UNWIND_INFO is zero, this offset is from RSP. If the Frame Register field is nonzero, this is the offset from where RSP was located when the FP register was established. This equals the FP register minus the FP register offset (16 * the scaled frame register offset in the UNWIND_INFO). If an FP register is used, then any unwind code taking an offset must only be used after the FP register is established in the prolog.

 

指定的运算代码需要一个到本地栈帧中的数据的无符号偏移值. 这个偏移值从分配的固定栈的最低地址开始计算. 如果在UNWIND_INFO中的帧寄存器字段为0, 该偏移值从RSP开始计算. 如果帧寄存器字段不为0, 该偏移值从 FP寄存器开始创建时, RSP所在的地址开始计算. 也等于 FP寄存器 - FP寄存器偏移(16 * UNWIND_INFO中的栈指针寄存器偏移比例). 如果FP寄存器正在使用, 任何带偏移值的展开码必须在FP寄存器在Prolog中建立后使用

 

For all opcodes except UWOP_SAVE_XMM128 and UWOP_SAVE_XMM128_FAR, the offset is always a multiple of 8, because all stack values of interest are stored on 8-byte boundaries (the stack itself is always 16-byte aligned). For operation codes that take a short offset (less than 512K), the final USHORT in the nodes for this code holds the offset divided by 8. For operation codes that take a long offset (512K <= offset < 4GB), the final two USHORT nodes for this code hold the offset (in little-endian format).

除了UWOP_SAVE_XMM128UWOP_SAVE_XMM128_FAR操作码之外, 偏移值始终是 8 的倍数, 因为所有的跟栈值有关的数据都储存在8字节边界上(栈本身始终为16字节对齐). 对于短偏移值的字节码(小于512K), 节点中最后的USHORT除以8 则为其偏移值. 对于长偏移值的字节码(大于512K且小于4GB), 节点中最后的两个USHORT为偏移值(小端存储方式)

 

For the opcodes UWOP_SAVE_XMM128 and UWOP_SAVE_XMM128_FAR, the offset is always a multiple of 16, since all 128-bit XMM operations must occur on 16-byte aligned memory. Therefore, a scale factor of 16 is used for UWOP_SAVE_XMM128, permitting offsets of less than 1M.

 

对于UWOP_SAVE_XMM128UWOP_SAVE_XMM128_FAR操作码, 偏移值始终是16的倍数, 因为所有128字节的XMM操作必须产生在16字节偏移的内存上. 所以, UWOP_SAVE_XMM128 使用16位比例因子的数值记录偏移, 偏移值本身大小不可超过一百万

 

The unwind operation code is one of these values:

 

展开的操作码是以下这些数据中的一种:

  • UWOP_PUSH_NONVOL (0) 1 node
    Push a nonvolatile integer register, decrementing RSP by 8. The operation info is the number of the register. Because of the constraints on epilogs, UWOP_PUSH_NONVOL unwind codes must appear first in the prolog and correspondingly, last in the unwind code array. This relative ordering applies to all other unwind codes except UWOP_PUSH_MACHFRAME.
  • UWOP_PUSH_NONVOL(0) 1个节点
    压入一个整数寄存器, 并将RSP - 8. 操作信息则为寄存器的数量.
    因为epilogs的限制, UWOP_PUSH_NONVOL 展开码必须出现在prolog的第一个, 和展开码数组的最后一个. 这个相对的顺序适用于所有其他的展开码, 除了UWOP_PUSH_MACHFRAME

  • UWOP_ALLOC_LARGE (1) 2 or 3 nodes
    Allocate a large-sized area on the stack. There are two forms. If the operation info equals 0, then the size of the allocation divided by 8 is recorded in the next slot, allowing an allocation up to 512K - 8. If the operation info equals 1, then the unscaled size of the allocation is recorded in the next two slots in little-endian format, allowing allocations up to 4GB - 8.

  • UWOP_ALLOC_LARGE(1) 2到3个节点
    在栈中开辟一块大空间. 共有两种开辟方式, 如果操作信息等于0, 那么开辟的栈空间大小除以8得到的商会被记录在下一个元素中, 允许开辟的大小最大为 512K - 8. 如果操作信息等于1, 那么开辟的栈空间的原始大小会被以小尾方式记录在下两个元素中, 允许开辟的大小最大为 4GB - 8
  • UWOP_ALLOC_SMALL (2) 1 node
    Allocate a small-sized area on the stack. The size of the allocation is the operation info field * 8 + 8, allowing allocations from 8 to 128 bytes.
  • UWOP_ALLOC_SMALL(2) 1个节点
    在栈中开辟一块小空间. 开辟空间的大小为 operation info字段 * 8 + 8, 允许开辟的空间大小为 8~128 字节

    The unwind code for a stack allocation should always use the shortest possible encoding:

    栈分配的展开码应始终为可达到的最小编码

Allocation Size 栈分配大小 Unwind Code 展开码
8 to 128 bytes UWOP_ALLOC_SMALL
136 to 512K-8 bytes UWOP_ALLOC_LARGE, operation info = 0
512K to 4G-8 bytes UWOP_ALLOC_LARGE, operation info = 1
  • UWOP_SET_FPREG (3) 1 node
    Establish the frame pointer register by setting the register to some offset of the current RSP. The offset is equal to the Frame Register offset (scaled) field in the UNWIND_INFO * 16, allowing offsets from 0 to 240. The use of an offset permits establishing a frame pointer that points to the middle of the fixed stack allocation, helping code density by allowing more accesses to use short instruction forms. The operation info field is reserved and should not be used.
  • UWOP_SET_FPREG(3) 1个节点
    创建FP寄存器, 并设置寄存器到当前RSP的偏移值. 该偏移值等于UNWIND_INFO结构体中的Frame Register offset (scaled) 字段 * 16, 偏移值的取值范围为 0 ~ 240. 偏移值的使用 建立了一个指向分配的固定栈中地址的帧指针, 通过更短的指令允许更好的代码密度. operation info字段被保留, 不应使用.

  • UWOP_SAVE_NONVOL (4) 2 nodes
    Save a nonvolatile integer register on the stack using a MOV instead of a PUSH. This code is primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack in a position that was previously allocated. The operation info is the number of the register. The scaled-by-8 stack offset is recorded in the next unwind operation code slot, as described in the note above.

  • UWOP_SAVE_NONVOL(4) 2个节点
    将一个整数寄存器保存在栈上, 注意使用MOV指令而非PUSH指令. 该展开码主要用作shrink-wrapping, 寄存器保存在栈上记录过的地址. 操作信息为寄存器数量. 比例因子为8的栈偏移被记录在下一个展开码的元素中, 具体操作在上面有介绍.
  • UWOP_SAVE_NONVOL_FAR (5) 3 nodes
    Save a nonvolatile integer register on the stack with a long offset, using a MOV instead of a PUSH. This code is primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack in a position that was previously allocated. The operation info is the number of the register. The unscaled stack offset is recorded in the next two unwind operation code slots, as described in the note above.
  • UWOP_SAVE_NONVOL_FAR(5) 3个节点
    将一个整数寄存器以远距离方式保存在栈上, 注意使用MOV指令而非PUSH指令. 该展开码主要用作shrink-wrapping, 寄存器保存在栈上记录过的地址. 操作信息为寄存器数量. 原始偏移值被记录在下两个展开操作码的槽中, 具体操作在上面有介绍.

  • UWOP_SAVE_XMM128 (8) 2 nodes
    Save all 128 bits of a nonvolatile XMM register on the stack. The operation info is the number of the register. The scaled-by-16 stack offset is recorded in the next slot.

  • UWOP_SAVE_XMM128(8) 2个节点
    将一个XMM寄存器的所有128字节全保存在栈上. 操作信息为寄存器数量, 比例因子为16的栈偏移被记录在下一个槽中

  • UWOP_SAVE_XMM128_FAR (9) 3 nodes
    Save all 128 bits of a nonvolatile XMM register on the stack with a long offset. The operation info is the number of the register. The unscaled stack offset is recorded in the next two slots.

  • UWOP_SAVE_XMM128_FAR(9) 3个节点
    将一个XMM寄存器的所有128字节以远距离偏移全部保存在栈上. 操作信息为寄存器数量, 栈偏移的原始数据被记录在下两个槽中

  • UWOP_PUSH_MACHFRAME (10) 1 node
    Push a machine frame. This is used to record the effect of a hardware interrupt or exception. There are two forms. If the operation info equals 0, one of these frames has been pushed on the stack:

  • UWOP_PUSH_MACHFRAME(10) 1个节点
    向栈中压入一个机器帧, 用来记录硬件中断或异常所带来的影响. 总共有两种格式. 如果操作信息为0, 则下面的这些数据之一被压入栈中

地址 对应数据
RSP+32 SS
RSP+24 Old RSP
RSP+16 EFLAGS
RSP+8 CS
RSP RIP
 

If the operation info equals 1, then one of these frames has been pushed:
如果操作信息等于1, 那么下面的数据之一被压入占中

地址 对应数据
RSP+40 SS
RSP+32 Old RSP
RSP+24 EFLAGS
RSP+16 CS
RSP+8 RIP
RSP Error code
 

This unwind code always appears in a dummy prolog, which is never actually executed but instead appears before the real entry point of an interrupt routine, and exists only to provide a place to simulate the push of a machine frame.

 

这个展开码始终出现在伪Prolog中, 表示永远不会实际执行, 而是出现在真正入口点之前的一个中断例程, 并且只是为了提供一个模拟机器帧的情况而出现.

 

UWOP_PUSH_MACHFRAME records that simulation, which indicates the machine has conceptually done this operation:

 

UWOP_PUSH_MACHFRAME 记录了该模拟, 并表示该机器已经从概念上完成了此操作:

  1. Pop RIP return address from top of stack into Temp
    从栈顶弹出RIP返回地址放入Temp
  2. Push SS
    压入SS段值
  3. Push old RSP
    压入原RSP
  4. Push EFLAGS
    压入EFLAGS
  5. Push CS
    压入CS段值
  6. Push Temp
    压入Temp值
  7. Push Error Code (if op info equals 1)
    压入错误码(如果操作信息等于1)

    The simulated UWOP_PUSH_MACHFRAME operation decrements RSP by 40 (op info equals 0) or 48 (op info equals 1).

    模拟的 UWOP_PUSH_MACHFRAME 操作将RSP降低40(操作信息为0) 或 48 (操作信息为1)

    Operation info 操作信息

    The meaning of the operation info bits depends upon the operation code. To encode a general-purpose (integer) register, this mapping is used:

    操作信息的含义由操作码决定, 若要编码常规用途的整数寄存器,请使用此表格:

编号 对应寄存器
0 RAX
1 RCX
2 RDX
3 RBX
4 RSP
5 RBP
6 RSI
7 RDI
8 to 15 R8 to R15

Chained unwind info structures 链式展开信息结构

If the UNW_FLAG_CHAININFO flag is set, then an unwind info structure is a secondary one, and the shared exception-handler/chained-info address field contains the primary unwind information. This sample code retrieves the primary unwind information, assuming that unwindInfo is the structure that has the UNW_FLAG_CHAININFO flag set.

 

如果设置了 UNW_FLAG_CHAININFO 标志位, 那么展开信息字段为次要信息, 共享的 异常处理/链式信息 地址保存主要的展开信息. 假设unwindInfo为具有UNW_FLAG_CHAININFO标志位的结构体, 下面的例子会检索主展开信息

PRUNTIME_FUNCTION primaryUwindInfo = (PRUNTIME_FUNCTION)&(unwindInfo->UnwindCode[( unwindInfo->CountOfCodes + 1 ) & ~1]);

Chained info is useful in two situations. First, it can be used for noncontiguous code segments. By using chained info, you can reduce the size of the required unwind information, because you do not have to duplicate the unwind codes array from the primary unwind info.

链式信息在以下两种情况下十分有用. 一, 它可以用于非连续的代码段. 通过使用链式信息, 你可以减少需要的展开信息的大小, 因为你不需要从主展开信息中复制展开码数组.

 

You can also use chained info to group volatile register saves. The compiler may delay saving some volatile registers until it is outside of the function entry prolog. You can record this by having primary unwind info for the portion of the function before the grouped code, and then setting up chained info with a non-zero size of prolog, where the unwind codes in the chained info reflect saves of the nonvolatile registers. In that case, the unwind codes are all instances of UWOP_SAVE_NONVOL. A grouping that saves nonvolatile registers by using a PUSH or modifies the RSP register by using an additional fixed stack allocation is not supported.

 

你也可以使用链式信息将易失寄存器进行分组保存. 编译器可能会迟缓保存一些易失寄存器中的信息, 直到离开函数的入口prolog处. 你可以通过记录在分组前的主展开信息, 然后设置链式信息与非零大小的Prolog, 链式信息中的展开码则对应了寄存器中保存的值. 在这种情况下, 所有展开码都为 UWOP_SAVE_NONVOL 的实例. 不支持使用PUSH或使用固定堆栈分配来修改RSP寄存器, 从而保存非易性寄存器的分组.

 

An UNWIND_INFO item that has UNW_FLAG_CHAININFO set can contain a RUNTIME_FUNCTION entry whose UNWIND_INFO item also has UNW_FLAG_CHAININFO set, sometimes called multiple shrink-wrapping. Eventually, the chained unwind info pointers arrive at an UNWIND_INFO item that has UNW_FLAG_CHAININFO cleared; this is the primary UNWIND_INFO item, which points to the actual procedure entry point.

一个设置了UNW_FLAG_CHAININFO标志位的 UNWIND_INFO 项可以保存一个 RUNTIME_FUNCTION 项. 该 UNWIND_INFO 同时设置了 UNW_FLAG_CHAININFO 标志位, 被称为 multiple shrink-wrapping. 当链式展开信息的指针到达一个设置了 UNWIND_INFO 项时, 该项的 UNW_FLAG_CHAININFO 标志位已经被清空. 这才是指向实际过程入口点的主 UNWIND_INFO 项,



[公告]LV6级以上的看雪会员可以免费获得《2019安全开发者峰会》门票一张!!

上传的附件:
最新回复 (4)
evionmzs 2019-4-15 13:50
2
0
正在学习这一块的内容,太感觉楼主了。顺便吐槽一下拖动登录验证功能,我试了9次才成功,以为出bug了。
ielts 2019-4-16 10:07
3
0
感谢分享~ 
kanxue 8 2019-4-21 14:28
4
0
evionmzs 正在学习这一块的内容,太感觉楼主了。顺便吐槽一下拖动登录验证功能,我试了9次才成功,以为出bug了。
 是指论坛登陆的验证功能吗?
evionmzs 2019-5-24 09:05
5
0
kanxue 是指论坛登陆的验证功能吗?
是的,不过今天试了一下,好用多了。
游客
登录 | 注册 方可回帖
返回