ARM-Linux嵌入式汇编笔记
来源:互联网 发布:mmd的动作数据 编辑:程序博客网 时间:2024/06/06 03:48
1 嵌入式结构
Arm公司只设计处理器架构,Arm1 Arm2 …. Arm6
除arm外的芯片
2 ARM架构
2.1 结构
SOC=CPU(arm)+总线+控制器i5--PIC-E--桥(芯片组)ARM=arm_core 执行arm指令,哈弗结构 cache 高速缓存 I-cache 缓存代码 D-cache 缓存数据 TCM 要求访问速度高的,可以存在这里 I-tcm 存代码 D-tccm 存数据
2.2 协处理器
2.3 寄存器
r13~r15不要随便用,所有函数按1、2、3的顺序执行,保证调用函数之后能够正确返回
1、LR->SP2、SP->LR3、PC=LR
2.4 指令集
arm-cortex-m 只支持thumb thumb2
2.5 七种工作模式
普通模式:user 只能修改NZCVQ
特权模式:system,svc,unde,abort,irq,fiq
异常模式:svc,unde,abort,irq,fiq 每个异常模式都有自己的r13,r14,SPSR
模式切换:CPSR[NZCVQ EAIFT M[4:0]] N 负操作1,否则0 Z 零操作1,否则0 C 加法,如果有进位1,否则0 减法,如果有借位0,否则1 V 有溢出1,否则0 Q 有饱和1,否则0 E 如果小端0,否则1 A 中止禁止位,如果为1则禁止了中止异常 I 中断禁止位 F 快速禁止位 T 如果执行的thumb指令则位2,否则为0 M[4:0] 只有特权模式可以写
3 ARM汇编,在C中嵌套汇编
int main(void){ int a = 100; int b = 30; int c = 50; //假设前面有C代码,把一个数放进r0,自己写的汇编改变了r0的值,这就出问题,所以自己使用前要存下r0的值 //使用完后恢复它,在保护寄存器行写一下就可以 __asm__ __volatile__( "mov %0,#20\n" //把a的值改为20,%0代表a,不能直接写20,不然会认为是地址,加个#号 "mov r0,#123\n" //把r0寄存器的值赋值123,汇编指令都要\n结尾 "mov %1,r0\n" "mov r1,%2\n" "mov %0,r1\n" :"=&r"(a),"=&r"(b) /** * 声明输出变量(只能写不能读)和输入输出变量,第一个声明的是%0, * 第二个是%1,=是输出变量,+是可读可写变量,&是独占寄存器,r代表是寄存器, * =后记住加& */ :"r"(c) //声明输入变量,只能读不能写 :"r0","r1" //保护寄存器,使用寄存器之后还原原来寄存器的值 ); printf("hello asm %d %d %d\n",a,b,c); /** * out = in_out; * in_out = in; */ int in_out = 200; int out; int in = 52; asm volatile( "mov %0,%1\n" "mov %1,%2\n" :"=&r"(out),"+r"(in_out) :"r"(in) : ) printf("hello asm out=%d in_out=%d\n",out,in_out); int d,f,e; asm volatile( "mov %[d],#1\n" "mov %[f],#2\n" :[d]"=&r"(d),[e]"=&r"(e),[f]"=&r"(f) //可以直接指定每个变量的标号,就可以用%0,%1这种方式访问 //在""前加[随便字符串]即可,解决添加变量在中间后序号改变 : : ) printf("hello asm d=%d f=%d\n",d,f); //减法sub int g,h,i; asm volatile( "mov r0,#9\n" "mov r1,#8\n" //要实现g = r0-r1; "sub %0,r0,r1\n" :"=&r"(g) : :"r0","r1" ); printf("hello asm sub g=%d\n",g); /** * 32位处理器上进行64位减法,I存高位,H存低位 * 0x33333333 00000004 * 0x11111111 00000005 * 0x22222221 ffffffff */ asm volatile( "mov r0,#4\n" "mov r1,#5\n" //C减法,如果有借位,Clear C置0,反之Set C置1,看上面模式切换那里,sub加s表示需要借位 "subs %0,r0,r1\n" "ldr r0,=0x33333333" "ldr r1,=0x11111111" //%1 = r0-r1-!C "sbc %1,r0,r1\n" :"=&r"(h),"=&r"(i) : :"r0","r1" ); printf("sub = %#x%08X\n",i,h); //乘法 int mul; asm volatile( "mov r0,#3\n" "mov r1,#4\n" //mul的三个操作数必须都是寄存器,%0 = r0*r1 "mul %0,r0,r1\n" :"=&r"(mul) : :"r0","r1" ); printf("hello asm mul=%d\n",mul); asm volatile( "mov r0,#3\n" "mov r1,#4\n" "mov r2,#5\n" //mla %0 = r0*r1+r2 结果是17 //mls %0 = r0*r1-r2 结果是7 "mla %0,r0,r1,r2\n" :"=&r"(mul) : :"r0","r1","r2" ); printf("hello asm mul=%d\n",mul); /** * 条件执行,大多数的arm指令都支持 * thumb指令只有跳转指令才支持 * 大于gt,小于lt,等于eq,不等于ne,小于等于le,大于等于ge */ int k=5,m=6,l; asm volatile( "subs r0,%1,%2\n" //条件执行 "movgt %0,#1\n" //k-m>0则l=1 "moveq %0,#2\n" //k-m=0则l=2 "movlt %0,#3\n" //k-m<0则l=3 :"=&r"(l) :"r"(k),"r"(m) :"r0" ); printf("hello asm l=%d\n",l); //专门比较指令 asm volatile( "mov r0,#4\n" "mov r1,#5\n" //cmp指令加不加s都行 "cmp r0,r1\n" "movgt %0,#1\n" //r0>r1则l=1 "moveq %0,#2\n" //r0=r1则l=2 "movlt %0,#3\n" //r0<r1则l=3 :"=&r"(l) : :"r0","r1" ); printf("hello asm l=%d\n",l); //专门比较是否相等指令 asm volatile( "mov r0,#4\n" "mov r1,#5\n" //teq指令加不加s都行 "teq r0,r1\n" "moveq %0,#1\n" //r0=r1则l=1 "movne %0,#2\n" //r0!=r1则l=2 :"=&r"(l) : :"r0","r1" ); printf("hello asm l=%d\n",l); //判断某一个寄存器的某一位是否为0,此题输出1 asm volatile( //0xf0 = 1111 0000,从右边第0位开始数 "mov r0,#0xf0\n" //r0&(1<<4)按位与的操作,判断第四位是否为0 "tst r0,#(1<<4)\n" "moveq %0,#0\n" //如果等于0,输出0 "movne %0,#1\n" //如果不等于0,输出1 :"=&r"(l) : :"r0" ); /** * 逻辑运算 * and 两个是1才是1,其余都是0 * orr 有1个是1都是1 * eor 不同为1,相同为0 * bic * * mvn r0,#0xff 按位取反 * r0 = ~0x000000ff = 0xffffff00 * * 移位运算符<<向左移,>>向右移 * 需要移位的数字 << 移位的次数 * 例如: 3 << 2,则是将数字3左移2位 * 首先把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011,然后把该数字高位(左侧)的两个零移出 * 其他的数字都朝左平移2位 * 最后在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 1100 * 则转换为十进制是12。不溢出的情况下 * 相当于3*2的2次方 * 3*(2^2) = 12 */ int and,orr,eor,bic; asm volatile( "mov r0,#5\n" //0000..0101 "mov r1,#6\n" //0000..0110 //%0 = r0&r1 "and %0,r0,r1\n" "orr %1,r0,r1\n" "eor %2,r0,r1\n" "mov r0,#0xff" //想把第2位清零,从右边第0位开始数 "bic %3,r0,#4\n"//或者#4 = #(1<<2) :"=&r"(and),"=&r"(orr),"=&r"(eor),"=&r"(bic) : :"r0","r1" ); printf("hello asm and=%d orr=%d eor=%d bic=%x\n",and,orr,eor,bic); /** * lsl逻辑左移,lsr逻辑右移 * asr算术右移,ror循环右移 */ int lsl,lsr,asr,ror; asm volatile( "mov r0,#20\n" "mov %0,r0,lsl #1\n" //%0 = r0<<1 结果是40 "mov %0,r0,lsr #1\n" //%1 = r0>>1 结果是10 "mov r0,#-20\n" //20 = 0000...10100 -20 = 1000...10100 补码:1111...01100 //计算机中存的都是补码 "mov %2,r0,lsr #1\n" //逻辑右移一位得到0111...0110 "mov %3,r0,asr #1\n" //算术右移一位得到1111...0110 "mov r0,#0#ff\n" "mov %4,r0,ror #4\n" //把最低位循环4次移到最高位,得到0xf000000f :"=&r"(lsl),"=&r"(lsr),"=&r"(asr),"=&r"(ror) : :"r0", ); printf("hello asm lsl=%d lsr=%d asr=%d ror=%x\n",lsl,lsr,asr,ror); int n; //读CPSR asm volatile( "mrs %0,cpsr\n" :"=&r"(n) : : ); printf("cpsr = %#x\n",n); //CPSR中有NZCVQ EAIFT asm volatile( "mrs r0,cpsr\n" "orr r0,r0,#(1<<7)\n" "msr cprs,r0\n" //修改CPSR中的值,此时处于用户模式,只能修改NZCVQ这5位,这里修改了第7位,修改失败 : : :"r0" ); return 0;}
4 syscall
/* * 直接调用内核函数* 内核中为每一个系统调用有编号* 在<Linux_src>/arch/arm/include/asm/unistd.h中* fork 2* read 3* write 4*/int main(void){ char *s = "hell syscall\n"; int ret; write(1,s,strlen(s)); syscall(4,1,s,strlen(s)); //对于arm平台系统调用号有一个0x900000的偏移 asm volatile( "mov r0,#1\n" "mov r1,%1\n" "mov r2,#14\n" "swi 0x900004\n" //进入内核 "mov %0,r0\n" //返回值在r0中 :"=&r"(ret) :"r"(s) :"r0","r1","r2" ); printf("ret =%d\n,ret"); return 0;}
阅读全文
0 0
- ARM-Linux嵌入式汇编笔记
- 【嵌入式Linux+ARM】ARM体系结构与编程(ARM汇编指令)
- 嵌入式Linux ARM汇编(一)——ARM体系结构
- 嵌入式Linux ARM汇编(一)——ARM体系结构
- 嵌入式ARM汇编复习
- 嵌入式Linux ARM汇编(三)——ARM汇编指令
- 嵌入式Linux ARM汇编(六)——GNU ARM汇编编程
- 嵌入式Linux ARM汇编(七)——C语言与ARM汇编混合编程
- 嵌入式Linux ARM汇编(三)——ARM汇编指令(一)
- 嵌入式Linux ARM汇编(三)——ARM汇编指令(二)
- 嵌入式Linux ARM汇编(三)——ARM汇编指令(三)
- 嵌入式Linux ARM汇编(三)——ARM汇编指令(四)
- 嵌入式Linux ARM汇编(六)——GNU ARM汇编编程
- 嵌入式Linux ARM汇编(七)——C语言与ARM汇编混合编程
- 嵌入式Linux中ARM gcc嵌套汇编学习-ARM GCC Inside Assembler
- 嵌入式Linux ARM汇编(二)——ARM异常处理
- 嵌入式Linux ARM汇编(四)——ARM汇编程序设计
- 嵌入式Linux ARM汇编(五)——ARM体系结构过程调用标准
- wget命令
- spring-boot+spring-retry
- JBPM介绍
- Git 提交过程
- 包子凑数
- ARM-Linux嵌入式汇编笔记
- Python实现归并排序
- Linux 下安装 LAMP及配置
- 算法导论-散列表-MIT6.006 Lecture 8
- 【深度学习框架Caffe学习与应用】第五课 自定义神经层和数据输入层
- Java中的数据类型
- 邮件发送
- 利用itext操作pdf从数据库导出大量数据--创建PDF表格(三)
- MySql 事务介绍