常用汇编
汇编只不过是机器代码的美化宏语言。 汇编指令与实际机器代码之间存在一对一的关系,汇编使用助记符来处理器所能够运行的操作,这比原始二进制文件更容易记忆。 将asm代码Assembly Code
转换为机器代码的工具是汇编程序。
每个处理器都会进行的操作:算术
(加减乘除),位操作
每个处理器都会有的能力:访问内存
,内存跳转
。
但是每个处理器,都有不同的方法来做这些工作
ARM没有除法指令
、并且不能在内存上直接处理数据
。
但是,ARM有大量通用寄存器
和简单指令集
,还有优秀的处理位转移方式
add r0, r0, #2 //加立即数,r0 += 2
add r0, r0, r1 //加寄存器,r0 += r1
add r0, r1, r2 //加多个寄存器, r0 = r1 + r2
//ldr 类似x86里的MOV
ldr r0, [r1] //从内存中加载int,r0 = r1[0]
ldr r0, [r1, #4] //从内存中加载下一个int,r0 = r1[1]
ldmia r2, {r0, r1} //多次加载,r0 = r2[0], r1 = r2[1]
在高级语言HLLs
中,使用变量
,在汇编中使用寄存器
,变量
(特定范围的内存),栈
寄存器是芯片的内置变量
,所以访问速度最快
,但数量有限
。内存临近
芯片,速度仅次于寄存器,而且空间很大,所以将变量放在内存里,访问变量就是访问内存。
寄存器和变量都是全局属性
,想要操作局部变量,使用栈。
栈Stack
-
Stack Point(SP)寄存器
包含栈顶的地址函数调用1.png - 栈用完之后需要清理,从而保证栈针用之前后用之后,指向一个位置,否则
例子
:加入存在一个函数FOO,它会使用寄存器A,B,C,D,同时会调用函数BAR,但是BAR也将使用A、B、C。分析
:因为BAR也会使用到寄存器A、B、C,为了不打扰FOO的使用,BAR首先将A,B,C的原始值压入堆栈,使用完之后,返回给寄存器A,B,C,让FOO接着使用
//函数FOO
FOO:
//将A,B,C,D 压入堆栈,保存他们的原始值
push {A, B, C, D}
mov A, #1
mov B, #2
mov C, #3
call BAR
//global_var0 is 14 from BAR
mov D, global_var0
//global_var1 = A+B+C = 20
add A, B //A = A+B = 3
add A, C //A = A+C = 6
add A, D //A = A+D = 20
mov global_var1, A //global_var1 = 20
//恢复A,B,C,D
pop {A-D}
return
//函数BAR
BAR:
//此时,A=1, B=2, C=3
push {A-C}
mov A, #2 //A = 2
mov B, #5 //B = 5
mov C, A //C = 2
add C, B //C = B + A = 7
//global_var0 = 2*C = A+B+C;全局变量global_var0,一个内存地址
add C, C //C = 14
mov global_var0, C
//恢复A, B, C
pop {A-C}
return
这段代码中,只是实现了global_var0、global_var1这两个内存变量的赋值
分支和条件代码 Branching and condition codes
-
PC
(程序计数器program Counter): 指向下一条指令的地址
正常情况下:执行到PC时,读取他的值,然后给他一个增量,让他指向下一个命令,这是一个相对直线的过程,他十一个比较规律的值
但是,如果出现条件语句
,或者直接跳转
,重定向这个程序的执行流程,PC会指向一个完全不规律的地址,技术术语(technical term)是分支branching
,对于分支的助记符(mnemonic)是b或者j(jump)
endless:
..... //代码块
b endless //跳转到无限循环的代码块去
但是,只有存在条件并且可以实现的分支才是完整的分支,这些条件依赖
处理器
Zero(Z) :操作的结果为0
Negative(N) :操作的结果是负数
Carry bit set(C) :进位设置,如果mostest
有效位被设置
Arithmetic overflow :算数溢出,例如:两个正数相加得到一个负数
这些标志位flags,都存储在Program status Register(PSR)
程序状态寄存器,每一个数据操作指令根据操作的结果,设置这些标志位中的一个或多个
//汇编程序的描述是: for (int i=0; i != 16; i++)
mov A, #0 //A = 0
//循环体
loop_start:
... //循环体内的代码
add A, #1 //A += 1
//compare A to 16,实际上会进行减法,来更改Z(Zero)
cmp A, #16
//branch if not equal,如果不相等就跳转
//其实这里也是根据Z标志位,来跳转
bne loop_start
条件代码(i.e. cmp,ne...)的数量取决与平台,ARM只有16个