门户网站建设项目书,页面设计一般用什么软件,如何在国外建设网站,上海品划做网站一、汇编学习#xff1a;可以向上理解软件、向下感知硬件
二、符号#xff08;注释#xff09;
注释#注释#xff08;放在行首表示注释一行#xff09;/* */注释#数字立即数#xff1a;一种标号#xff08;比如main: loop:#xff09;.text .end换行…一、汇编学习可以向上理解软件、向下感知硬件
二、符号注释
注释#注释放在行首表示注释一行/* */注释#数字立即数一种标号比如main: loop:.text .end换行固定格式
三、ARM指令格式和立即数
ARM指令构成 ARM 指令包含操作码和一些其他的信息只剩下8 位存放数据 具体来说一个 ARM 指令通常由以下部分组成 操作码Opcode这指定了指令的基本操作例如 ADD、MOV、SUB 等。条件码Condition这指定了该指令在什么条件下执行。寄存器索引Register Index这指定了要操作的寄存器。位移量Offset这是一个相对于某个基址的偏移量常用于内存操作。立即数Immediate这是一个直接嵌入到指令中的数值。其中操作码、条件码、寄存器索引和位移量总共占据了大部分的指令位数因此一个 ARM 指令中只有少部分通常为 8 位是用来表示立即数的。 例如一个 ARM 指令可能是这样的格式 Opcode Condition Register1 Register2 Offset/Displacement #0 一般指令格式 操作码 目的操作数 源操作数 mov r0 #5 mov r0, r1 立即数的优点取指的时候可以直接读到cpu 不需要单独去内存读取速度快立即数的缺点不能是任意的32位数字有局限且只能放在指令右边 四、如何判断立即数合法 转化为二进制编码观察第一个1和最后一个1之间的位数(包含这两个1) 1、将数据转换为 二进制编码 4 个一组 2、数1 的位数 如果超过8 个 那就不是立即数 3、如果数据中有连续 大于等于 24 个 0 通过循环位移 偶数位 使其高位全部为0 4、找到 高位1 去掉前边偶数个0 5、找到低位的1 去掉末尾偶数个0 6、剩下的位数小于等于8 那么就是立即数否则 不是 eg10xF000 000F 1111 0000 0000 0000 0000 0000 0000 1111 -- 1111 1111合法 eg20x123 ... 0000 0001 0010 0011 -- 01 0010 0011不合法 eg30x234 .... 0010 0011 0100合法 eg40x3F0 ... 0011 1111 0000合法
五、伪指令
伪指令不是指令
伪指令和指令的根本区别编译后是否生成机器码伪指令不会生成伪指令的意义 指导编译的过程如果需要执行伪指令必须先翻译成在指令 比如.text .end 也是伪指令 伪指令和编译器相关我们用到是gnu工具链因此我们学习的是gnu 环境下的汇编伪指令常用伪指令 ldr //大范围地址的加载指令 adr //小范围地址的加载指令 adrl //中范围地址的加载指令 nop //空操作 ldr (load register) 将内存内容加载进入通用寄存器 str (store register) 将寄存器内容存入内存空间 eg ldr r0, 0x12345678 num .word 0x15300000 //int num 0x15300000 buf1: .byte 1, 2, 3, 4 //char buf1[4] {1,2,3,4}; 六、指令--搬移、偏移指令
mov 搬移 mov r2, r1 // r2 r1 mov r0, #7 //r1 7 mvn 取反搬移 mvn r0, r1 // r0 ~r1 ldr向寄存器存入非立即数可以用伪指令LSL左移位LSR右移位ASL算术左移位位数不够补符号位ASR算术右移位位数不够补符号位ROR循环移位RRX带扩展的循环右移偏移指令总结 mov r0,r2, lsr #3 //r0 r2 3 mov r1 ,r0,lsl #1 //r1 r0 1 add r2, r1,r0,lsr #2 // r2 r1 r0 2 LSL 逻辑左移 Logical shift left LSR 逻辑右移Logical shift right ASL 算术左移 (Arithmet shift left ) ASR 算术右移(Arithmet shift right ) ROR 循环右移 RRX 带扩展的循环右移重要例子 tst r0, #0x8 判断某个数的某几位 是否为 0 movne r11, #1 moveq r11, #1 当上一条判断结果相等时 执行 mov movne r12, #2 当上一条判断结果不相等时执行mov tst r0, #0x8 表示判断r0的第三位(8的二进制1000也就是从右往左的第四位0 1 2 3)是否为0 eq ne表示相等/不相等 搬移
练习a) r0 16b) r0 r1/16c) r1 r2 *2d) r0 -4e) r1 r0/2答 mov r0, #16 mov r1, #32mov r2,r1, LSR #4mov r2, #4mov r3, r2, LSL #1 mov r0, #-4 mov r1,r0, ASR #1
偏移移位
.text 基本格式的头
搬移指令 mov r0, #3 搬移指令 r0 3 #3 立即数 ldr r0, 0xfff00000 ldr 伪指令 r0 0xfff mov r1,r0 搬移指令 r1 r0 移位mov r0, #0x4 mov r1, r0, LSL #1 r1r0 1 , 逻辑左移 高位移除部分舍去低位不够补0ldr r0, 0xffffffffmov r2, r0, LSR #1 r2r0 1 逻辑右移低位移除部分舍去 高位部分不够补 0mov r3, r0, ASR #1 r3 r0 1 算术右移低位移除部分舍去 高位不够 补 符号位ldr r0, 0x7000000f mov r4,r0, ROR #1 r4 r0 1 , 循环右移 低位移除部分补到 高位 ldr r0, 0xff0000ffmvn r5,r0 r5 ~r0.end 基本格式的尾巴 通常 该行下边 加空行七、指令--位操作 AND ORR BIC EOR
and与orr或bic 按位清零比如说0x4 就表示第2位(从0开始数)清零 bic r0,r1,#0x4 //r0 r1 (~0x4 ) eor异或
.text 基本格式的头逻辑指令mov r0, #6mov r1, #5and r2, r0,r1 r2 r1 r0orr r3, r0,r1 r3 r1 | r0eor r4, r0,r1 r4 r1 ^ r0 ldr r0,0x12345678bic r1, r0, #0xffbic r2,r0, #0xf0000000tst r0, #0x8 判断某个数的某几位 是否为 0 movne r11, #1moveq r11, #1 当上一条判断结果相等时 执行 movmovne r12, #2 当上一条判断结果不相等时执行mov 使能中断和快速中断设置cpsr的值mrs r0, cpsr r0 cpsrbic r1, r0, #0xc0msr cpsr, r1 cpsr r1.end 基本格式的尾巴 通常 该行下边 加空行 八、指令--比较指令、测试指令 用法注意 cmp moveq movne
cmp cmp r1, r0 //改变 cpsr 的 NZ moveq r2 #0 //相当于 if r1 r0 r2 0这是两行代码 cmn关系符号 eq ge gt le lt ne ! tst 实质是做 与运算 通常用于 测试某一位或几位是0 还是1 结果 CPSR Z 位来判断 Z 位位 1 表明结果为0 tst r0, #0x10 //测试 第4位是否为 0 if((r0 (0x10)) 0) //00010000 teq 实质是异或运算 测试两个 数是否相等如果两个数相等或者异或结果 为 0 修改 cpsr 的z 位 判断 teq r0 r1 // if((r0 ^ r1 ) 0)
.text 基本格式的头
比较指令/*int a 5ifa 5a 0else a 100*//*mov r0, #5cmp r0, #5 比较指令 比较 r0 和 5 movge r0 , #0 当cmp的结果 时 r0 0 movlt r0, #100 当cmp的结果 是 时 r0 100*/.end 基本格式的尾巴 通常 该行下边 加空行九、指令--算术指令 ADD ADC SUB SBC RSB RSC
add 相加 add r2, r1,#3 //r2 r1 4 adds 会改变条件位的相加配合adc使用 adds r0, r1, r2 // r0 r1 r2 (cpsr ) v c CPSR进位 -- c置为1 溢出 -- v置为1 补充--溢出在两个正数相加时如果结果超过了机器所能表示的最大正数那么就发生了上溢。同样地在两个负数相加时如果结果小于机器所能表示的最小负数那么就发生了下溢 adc 带进位的加法(常用于64位加法配合adds使用) adc r0, r1, r2 //r0 r1 r2 (cpsr) c sub 相减 sub r1 r2, r3 subs 影响cpsr的条件位 没有借位 时 cpsr c 位 置1 当有借位 c 0 sbcsbc 带借位的减法rsbrsb 逆向减法 rsb r1,r2, r3 //r1 r3 - r2 mul 乘法指令 mul r2, r0, r1 // r2 r0 * r1
练习64位加减法高32位 低32位
.text 基本格式的头算术指令mov r0, #10mov r1, #5add r2, r0, r1 r2 r0 r1 ldr r0, 0xff000000ldr r1, 0xf0000000add r2, r0, r1 (不带进位加法)adds r2, r0, r1 r2 r0 r1 , 如果有进位 那么会修改cpsr的进位值mov r3, #1mov r4, #1adc r5,r3,r4 r5 r3 r4 进位值64 bit 两个数的加法 r0, r1 表示被加数 r2 r3表示加数 64 bit 两个数的减法 ldr r0, 0xffffffff 低32 bitldr r1, 0x1 高32bitldr r2,0x1 低32bit ldr r3,0x5 高32bit adds r4, r0, r2adc r5, r1, r3subs r6, r2,r0sbc r7, r3,r1add r2, r0, r1 不带进位 不能计算 64 bit .end 基本格式的尾巴 通常 该行下边 加空行十、条件码eq、ne、lt小于、gt大于 十一、跳转
b 类似 goto bl 跳转之前 先保存 下一条指令的地址 bl lrr14 pc r15 -4 由cpu 帮我们执行
练习函数跳转 int main(void ) { int ret 0; func1(2); while(1) ; } func1int a { if(a 2) return func2(a) else return func3 (a) } func2(int a) { return a3; } func3(int a) { return a-1; }
.text 基本格式的头跳转练习main:mov r0, #0mov r1, #2bl func1main_end:b main_end 死循环func1:cmp r1, #2bleq func2blne func3
func1_end:func2:add r1, #3b func2_end
func2_end:mov pc, lrfunc3:.....字节补充一下
func3_end:.end 基本格式的尾巴 通常 该行下边 加空行
练习1加到100
.text 基本格式的头跳转指令 /*mov r0, #1mov r1, #10b t 跳转指令 跳到 t 后执行 add r2, r0, r1t: sub r3, r0, r1b t */实现 1-100的累加 和 /*for(int i1; i100; i){static int sum i; }*/mov r0, #0 类似 sum 累加和mov r1, #1 类似 i 循环变量
loop:循环计算cmp r1, #100bgt loop_end 这句 相当于 判断 i 大于 100 跳出循环 add r0,r1 相当于 sum i; add r1, #1 相当于 ib loop 继续下次循环loop_end:结束 mov r12,r0 把计算结果 放到 r12 .end 基本格式的尾巴 通常 该行下边 加空行
练习延时1s
.text 基本格式的头跳转指令 实现延时 1 sldr r0, 0x1f1fffff 具体多少为 1秒 需要计算
loop:cmp r0, #0beq loop_endsub r0,#1b loop
loop_end:mov r12, #0.end 基本格式的尾巴 通常 该行下边 加空行十二、修改ARM状态和模式
.text 基本格式的头判断 当前工作状态是否 是ARM 状态 如何切换到 user 模式或其他模式 mrs r0, cpsr r0 cpsr mov r1, #0x20 0010 0000 T 位 orr r1, r1, #0x1000000 J 位 结果r1把 T位和 J位置为1 ,其余为0tst r0, r1 判断 r0中的J和 T 是否为 0 biceq r0, #0x1f 把 mode 清0 orreq r0, #0x10 把mode 变为 user模式 10000msr cpsr, r0 cpsr r0.end