我对ARM有点陌生,我正在尝试理解指令是如何解释/执行的:
据我所知,在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的指针在哪里,它是不是还有两条指令?
发布于 2020-03-10 18:36:14
我们大多数人不知道/不会确切地知道它是如何在逻辑中实现的(并且有不同的核心,所以每个核心可能是不同的)。但是,过去未定义的指令在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,执行。处理器grabs 0x4006有它需要执行的东西。grabs 0x4008有它需要执行的东西。grabs 0x400A发现它需要另一个半字,grabs 0x400C执行。
这些位模式以前是未定义的指令,现在它们是可变长度指令定义的一部分。就像以0b010000开头的指令是数据处理指令一样,要确定它是加法还是异或,您必须查看其他位。这些位模式定义了thumb-2扩展,然后这两个半字中的其他位定义了完整的指令。
为什么会出现这样的位模式?如果你愿意,你可以认为它是任意的,所有的指令集都有人(/group)坐下来,决定什么位模式将意味着什么,这里没有什么不同。指令集空间中有特定模式的空间,因此这些模式被使用。在处理器家族的后期添加指令并不少见,以x86为例。再加上许多其它的,对于像x86或6502之类的8位指令/操作码,你可以使用8位指令/操作码作为你的下一个新指令,或者你把以前未使用的字节/操作码扩展成更多。例如,你拿一个未使用的字节/操作码,那个字节现在意味着看下一个字节,下一个字节可以是256条新指令,或者它可以简单地补充第一个字节,指定寄存器或操作等。这里没有什么不同,沿着路的手臂扩展了thumb指令集,消耗了一定百分比的指令,这表明这是一个可变长度指令,但在这32位中,仍然有相当多的位,以允许具有更多选项的更大指令。(但失去了thumb和arm指令之间的一对一关系,所有thumb指令(不是thumb-2扩展)直接映射到完整大小的arm指令)。
每个内核都是不同的,它们不是每次都提取一个字,thumb-2扩展不必对齐,因此对于执行字提取的处理器来说,整个thumb-2指令不一定适合对齐的字提取。把(Pre)抓取器和解码器看作是两个独立的东西,既然它们是,功能上解码器在thumb模式下一次取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是明智的方法。
https://stackoverflow.com/questions/60610931
复制相似问题