Assembly 程序集分支/循环和函数是如何工作的

Assembly 程序集分支/循环和函数是如何工作的,assembly,arm,Assembly,Arm,今天刚上了第一课组装课。演讲者没有解释太多,因为他们的想法是,我们必须用书本来了解装配是如何工作的。我的编程背景是Python和C++,并且考虑到汇编,它甚至会感到不安,甚至会考虑来回跳转到代码中。p> 当谈到分支时,一个问题一直困扰着我,在我的书中似乎没有解释。基本上,操作代码B+(EQ、PL等)根据条件和标志进行分支。例如,“BEQ位置”将分支到“位置”,如果……也就是说,如果什么。根据我的理解,它使用前面的指令来计算条件(在本例中,如果某个值相等(Z=1))。如果BEQ会查看之前指令的返回

今天刚上了第一课组装课。演讲者没有解释太多,因为他们的想法是,我们必须用书本来了解装配是如何工作的。我的编程背景是Python和C++,并且考虑到汇编,它甚至会感到不安,甚至会考虑来回跳转到代码中。p> 当谈到分支时,一个问题一直困扰着我,在我的书中似乎没有解释。基本上,操作代码B+(EQ、PL等)根据条件和标志进行分支。例如,“BEQ位置”将分支到“位置”,如果……也就是说,如果什么。根据我的理解,它使用前面的指令来计算条件(在本例中,如果某个值相等(Z=1))。如果BEQ会查看之前指令的返回值来计算EQ,那么我如何做一个循环,第一个R0(寄存器0)得到值0,然后发生其他事情,最后我会做一个条件分支来检查R0是否为零

问题2: 我还注意到,如果您正在制作某种函数:

WhileLoop:
     MOV R0, R1
     ..bla bla bla
     BEQ WhileLoop
我怎么知道BEQ回到了“WhileLoop”?这是否意味着对于我所做的每个函数,我都需要将其称为不同的函数。也许我没有正确理解函数


请提供帮助。

您需要阅读ARM文档。你的问题的答案就在那里

是的,手臂使用旗子。与使用标志的任何指令集一样,您需要检查正在使用或希望使用的每一条指令,或者为了一般理解,查看它们是否修改了任何标志。例如,一个操作,设置进位标志有意义吗?没有,但是设置零标志有意义吗?当然,这可能有用,或者有时他们TST设置了零标志,但是没有,这取决于架构

与典型的基于标志的解决方案不同,ARM有一段时间出现了扭曲,您必须请求指令设置标志。如果你注意到

loop:
  sub r0,#1
  bne loop
不做您希望它做的事情,因为正如所写的(根据arm文档),减法dos不接触任何标志,特别是我们正在测试的Z标志,但是

loop:
  subs r0,#1
  bne loop
此代码中,减法不接触Z标志

它允许像这样的事情

  cmp r2,r3
  moveq r1,#1
  bxeq lr
  mov r1,#0
  bx lr
或者说

  if(foo==1)
  {
     bar++;
  }
通常情况下,您需要将其实现为

compare with 1
branch if not equal to skip
increment
skip:
所以你有一个烟斗,也许会被树枝击中

而是

compare with 1
increment if equal
条件执行,条件位

现在这是全尺寸手臂指令,拇指指令是另一回事

在64位指令集aarch64中,所有的条件都消失了,每一条用于条件执行的指令都会烧掉4位,这有点痛苦,使用得不够。他们本可以有32个通用寄存器,而这可能更有用

所以,不确定您对函数的要求是什么,首先在汇编语言中,您可以经常使用像WhileLoop这样的标签。汇编程序将其转换为正确的指令,而LOOP不是一条指令,它基本上是一个地址,在这种情况下,汇编程序应该使用您要求的指令并进行pc相对偏移(不使用固定地址,它计算标签和beq之间的指令数,并表示是否等于反向分支N条指令)。如果将beq放在某个标签上,并且该标签是在另一个模块/对象中定义的,则链接器随后必须修补该指令

就函数而言,如果用C编写一个程序,我想做几个指令,我需要使所有函数名都不同吗?是的。汇编中真的没有函数这样的东西,有一些指令给人一种错觉,但它只是一个花哨的标签。但是如果你想的话,代表函数的代码写7个是的,你需要为每一个使用不同的标签。汇编语言与此无关

gnu汇编程序有一个有趣的特性,没有理由假定其他汇编语言支持它(汇编语言是由汇编程序、工具而不是目标(ARM指令集)定义的),非常容易为许多不同的指令集演示这一点,很容易编写arm汇编程序,它不会在所有受积极支持的汇编程序中进行汇编。因此,这里有一个gnu汇编程序技巧,它可能对您的标签有帮助,也可能没有帮助

1:
 subs r0,#1
 beq 1f
 b 1b
1:
你通常只想做bne,但这说明了它的功能。一个数字标签是特殊的1f表示标签1:向前,所以下一个标签1:沿着页面向下。1b表示1:向后,所以从这一点开始,向上阅读页面以找到下一个1:所以你不必这样做

myfunction:
...
myfunction00:
...
myfunction01:
...
myfunction02:
...
因为您正努力制作中间标签来处理填充和循环上的简单分支


您可以选择它是一个功能还是一个负担,因为它创建的习惯可能是特定于工具的,也可能不是特定于工具的。

1)标志是程序状态寄存器中的位。它们不一定由前面的指令设置。另请参见2)是的,全局标签必须是唯一的。您的汇编器可能支持某种形式的局部变量标签。re:汇编中的结构化编程:只要您编写与高级结构化编程相对应的循环和分支,就可以使事情保持简单,而不是意大利面代码。有关结构化编程规则(如no GOTO)试图避免的混乱类型的更多信息,请参阅。您甚至可以在asm中添加注释,如
@do{
@}(condition)
,以跟踪您使用分支实现的结构化循环或if()构造的类型。有关注释简单循环的示例,请参见。(x86,但在ARM中工作原理相同。)CPU本身拥有有限数量的单元,这些单元包含0/1信息=寄存器、程序计数器、状态寄存器(有时称为“标志”),其他所有内容都存储在这些单元中,因此了解这些单元的全部内容是非常必要的