| Arm指令集介绍 崇尚简单粗暴的介绍方式,我们直接来看各个寄存器的大体用法,详细用法可百度,不,谷歌。
 
 1.    r0-r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。---如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。2.    r4-r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。r11 是栈帧指针 fp。3.    r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。4.    寄存器 r13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。5.    寄存器 r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复6.    寄存器 r15 是程序计数器 pc。它不能用于任何其它用途。演示代码
 假如现在你已经掌握了 arm 指令的用法,即便没有掌握也没关系,“书到用时回头翻”。这里以一段简单的 c 语言为例:
 代码语言:javascript
 复制
 
 
 #include .h= ;int (,int b{    int c 0= a ;    ;main)= ;    int j 5= (i)return ;编译一下,然后反汇编:
 $ arm-linux-gnueabi-gcc main.c -o main $ arm-linux-gnueabi-objdump -D -D main代码语言:javascript
 复制
 
 
 <fun:   :       e52db004        push    }            (str fp[sp-])   :       e28db000        add     fp, #10408, sp20   1040c, , #1610410, , #20; 10414, #10418, , #8:       e51b2010        ldr     r2[fp-]   :       e51b3014        ldr     r3[fp-]  0xffffffec   :       e0823003        add     r3, r3   :       e50b3008        str     r3[fp-]   1042c, , #810430, r3   :       e24bd000        sub     sp, #10438{fp; , ]4:       e12fff1e        bx      lr<main:   :       e92d4800        push    , lr10444, sp4   :       e24dd008        sub     sp, #:       e3a03004        mov     r34   :       e50b300c        str     r3[fp-]   :       e3a03005        mov     r35   :       e50b3008        str     r3[fp-]   1045c, , #810460, , #121046410400 >   :       e1a02000        mov     r2:       e59f3010        ldr     r3[pc16; <main0x4410470, ]   :       e3a03000        mov     r30   :       e1a00003        mov     r0:       e24bd004        sub     sp, #10480{fp}   :       , r2, lsr #如何能让读者接受吸收的更快,我一直觉得按照学习效率来讲的话顺序应该是视频,图文,文字。反正我是比较喜欢视频类的教学。这里给大家画下栈变化的过程是什么样子的。这里的图是结合上面的代码来画的,希望有助于读者的理解。1.程序在内存分布区域
 
  
 
 
 2.全局变量m赋值  
 
 3.保存进入main之前的栈底, fp-sp之间是当前函数栈
 
  
 
 4.函数main的栈已经准备好了
 
  
 
 5.i入栈
 
  
 
 6.j入栈
 
  
 
 7.准备函数fun的调用, 形参反向入栈 先形参b入栈
 
  
 
 8.形参a入栈
 
  
 
 9.留空一个地址作为fun返回值, 待后面返回时填入
 
  
 
 10.fun返回地址入栈, 通常是main函数当前pc指针的下一个
 
  
 
 11.main函数的栈底地址入栈
 
  
 
 12.pc指针跳转fun代码
 
  
 
 13.c入栈
 
  
 
 14.可以看到函数fun的数据 形参a,b 在上一层函数的栈中. 一部分在自己的栈上. 此步取值到加法器中进行加法运算,再赋值给c
 
  
 
 15.c赋给返回值,填入上面的留空位置
 
  
 
 16.栈底恢复上一层
 
  
 
 17.lr赋值给pc, 实现了跳转
 
  
 
 18.返回值赋值给全局变量m
 
  
 
 19.前面函数调用的形参已经无用,回滚sp
 
  
 
 20.函数返回,清理main的栈空间
 
  
 
 
 
 
 |