目录
一、示例汇编代码示例
.text @声明当前内容为文本段内容
.global _start @声明_start的内容为全局内容
_start:
mov r1,#1 @将1保存在r1寄存器
loop:
b loop @程序跳转到loop标签
.end @程序结束
二、.程序的调试
三、map.lds分析
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、汇编文件中的内容
1.伪操作:在汇编程序中不占用存储空间,但是可以在程序编译时起到引导和标识作用
.text .global .glbal .if .else .endif .data .word....
2.汇编指令:每一条汇编指令都用来标识一个机器码,让计算机做一个指令运算
数据处理指令
数据搬移指令
算数运算指令
数据移位指令
位运算指令
数据比较指令
跳转指令
内存读写指令
状态寄存器传送指令 CPSR
软中断指令
3.伪指令:不是汇编指令,但是也可以让处理器做一些数据处理,通常一条伪指令会由多条汇编指令联合实现
4.注释
单行注释: @ ;
多行注释: /* */
条件注释
.if 1/0
指令段1
.else
指令段2
.endif
2.汇编指令的基本语法格式
指令的基本格式:
<opcode> {<cond>} {s} <Rd>, <Rn>, <shifter_operand>
<opcode>:指令的操作码
cond:条件码后缀
s:指令的执行结果将会影响CPSR中的条件标志位。
<Rd>:目标寄存器,指令的运算结果保存在目标寄存器中
<Rn>:第一操作寄存器,只能是寄存器
<shifter_operand> :第二操作数,既可以是寄存器编号,又可以是立即数
意义:让第一操作寄存器中的值和第二操作数按照指令操作码进行运算,并且将运算的结果保存在目标寄存器中
注意:
1.一般一条汇编指令就占据一行代码
2.汇编不区分大小写
3.操作数前面要跟一个#
五、【汇编的指令】
1.数据搬移指令
1.1 基本格式
<opcode> {<cond>} {s} <Rd>, <shifter_operand>
解释:
<opcode>:指令的操作码
cond:条件码后缀
s:指令的执行结果将会影响CPSR中的条件标志位。
<Rd>:目标寄存器,指令的运算结果保存在目标寄存器中
<shifter_operand> :第一操作数,既可以是寄存器编号,又可以是立即数
指令码:
mov:将操作数直接搬移到目标寄存器中
mvn:将操作数按位取反之后搬移到目标寄存器中
1.2 示例
2. 立即数的概念
2.1 概念
定义:可以直接当作指令的一部分去执行的数据叫做立即数。立即数是通过一个0-255之间的数字循环右移偶数位获取
循环右移:低位移除,补到高位
2.2 立即数的判断
如何判断一个数据是不是立即数:
只要让这个数据或者这个数据按位取反的值循环右移偶数位,能够得到一个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也是一个立即数
2.3 如何将一个非立即数保存在寄存器中
利用伪指令ldr即可完成非立即数的操作 格式: ldr 目标寄存器名,=数据
3.移位操作指令
3.1 指令格式以及指令码
格式:
<opcode> {<cond>} {s} <Rd>, <Rn>, <shifter_operand>
解释:将第一操作寄存器的数值移位第二操作数位,将结果保存在目标寄存器中
指令码:
lsl:左移运算,最高位移出,最低位补0
lsr:右移运算,最低位移出,最高位补0
ror:循环右移:最低位移出,补到最高位
3.2 示例
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
4.位运算指令
4.1 相关指令功能以及规则
与、或、异或、按位清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 |
4.2 位运算指令码以及格式
格式:
<opcode> {<cond>} {s} <Rd>, <Rn>, <shifter_operand>
指令码:
and:进行按位与
orr:进行按位或
eor:按位异或
bic:按位清0
4.3 示例
.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
5.算数运算指令
5.1 指令码以及格式
格式:
<opcode>{<cond>}{s} <Rd>, <Rn>, <shifter_operand>
指令码:
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
5.2 示例代码
加法
.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
5.3 进行64位算数运算
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
6.数据比较指令
6.1 语法
格式:
cmp <Rn>, <shifter_operand>
比较指令的本质:
拿第一操作寄存器和第二操作数进行减法运算,并且减法运算的结果会影响到CPSR的条件位
可以根据比较指令之后的条件位的数值进行不同的运算,相当于c里的选择语句
这里需要对CPSR的条件位进行判断,我们依赖条件位的助记词{cond}后缀实现
6.2 示例
.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
7.跳转指令
一般实现程序的跳转有两种方式:
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
任务
1.复习今日内容
2.实现1-100,累加
.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