目录
一、示例汇编代码示例
二、.程序的调试
编辑三、map.lds分析
四、【汇编语言的相关语法】
1、汇编文件中的内容
2.汇编指令的基本语法格式
五、【汇编的指令】
1.数据搬移指令
1.1 基本格式
1.2 示例
编辑2. 立即数的概念
2.1 概念
2.2 立即数的判断
编辑2.3 如何将一个非立即数保存在寄存器中
编辑3.移位操作指令
3.1 指令格式以及指令码
3.2 示例
编辑4.位运算指令
4.1 相关指令功能以及规则
4.2 位运算指令码以及格式
4.3 示例
5.算数运算指令
5.1 指令码以及格式
5.2 示例代码
编辑5.3 进行64位算数运算
6.数据比较指令
6.1 语法
编辑6.2 示例
7.跳转指令
任务
1.复习今日内容
2.实现1-100,累加
.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
指令的基本格式:
{} {s} , ,
:指令的操作码
cond:条件码后缀
s:指令的执行结果将会影响CPSR中的条件标志位。
:目标寄存器,指令的运算结果保存在目标寄存器中
:第一操作寄存器,只能是寄存器
:第二操作数,既可以是寄存器编号,又可以是立即数
意义:让第一操作寄存器中的值和第二操作数按照指令操作码进行运算,并且将运算的结果保存在目标寄存器中
注意:
1.一般一条汇编指令就占据一行代码
2.汇编不区分大小写
3.操作数前面要跟一个#
{} {s} ,
解释:
:指令的操作码
cond:条件码后缀
s:指令的执行结果将会影响CPSR中的条件标志位。
:目标寄存器,指令的运算结果保存在目标寄存器中
:第一操作数,既可以是寄存器编号,又可以是立即数
指令码:
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 目标寄存器名,=数据
格式:
{} {s} , ,
解释:将第一操作寄存器的数值移位第二操作数位,将结果保存在目标寄存器中
指令码:
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