Assembly ARM寄存器的功能

Assembly ARM寄存器的功能,assembly,arm,microprocessors,Assembly,Arm,Microprocessors,我对手臂注册有一些疑问 r12的主要目标是什么?在其他体系结构中是否与FP相同 其中一些用于“暂存”,这是否意味着临时存储/调用方保存 r13和r14具有不同的名称,具体取决于模式。如果我使用#MOV R0,R14_svc,我会在R0中得到它的内容吗?或者这只是在不同模式下区分R14的一种方法,而没有硬件差异 您看到的是结果,而不是症状 访问arms网站(infocenter.arm.com)并查找armv5的arm体系结构参考手册,您可能必须放弃电子邮件地址,但这些地址很容易获得,没什么大不

我对手臂注册有一些疑问

  • r12的主要目标是什么?在其他体系结构中是否与FP相同
  • 其中一些用于“暂存”,这是否意味着临时存储/调用方保存
  • r13和r14具有不同的名称,具体取决于模式。如果我使用#MOV R0,R14_svc,我会在R0中得到它的内容吗?或者这只是在不同模式下区分R14的一种方法,而没有硬件差异

您看到的是结果,而不是症状

访问arms网站(infocenter.arm.com)并查找armv5的arm体系结构参考手册,您可能必须放弃电子邮件地址,但这些地址很容易获得,没什么大不了的

因此,有arm指令集和与之配套的arm体系结构。有些寄存器是特殊的,有些则不是。显然,r15非常特殊,它是程序计数器,有些指令的寻址模式仅支持r15(pc相对寻址)。同样,r14是特殊的,它也是硬连线的分支链接指令,返回是通用的,但调用不是,确保您可以在不使用r14的情况下进行调用,但这并不重要r14是特殊的,因为它硬连线到一个/一些指令上

在thumb模式下,r13硬编码到push和pop指令中(在arm模式下,ldm和stm技术上可以使用任何寄存器,尽管r15可能是个坏主意)

也许还有其他人

因此,一些寄存器硬连接到一些指令或寻址模式中。因此,除此之外,可能出于性能原因,还有不同的处理器模式、管理器、中断等。arm文档向您展示了其中一些寄存器具有_svc版本或_und版本等。是的,r14 _svc位与r14 _abt不同,如果修改r14\u abt,则无法使用r14\u svc或r14\u irq读回数值。根据处理器模式,当特定指令读写r14或r13等时,会选择不同的寄存器组,并使用特定于模式的寄存器组。对于r0-r7,所有模式都使用相同的实际寄存器/位/ram,但从r8开始,要知道使用了哪些寄存器,必须查看该模式。根据手臂的不同,这种说法可能有所不同,但我现在看到的说法是:

ARM处理器共有37个寄存器:

它们向你展示了r0-r15的图片,加起来是37,而不是16,因为它们是独立的寄存器

现在,您进入了一个与硬件完全无关的呼叫约定,它只是一个习惯或一个人们已经同意使用的约定。如果您跳上wayback机器,您可能会了解到一些x86编译器使用基于堆栈的参数传递,一些使用基于寄存器的,它们彼此不兼容,有时您可以指定在编译时使用哪种约定。其他一些人也是如此,但并非所有人都是如此。如果您查看mips文档,那里的硬件人员喜欢通过根据约定重命名寄存器来定义调用约定,这不是用硅刻的,您不必遵守它。与体系结构手册以外的其他地方定义的arm调用约定相同,因为这毫无意义,但它是在某个地方定义的,编译器编写人员是否为arm工作,是否符合这些标准,甚至在arm更改约定时也会更改,这是非常明智的

这是您开始看到使用r0-r3传递参数的惯例的地方,然后在这些参数被消耗之后,您使用堆栈,如果您的计算机觉得需要一个帧指针(懒惰的程序员,更容易调试编译器输出),他们会选择r12或其他什么。该约定定义了函数需要保留的寄存器和不需要保留的寄存器,并定义了如何返回值。尽管该约定在某些方面是任意的,并且如果您正在制作自己的编译器,您可以发明自己的或一直使用堆栈,而不是注册等,但您可能使用的编译器在其一个不断发展的版本中符合arm调用约定(abi/eabi)

是的,这就是为什么一个或多个上层寄存器没有保留在约定中,以便在需要帧指针时可以将其用作帧指针

什么意思?如果你看一看那些寄存器较少、编译器不太成熟、堆栈参数传递较少的旧日子,你基本上保留了进入函数时要接触的每个寄存器,并在退出时恢复它们,你修改的内容(返回值)在堆栈上,或者你在函数中使用堆栈顶部的易失性内容(局部变量、中间值等)。即使有16个寄存器,您也可以开始讨论使用寄存器进行参数传递,甚至可以制定一个不必保留所有寄存器的约定。这就是arm约定和其他一些约定的作用

unsigned int fun ( unsigned int a, unsigned int b )
{  
  return(a+b+7);
}
a将被传递到寄存器r0中的函数,b在寄存器r1中,因为约定是这样说的。返回值在r0中,因为约定是这样说的,所以代码的优化版本将是要么通过添加7来销毁r0,这样a值就消失了,从代码中我们可以看出,我们只需要a值足够长的时间来保存d用它做一个数学运算,这样我们就可以

r0 = r0 + 7;
r0 = r0 + r1;
返回

或者我们可以

r1 = r1 + 7;
r0 = r0 + r1;
return
或主题的其他变体。在上述任何一种情况下,我们都没有保留r0,因为公约基本上规定我们必须销毁内容,因为这是我们的回报。但我们也可以至少修改r0、r1、r2、r3,因此我们也可以这样做:

r2 = r1+7;
r3 = r2+r0;
r0 = r3;
return
这将是合法的,因为除了我们,没有人关心我们与r0-r3(有时还有其他人)的关系

如果你这么做了

r4 = r1+7;
r0 = r0 + r4;
return
你可能会很幸运,不会崩溃,或者你可能会以正确的方式崩溃,或者可能不会崩溃很长时间
push {r4}
r4 = r1+7;
r0 = r0 + r4;
pop {r4}
return
unsigned int fun ( unsigned int a, unsigned int b )
{  
  return(more_fun(a,b)+a+b+7);
}
push {r4,r14}
r4 = r0 + r1;
r4 = r4 + 7;
call more_fun();
r0 = r0 + r4;
pop {r4,r14}
return