ZHCADC4A September 2011 – March 2014
个性化例程 PR0、PR1 和 PR2 使用字节编码的指令序列来说明如何展开帧。前几条指令被封装到 EXTAB 第一个字的剩余三个字节中;附加指令被封装到后续字中。最后一个字中未使用的字节由“RET B3”指令填充。
尽管指令是字节编码的,但它们始终封装成从 MSB 开始的 32 位字。因此,在小端字节序模式下,第一个展开指令将不会位于最低地址字节。
个性化例程 PR0 最多允许三条展开指令,所有这些指令都存储在第一个 EXTAB 字中。如果有三个以上的展开指令,则必须使用其他个性化例程之一。
对于 PR1 和 PR2,位 23-16 编码展开指令的额外 32 位字的数量,该数量可为 0。
表 11-2 总结了展开指令集。表格后面对每条指令进行了更详细的介绍。
编码 | 指令 | 说明 |
---|---|---|
00kk kkkk | SP += (k << 3) + 8 | 将 SP 递增,增量为一个小常数 |
1101 0010 kkkk kkkk ... | SP += (ULEB128 << 3) + 0x408 | 将 SP 递增,增量为一个 ULEB128 编码的常数 |
1000 0000 0000 0000 | CANTUNWIND | 函数无法展开,但可能会捕获异常 |
100x xxxx xxxx xxxx | POP bitmask | 弹出一个或多个寄存器 [x != 0] |
101x xxxx xxxx xxxx | POP bitmask | 从 C64x + 压缩帧 [x!= 0] 中弹出一个或多个寄存器 |
1100 nnnn xxxx xxxx ... | POP register | n 表示要弹出的寄存器数量,这些寄存器在后面的 4 位半字节中进行编码 |
1101 0000 | MV FP, SP | 从 FP 恢复 SP 而不是将 SP 递增 |
1101 0001 | _ _C6000_pop_rts | 模拟对 _ _C6000_pop_rts 的调用 |
1110 0111 | RET B3 | 此帧的展开完成 |
1110 xxxx | RETURN 或恢复 B3 | b3:= 寄存器 x (x != B3) |
所有其他位模式均保留。
以下各段详细说明了展开指令的解释。
小增量
k 的值从编码的低 6 位中提取。此指令可以使 SP 递增一个介于 0x8 到 0x200 之间的值,包括边界值。0x208 到 0x400 范围内的增量应该用这些指令中的两个来完成。
大增量
值 ULEB128 在 8 位操作码之后的字节中进行 ULEB128 编码。此指令可以将 SP 递增 0x408 或更大的值。增量小于 0x408 应使用 1 条或 2 条小增量指令实现。
CANTUNWIND
此指令指示函数不能展开,通常是因为它是中断函数。但是,中断函数仍然可以有 try/catch 代码,因此 EXIDX_CANTUNWIND 不适用。
POP Bitmask
这条两个字节的指令指示:根据位掩码指定,最多应该从虚拟栈弹出 13 个被调用者保存的寄存器。恢复寄存器的顺序必须与它们在安全调试 顺序中的出现顺序相同。
当使用“POP bitmask”指令弹出任何寄存器时,SP 首先根据被调用者保存的寄存器区域的大小隐式递增,四舍五入为最多 8 个字节。这是对任何显式 SP 增量指令的补充。但是,如果使用过“MV FP, SP”指令,则“POP bitmask”不会隐式递增 SP。
POP Bitmask; C64x+ Compact Frame
与 POP Bitmask 相同,但指示使用 C64x+ 紧凑帧 布局,这可能会在堆栈上留下空洞以有利于使用 SP 自动递减存储。展开程序必须知道用于放置空洞并进行相应补偿的算法。
POP Register
如果编译器无法保持安全调试顺序,或者对于选择不同布局的编译器,可以个别弹出每个被调用者保存的寄存器。4 位操作码后的前四位指示要弹出的寄存器数量。每个后续的 4 位半字节表示被调用者保存的寄存器的编码,或表示空洞 的特殊值 0xF。如果指示有空洞,则应递减虚拟 SP,但不应弹出寄存器。
4 位寄存器编码如下:
编码 | 寄存器 | 编码 | 寄存器 |
---|---|---|---|
0000 | A15 | 1000 | A14 |
0001 | B15 | 1001 | A13 |
0010 | B14 | 1010 | A12 |
0011 | B13 | 1011 | A11 |
0100 | B12 | 1100 | A10 |
0101 | B11 | 1101 | 被保留 |
0110 | B10 | 1110 | 保留 |
0111 | B3 | 1111 | “空洞” |
MV FP, SP
此指令从 FP (A15) 恢复 SP,而不是递增 SP。当 FP 可用时,只需从 FP 恢复 SP 值会容易一些。对于 DATA_MEM_BANK 布局,这可能是恢复 SP 的唯一方法。
_ _C6000_pop_rts
此指令指示所有寄存器恢复都通过调用 _ _C6000_pop_rts 来完成。此函数的行为应由展开程序进行模拟。_ _C6000_pop_rts 隐式恢复 B3 并执行 RET B3。
恢复 B3
如果 r 表示 B3 以外的任何寄存器,则此指令对用于从“reg”恢复 B3 的“MV reg, B3”进行编码。如果 POP 会覆盖寄存器,则必须在任何 POP 指令之前执行此操作。
RET B3
此指令对模拟的 return 进行编码,表示此帧的展开已完成。请注意,编码与“恢复 B3”相同,但源寄存器指示为 B3 本身。
每个展开指令序列都以显式或隐式“RET B3”结束。可以从显式展开指令中省略此指令,展开程序将隐式添加它。