检测 Thumb-2 指令和 PC 偏移位置
Detecting Thumb-2 instruction and location of PC offset
我是 ARM 的新手,我正在尝试了解指令是怎样的 interpreted/executed:
据我所知,在 ARM 上非常简单,因为每条指令占用 4 个字节,并且所有指令也都按 4 个字节对齐。
Thumb-2 有问题,它们的指令可能都是 16/32 位长。我读过为了确定当前指令是否为 16/32 位长,处理器读取一个字(32 位)并评估某些位 [15:11] 上的第一个半字。如果这些位是 0b11101/0b11110/0b11111 那么该半字是 32 位指令的第一个半字,否则它是 16 位指令(我不太明白为什么这些特定字节决定了这一点)。所以一个例子应该是:
0x4000 16-bit
0x4002 32-bit
0x4006 16-bit
0x4008 16-bit
0x400a 32-bit
然后处理器应该从 0x4000 抓取到 0x4004,评估第一个半字(0x4000 到 0x4002)如果指令是 16 位那么它就跳到下一个半字并重复这个过程但是如果半字表示 32 位地址然后它跳过下一个半字并执行该 32 位指令?
此外,我对 thumb-2 中的 PC 指向何处感到困惑,是否还有两条指令?
我们大多数人不t/won不知道它在逻辑中是如何实现的(并且有各种内核,所以每个内核都可能不同)。但是以前未定义的指令在 armv6-m 中变成了 thumb-2 扩展,然后在 armv7-m 中变成了 150 个新指令。
想想处理器获取 16 位指令,有时它会运行一个可变长度的指令。就像其他可变长度处理器一样,x86 将查看单字节指令,然后基于它可能需要也可能不需要查看下一个字节等等,直到它解析了整个指令。同样在这里,它会查看一个半字来确定它是否拥有所需的一切,如果没有,它会抓住下一个半字来获取其余信息。
0x4000 16-bit
0x4002 32-bit
0x4006 16-bit
0x4008 16-bit
0x400a 32-bit
处理器获取 0x4000,看到它有它需要的东西,然后执行。处理器获取 0x4002,发现它需要另一个半字,获取 0x4004,执行。处理器抓取 0x4006 有它需要执行的东西。抓取 0x4008 有它需要执行的内容。抓取 0x400A 发现它需要另一个半字,抓取 0x400C,执行。
那些位模式以前是未定义的指令,现在它们是可变长度指令定义的一部分。就像以 0b010000 开头的指令是数据处理指令一样,要确定它是加法还是异或,您必须查看其他位。这些位模式定义了 thumb-2 扩展,然后这两个半字中的其他位定义了完整指令是什么。
为什么是这些位模式?如果你愿意,你可以认为它是任意的,所有指令集都有人(/组)坐下来决定什么位模式意味着什么,这里没有什么不同。指令集 space 中有特定模式的空间,因此使用了这些模式。在处理器系列的生命后期添加指令并不少见,以 x86 为例。加上许多其他的,对于像 x86 或 6502 之类的 8 bitter 或任何你可以使用 8 bit instruction/opcode 作为你的下一个新指令,或者你将以前未使用的 byte/opcode 扩展为更多例如你拿一个未使用的 byte/opcode ,那个字节现在意味着查看下一个字节,下一个字节最多可以是 256 条新指令,或者它可以简单地补充指定寄存器或操作等的第一个字节。这里没有什么不同,在这条路上,手臂扩展了拇指指令集,消耗了一定百分比的指令,表明这是一条可变长度指令,但在这 32 位中,仍然有相当多的位允许更大的指令和更多的选项。 (但失去了拇指和手臂指令之间的一对一关系,所有拇指指令(不是 thumb-2 扩展)直接映射到全尺寸手臂指令)。
每个核心都不同,它们不会一次都取一个字,thumb-2 扩展不必对齐,因此整个 thumb-2 指令不一定适合处理器的对齐字取做取词。将(预)取器和解码器视为两个独立的东西,因为它们在功能上解码器在拇指模式下一次需要 16 位,它是如何具体实现的?不知道。在解码第一个之前,他们是否等待两个半字准备就绪?不知道。每个实现都一样吗?不知道,希望不会。就获取而言,它们与您在 ARM 文档中看到的不同,我认为芯片供应商至少可以在编译时选择一个(如果不是更多的话)。
如果您来自例如基于 MIPS 的教科书并试图了解其他处理器,这可能会造成混淆,请理解这些教科书和术语是为了理解和词汇,流水线通常没有那么深,您通常不要一次获取整个指令(x86 不会一次获取一个字节,它会一次获取许多指令)。 risc-v 的问题比 arm 和 mips 更糟糕,因为你可以有 16 位压缩指令、32 位指令和 64 位指令,32 位指令不必在 risc-v 上对齐(64 位指令也不必对齐)位)所以一次获取 32 并不能得到完整的指令,获取器与解码器是分开的,一旦足够,解码器就可以完成。
我想说 thumb 领先两个(独立于 thumb2 扩展或不)所以 pc+4,应该很容易弄清楚。
Disassembly of section .text:
00000000 <hello-0xe>:
0: e005 b.n e <hello>
2: bf00 nop
4: bf00 nop
6: f000 b802 b.w e <hello>
a: bf00 nop
c: bf00 nop
0000000e <hello>:
e: bf00 nop
是的,所以在这两种情况下都提前了两个拇指大小的半字 (pc+4)。如果前面有两条指令,情况会复杂得多,这就是过去为了便于记忆而采用的方式。如果前面有两条指令,那么有时是 pc+4,有时是 pc+6,有时是 pc+8 逻辑必须解码两条指令才能知道 pc 如何偏移两条指令中的第一条,所以坚持使用 pc +4 一直以来都是拇指模式,这是明智的做法。
我是 ARM 的新手,我正在尝试了解指令是怎样的 interpreted/executed:
据我所知,在 ARM 上非常简单,因为每条指令占用 4 个字节,并且所有指令也都按 4 个字节对齐。
Thumb-2 有问题,它们的指令可能都是 16/32 位长。我读过为了确定当前指令是否为 16/32 位长,处理器读取一个字(32 位)并评估某些位 [15:11] 上的第一个半字。如果这些位是 0b11101/0b11110/0b11111 那么该半字是 32 位指令的第一个半字,否则它是 16 位指令(我不太明白为什么这些特定字节决定了这一点)。所以一个例子应该是:
0x4000 16-bit
0x4002 32-bit
0x4006 16-bit
0x4008 16-bit
0x400a 32-bit
然后处理器应该从 0x4000 抓取到 0x4004,评估第一个半字(0x4000 到 0x4002)如果指令是 16 位那么它就跳到下一个半字并重复这个过程但是如果半字表示 32 位地址然后它跳过下一个半字并执行该 32 位指令?
此外,我对 thumb-2 中的 PC 指向何处感到困惑,是否还有两条指令?
我们大多数人不t/won不知道它在逻辑中是如何实现的(并且有各种内核,所以每个内核都可能不同)。但是以前未定义的指令在 armv6-m 中变成了 thumb-2 扩展,然后在 armv7-m 中变成了 150 个新指令。
想想处理器获取 16 位指令,有时它会运行一个可变长度的指令。就像其他可变长度处理器一样,x86 将查看单字节指令,然后基于它可能需要也可能不需要查看下一个字节等等,直到它解析了整个指令。同样在这里,它会查看一个半字来确定它是否拥有所需的一切,如果没有,它会抓住下一个半字来获取其余信息。
0x4000 16-bit
0x4002 32-bit
0x4006 16-bit
0x4008 16-bit
0x400a 32-bit
处理器获取 0x4000,看到它有它需要的东西,然后执行。处理器获取 0x4002,发现它需要另一个半字,获取 0x4004,执行。处理器抓取 0x4006 有它需要执行的东西。抓取 0x4008 有它需要执行的内容。抓取 0x400A 发现它需要另一个半字,抓取 0x400C,执行。
那些位模式以前是未定义的指令,现在它们是可变长度指令定义的一部分。就像以 0b010000 开头的指令是数据处理指令一样,要确定它是加法还是异或,您必须查看其他位。这些位模式定义了 thumb-2 扩展,然后这两个半字中的其他位定义了完整指令是什么。
为什么是这些位模式?如果你愿意,你可以认为它是任意的,所有指令集都有人(/组)坐下来决定什么位模式意味着什么,这里没有什么不同。指令集 space 中有特定模式的空间,因此使用了这些模式。在处理器系列的生命后期添加指令并不少见,以 x86 为例。加上许多其他的,对于像 x86 或 6502 之类的 8 bitter 或任何你可以使用 8 bit instruction/opcode 作为你的下一个新指令,或者你将以前未使用的 byte/opcode 扩展为更多例如你拿一个未使用的 byte/opcode ,那个字节现在意味着查看下一个字节,下一个字节最多可以是 256 条新指令,或者它可以简单地补充指定寄存器或操作等的第一个字节。这里没有什么不同,在这条路上,手臂扩展了拇指指令集,消耗了一定百分比的指令,表明这是一条可变长度指令,但在这 32 位中,仍然有相当多的位允许更大的指令和更多的选项。 (但失去了拇指和手臂指令之间的一对一关系,所有拇指指令(不是 thumb-2 扩展)直接映射到全尺寸手臂指令)。
每个核心都不同,它们不会一次都取一个字,thumb-2 扩展不必对齐,因此整个 thumb-2 指令不一定适合处理器的对齐字取做取词。将(预)取器和解码器视为两个独立的东西,因为它们在功能上解码器在拇指模式下一次需要 16 位,它是如何具体实现的?不知道。在解码第一个之前,他们是否等待两个半字准备就绪?不知道。每个实现都一样吗?不知道,希望不会。就获取而言,它们与您在 ARM 文档中看到的不同,我认为芯片供应商至少可以在编译时选择一个(如果不是更多的话)。
如果您来自例如基于 MIPS 的教科书并试图了解其他处理器,这可能会造成混淆,请理解这些教科书和术语是为了理解和词汇,流水线通常没有那么深,您通常不要一次获取整个指令(x86 不会一次获取一个字节,它会一次获取许多指令)。 risc-v 的问题比 arm 和 mips 更糟糕,因为你可以有 16 位压缩指令、32 位指令和 64 位指令,32 位指令不必在 risc-v 上对齐(64 位指令也不必对齐)位)所以一次获取 32 并不能得到完整的指令,获取器与解码器是分开的,一旦足够,解码器就可以完成。
我想说 thumb 领先两个(独立于 thumb2 扩展或不)所以 pc+4,应该很容易弄清楚。
Disassembly of section .text:
00000000 <hello-0xe>:
0: e005 b.n e <hello>
2: bf00 nop
4: bf00 nop
6: f000 b802 b.w e <hello>
a: bf00 nop
c: bf00 nop
0000000e <hello>:
e: bf00 nop
是的,所以在这两种情况下都提前了两个拇指大小的半字 (pc+4)。如果前面有两条指令,情况会复杂得多,这就是过去为了便于记忆而采用的方式。如果前面有两条指令,那么有时是 pc+4,有时是 pc+6,有时是 pc+8 逻辑必须解码两条指令才能知道 pc 如何偏移两条指令中的第一条,所以坚持使用 pc +4 一直以来都是拇指模式,这是明智的做法。