目录
- .text @声明当前内容为文本段内容
-
- .global _start @声明_start的内容为全局内容
-
- _start:
- mov r1,#1 @将1保存在r1寄存器
-
- loop:
- b loop @程序跳转到loop标签
-
- .end @程序结束
map.lds文件是一个链接脚本文件 链接脚本的作用:当程序在编译的最后一个阶段-链接阶段中按照链接脚本的规定,链接不同的文件生成可执行文件
- OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
- /*指定输出elf格式的适用于32位机器的镜像,镜像内部的数据按照小端存储方式 */
- OUTPUT_ARCH(arm)/*生成的镜像架构是ARM架构的 */
- ENTRY(_start)/* 程序执行的入口是_start*/
- SECTIONS /* 内部指定了不同内容在内存中的存储位置*/
- {
- . = 0x00000000; /*当前程序起始地址为0X0*/
- . = ALIGN(4);/*程序中的指令遵循4字节对齐*/
- .text : /*指定文本段的存储地址*/
- {
- ./Objects/start.o(.text) /*将start.o的内容放在文本段最开始*/
- *(.text)/*其他的文件保存位置由链接器自己决定*/
- }
- . = ALIGN(4);
- .rodata : /*规定只读代码段的存储规则*/
- { *(.rodata) }
- . = ALIGN(4);
- .data :
- { *(.data) }
- . = ALIGN(4);
- __bss_start = .; /*指定.bss段的起始位置*/
- .bss :
- { *(.bss) }
- __bss_end__ = .;/* 指定.data段的起始位置*/
- }
- 1.伪操作:在汇编程序中不占用存储空间,但是可以在程序编译时起到引导和标识作用
- .text .global .glbal .if .else .endif .data .word....
- 2.汇编指令:每一条汇编指令都用来标识一个机器码,让计算机做一个指令运算
- 数据处理指令
- 数据搬移指令
- 算数运算指令
- 数据移位指令
- 位运算指令
- 数据比较指令
- 跳转指令
- 内存读写指令
- 状态寄存器传送指令 CPSR
- 软中断指令
- 3.伪指令:不是汇编指令,但是也可以让处理器做一些数据处理,通常一条伪指令会由多条汇编指令联合实现
-
- 4.注释
- 单行注释: @ ;
- 多行注释: /* */
- 条件注释
- .if 1/0
- 指令段1
- .else
- 指令段2
- .endif
- 指令的基本格式:
- <opcode> {<cond>} {s} <Rd>, <Rn>, <shifter_operand>
-
- <opcode>:指令的操作码
- cond:条件码后缀
- s:指令的执行结果将会影响CPSR中的条件标志位。
- <Rd>:目标寄存器,指令的运算结果保存在目标寄存器中
- <Rn>:第一操作寄存器,只能是寄存器
- <shifter_operand> :第二操作数,既可以是寄存器编号,又可以是立即数
- 意义:让第一操作寄存器中的值和第二操作数按照指令操作码进行运算,并且将运算的结果保存在目标寄存器中
-
- 注意:
- 1.一般一条汇编指令就占据一行代码
- 2.汇编不区分大小写
- 3.操作数前面要跟一个#
- <opcode> {<cond>} {s} <Rd>, <shifter_operand>
- 解释:
-
- <opcode>:指令的操作码
- cond:条件码后缀
- s:指令的执行结果将会影响CPSR中的条件标志位。
- <Rd>:目标寄存器,指令的运算结果保存在目标寄存器中
- <shifter_operand> :第一操作数,既可以是寄存器编号,又可以是立即数
-
- 指令码:
- mov:将操作数直接搬移到目标寄存器中
- mvn:将操作数按位取反之后搬移到目标寄存器中
定义:可以直接当作指令的一部分去执行的数据叫做立即数。立即数是通过一个0-255之间的数字循环右移偶数位获取
循环右移:低位移除,补到高位
- 如何判断一个数据是不是立即数:
- 只要让这个数据或者这个数据按位取反的值循环右移偶数位,能够得到一个0-255范围内的数字就说明这个数是立即数
-
- ex:
- 1. 0X104-> 0000 0000 0000 0000 0000 0001 0000 0100
- 0X104循环右移两位-》00 0000 0000 0000 0000 0000 0001 0000 01->0x41
- 0X41是一个0-255范围内的数据
- 0x104是0X41循环右移30位得到的数据,所以,0X104是立即数
-
- 2.0x101-> 0000 0000 0000 0000 0000 0001 0000 0001
- 0X101找不到一个0-255范围内的数字寻魂右移偶数位得到它,所以它不是立即数
-
- 3.0XFFFFFFFE ->1111 1111 1111 1111 1111 1111 1111 1110
- 0XFFFFFFFE也找不到0-255范围内的数字循环右移偶数位得到它,但是它的取反值0X1是一个立即数,所以0XFFFFFFFE也是一个立即数
利用伪指令ldr即可完成非立即数的操作 格式: ldr 目标寄存器名,=数据
- 格式:
- <opcode> {<cond>} {s} <Rd>, <Rn>, <shifter_operand>
- 解释:将第一操作寄存器的数值移位第二操作数位,将结果保存在目标寄存器中
-
- 指令码:
- lsl:左移运算,最高位移出,最低位补0
- lsr:右移运算,最低位移出,最高位补0
- ror:循环右移:最低位移出,补到最高位
-
- text
- .global _start
- _start:
- mov r0,#0XFF
- lsl r1,r0,#4 @0XFF左移四位结果保存到r1 0XFF0
- lsr r2,r0,#4 @0XFF右移移四位结果保存到r2 0XF
- ror r3,r0,#4 @0XFF循环右移四位结果保存到r3 0XF000000F
- loop:
- b loop
-
- .end
-
-
与、或、异或、按位清0
与:与0清0 与1不变
初值 | 运算值 | 结果 |
1 | 0 | 0 |
1 | 1 | 1 |
0 | 1 | 0 |
0 | 0 | 0 |
或:或1置1 或0不变
初值 | 运算值 | 结果 |
1 | 0 | 1 |
1 | 1 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
异或:相同为0,不同为1
初值 | 运算值 | 结果 |
1 | 0 | 1 |
1 | 1 | 0 |
0 | 1 | 1 |
1 | 1 | 0 |
按位清0:想要哪位清0,只需要和1进行运算即可
初值 | 运算值 | 结果 |
1 | 1 | 0 |
0 | 1 | 0 |
1 | 0 | 1 |
0 | 0 | 0 |
- 格式:
{} {s} , , -
- 指令码:
- and:进行按位与
- orr:进行按位或
- eor:按位异或
- bic:按位清0
- .text
- .global _start
- _start:
- mov r0,#0XFF
- and r1,r0,#(~(0X1<<4)) @第四位清0 0xEF
- orr r2,r0,#(0X1<<9) @第9位置1 0X2FF
- eor r3,r0,#0XF @0xf0
- bic r4,r0,#(0X1<<4)@第四位清0 0xEF
- loop:
- b loop
-
- .end
- 格式:
{}{s} , , -
- 指令码:
- add:加法运算 Rd=Rn+shifter_operand
- adc:进行加法运算时考虑CPSR的C位 Rd=Rn+shifter_operand+CPSR[c]
- sub:减法运算 Rd=Rn-shifter_operand
- sbc:进行减法运算时考虑CPSR的c位 Rd=Rn-shifter_operand-!CPSR[c]
- RSB
- :逆向减法Rd=shifter_operand-Rn
- RSC:带借位的逆向减法指令 Rd = shifter_operand – Rn - !CPSR[c]
-
-
- mul:乘法运算 Rd=Rn*shifter_operand
加法
- .text
- .global _start
- _start:
- mov r0,#0XFFFFFFFE
- mov r1,#3
- adds r2,r0,r1 @0X1,运算的结果影响到条件位
- adc r3,r1,r2 @r3=r1+r2+CPSR[c]
-
- loop:
- b loop
-
- .end
-
减法:
- .text
- .global _start
- _start:
- mov r0,#0XFFFFFFFE
- mov r1,#3
- subs r2,r1,r0 @减法不借位,c位置1,借位,c位清0
- mov r3,#6
- sbc r4,r3,r1 @r4=r3-r1-!CPSR[c]
-
-
- loop:
- b loop
-
- .end
-
- MOV R1,#0xfffffffe @第一个数据的低32位
- mov r2,#0x00000004 @第一个数据的高32位
-
- MOV R3,#0x00000005 @第二个数据的低32位
- mov r4,#0x00000004 @第二个数据的高32位
- 加法:
- 低32位:
- adds r5,r1,r3
- 高32位:
- adc r6,r2,r4
-
- 减法:
- 低32位:
- subs r5,r3,r1
- 高32位:
- sbc r6,r4,r2
- 格式:
- cmp
, - 比较指令的本质:
- 拿第一操作寄存器和第二操作数进行减法运算,并且减法运算的结果会影响到CPSR的条件位
-
-
- 可以根据比较指令之后的条件位的数值进行不同的运算,相当于c里的选择语句
- 这里需要对CPSR的条件位进行判断,我们依赖条件位的助记词{cond}后缀实现
- .text
- .global _start
- _start:
- MOV R1,#4
- MOV R2,#4
- CMP R1,R2
- addeq r3,r1,r2 @if(r1==r2) r3=r1+r2
- subne r4,r1,r2 @if(r1!==r2) r4=r1-r2
- loop:
- b loop
-
- .end
- 一般实现程序的跳转有两种方式:
- 1.直接修改PC的值
- 2.通过跳转指令
- 跳转指令:
-
- 1.b label
- 解释:跳转到label标签所在代码,此时跳转,lr寄存器不保存返回地址
- ex:
- .text
- .global _start
- _start:
- MOV R1,#4
- MOV R2,#4
- CMP R1,R2
- beq addfunc
- bne subfunc
-
- addfunc:
- add r3,r1,r2
- b loop
- subfunc:
- sub r4,r1,r2 @if(r1!==r2) r4=r1-r2
- b loop
- loop:
- b loop
-
- .end
-
- 2. bl label
- 解释:跳转到label标签所在代码,此时跳转,lr寄存器保存返回地址
-
- ex:
- .text
- .global _start
- _start:
- MOV R1,#4
- MOV R2,#4
- CMP R1,R2
- bleq addfunc
- blne subfunc
-
- addfunc:
- add r3,r1,r2
- mov pc,lr @程序返回
- subfunc:
- sub r4,r1,r2 @if(r1!==r2) r4=r1-r2
- mov pc,lr @程序返回
- loop:
- b loop
-
- .end
-
- 3. bx 地址
- 跳转到地址对应的的指令位置,此时跳转LR不保存返回地址
- .text
- .global _start
- _start:
- MOV R1,#4
- MOV R2,#4
- MOV R3,#4
- MOV R4,#4
- MOV R5,#4
- MOV R6,#4
- bx r3 @跳转到地址为4的指令位置
-
- loop:
- b loop
-
- .end
-
- 4.blx 地址
- 跳转到地址对应的的指令位置,此时跳转LR保存返回地址
-
- .text
- .global _start
- _start:
- MOV R1,#4
- MOV R2,#4
- MOV R3,#4
- MOV R4,#4
- MOV R5,#4
- blx r3 @跳转到地址为4的指令位置
- MOV R6,#4
-
-
- loop:
- b loop
-
- .end
-
- .text
- .global start
-
-
- _start:
- mov r0,#0 @存放sum
- mov r1,#1 @存放相加的数值
- loop:
- cmp r1,#100
- bhi wh
- add r0,r0,r1
- add r1,r1,#1
- b loop
- wh:
- b wh
-
- .end