分支
X - Y
int x = 0x1234;
int y = 0x5678;
if (x > y) {
z = x - y;
z = 7 * z;
} else {
z = y - x;
z = 9 * z;
}
.text
.globl _start
_start:
LDR R0, =0x1234
LDR R1, =0x5678
h
CMP R0,R1
BHI XY
BLS YX
XY:
SUB R2,R0,R1
RSB R2,R2,R2,LSL #3 @ 逆向减
YX:
SUB R2,R1,R1
ADD R2,R2,R2,LSL #3
b . @ B .表示一直在当前指令处原地跳转,也就是死循环
.end
大于小于
< : CC >= : CS
> : HI <= : LS
= : EQ
完成如下动作
.text
.globl _start
_start:
# 给R0赋值为3 0x00000003
MOV R0,#3
# 给R1赋值为4 0x00000004
MOV R1,#4
# 将R0逻辑左移R1当前值位 0x00000006
MOV R0,R0,LSL #1
# 将R0减5 0x00000001
SUB R0,R0,#5
# 将R0第2位取反 0x00000041
EOR R0,R0,#0x40
# 将R0第3位置0 0x00000041
AND R0,R0,#0xDF
# 将R0第4为置1 0x00000051
ORR R0,R0,#0x10
B .
.end
函数的应用
如何在汇编中实现函数调用
通过 BL func 进行函数调用
函数中如何返回
两种方法:
BX LR 更通用一些,可以在Thumb和ARM间互相调用MOV PC,LR
PC R15 里面存放将要执行的指令的地址 LR R14 里面存放要返回到的指令的地址
一般在实际编程中:R13写成SP,R14写成LR,R15写成PC
函数调用过程中如何传参
参数依次用r0,r1,r2,r3来进行传递 函数的返回值首选r0 来进行传递,如果有两个结果则首先R0,R1,。。。。。。
函数定义和调用的模板
/*函数调用*/
@通过给R0、R1、R2、R3设置值,来向func函数传递参数,用几个寄存器,根据函数的参数个数决定,绝大多数函数的参数个数不会超过4个
BL func @调用名为 func 的函数
/*函数定义*/
func:
@ 功能实现
@ 通过给R0设置值,来向函数调用处返回实现结果,如果结果有多个则继续使用R1、R2....,绝大多数函数的实现结果是一个
BX LR @函数返回
add 函数
.text
.globl _start
_start:
MOV R0,#3
MOV R1,#5
BL foo
B .
foo:
ADD R0,R0,R1
MOV PC,LR @BX LR
.end
求三角形周长
.text
.global _start
_start:
MOV R0,#3 @a
MOV R1,#4 @b
MOV R2,#5 @c
BL TRI_C
B .
TRI_C:
ADD R0,R0,R1
ADD R0,R0,R2
BX LR
.end
大小端
内存序:整数在内存的存放次序
12345678
小端 78 56 23 12 X86
大端 12 34 56 78 Power PC、ARM(默认,但可改)
LDR/STR
LDR:取地址里的数,如LDR R1, [R0] @ 将 R0 地址的 内容放入 R1 中 (先看后面的)
STR:将数存入地址,如STR R1, [R0] @ 将 R1 的内容放入 R0 所对应的地址里 (先看前面的)
.text
.globl _start
_start:
LDR R0,=0x11223344
MOV R1,#0x40000000
STR R0,[R1] @ 将 R0 的内容放入 R1 的内容的地址
LDRB R2,[R1] @ 读取 R1 地址的前两个 2 进制
B .
.end
字数据和8位无符号字节数据Load和Store的寻址方式
基址变址寻址:在基础地址上做一些改变形成新地址
基址:基础地址,用寄存器来存放,因此这样的寄存器被称为基址寄存器
LDR|STR{cond}{B}{T} <Rd>,<address_mode>
<address_mode>有九种方式:访问内存用的地址是[]里计算出来的地址
不索引三种:先计算新地址但不更新基址寄存器,然后用新地址访问内存
[<Rn>,#+/-<offset_12>]
[<Rn>,+/-<Rm>]
[<Rn>,+/-<Rm>,<shift> #<shift_imm>]
前索引三种:先计算新地址并更新基址寄存器,然后用新地址访问内存
[<Rn>,#+/-<offset_12>]!
[<Rn>,+/-<Rm>]!
[<Rn>,+/-<Rm>,<shift> #<shift_imm>]!
后索引三种:先用基址寄存器的地址访问内存,然后计算新地址并更新基址寄存器
[<Rn>],#+/-<offset_12>
[<Rn>],+/-<Rm>
[<Rn>],+/-<Rm>,<shift> #<shift_imm>
两数相加
将内存中的两个数相加并保存到内存
.text
.globl _start
_start:
LDR R0, =Value1 @ 将 Value1 的地址放入 R0 中
LDR R1, [R0] @ 将 R0 地址的 内容放入 R1 中
LDR R0, =Value2
LDR R2, [R0]
# 两数x
ADD R1, R1, R2
LDR R0, =Result
STR R1, [R0] @ 将 R1 的内容放入 R0 所对应的地址里
B .
.data
Value1: .word 0x11111111
Value2: .word 0x22222222
Result: .word 0x0
.end
两数比较
LDR 取后地址的内容 后面有立即数,地址加上立即数
STR 存前到地址的内容
@找内存中两个32位数的最大数,并将最大数保存到新的内存块
.text
.globl _start
_start:
LDR R0, =Value1
LDR R1, [R0],#4 @ 将 R0 地址的内容放入 R1 ,并且 R0 地址 + 4
LDR R2, [R0] @ 将 R0 地址的内容放入 R2
CMP R1,R2
MOVHI R3,R1 @ >
MOVLS R3,R2 @ <=
LDR R0, =Result @ 将 Result 地址的内容放入 R0
STR R3, [R0] @ R3(大的值)放入 R0 (result) 中
B .
.data
Value1: .word 0x11111111
Value2: .word 0x22222222
Result: .word 0x0
.end
数组
数组相加
ARM汇编编写程序,程序功能为:定义一个数组,数组中包含4个32位无符号整数,找出最大值,并将结果保存到内存
@定义一个数组,数组中含4个32位数,求数组中元素的总和,并将结果保存到内存
.text
.globl _start
_start:
LDR R0,=Length
LDR R2, [R0] @ R2 数组的长度
LDR R0, =Table
EOR R1, R1, R1 @ 清零
Loop:
LDR R3, [R0],#4
ADD R1, R1, R3
SUBS R2, R2, #0x1
BNE Loop
LDR R0, =Result
STR R1, [R0]
B .
.data
Table: .word 0x1000,0x2000,0x3000,0x4000
TablEnd: .word 0
Length: .word (TablEnd-Table)/4
Result: .word 0
.end
数组最小数
.text
.globl _start
_start:
LDR R0,=Length
LDR R2, [R0] @ R2 数组的长度
LDR R0, =Table @ Table 起始地址
LDR R1, [R0] @ R1 为数组中的第一个元素
SUBS R2, R2, #0x1
Loop:
LDR R3, [R0,#4]!
CMP R1,R3
MOVHI R1,R3
SUBS R2, R2, #0x1
BNE Loop
LDR R0, =Result
STR R1, [R0]
B .
.data
Table: .word 0x2000,0x1234,0x3000,0x4000
TablEnd: .word 0
Length: .word (TablEnd-Table)/4 @ d
Result: .word 0
.end
数组最大数
ARM汇编编写程序,程序功能为:定义一个数组,数组中包含4个32位无符号整数,找出最大值,并将结果保存到内存
.text
.globl _start
_start:
LDR R0,=Length
LDR R2, [R0] @ R2 数组的长度
LDR R0, =Table @ Table 起始地址
LDR R1, [R0] @ R1 为数组中的第一个元素
SUBS R2, R2, #0x1
Loop:
LDR R3, [R0,#4]!
CMP R1,R3
MOVCC R1,R3
SUBS R2, R2, #0x1
BNE Loop
LDR R0, =Result
STR R1, [R0]
B .
.data
Table: .word 0x2000,0x1234,0x5555,0x3000
TablEnd: .word 0
Length: .word (TablEnd-Table)/4
Result: .word 0
.end
数组复制
.equ num,20
.text
.global _start
_start:
LDR R0,=src
LDR R1,=dst
MOV R2,#num
blockcopy: @以8个字为单位复制
MOVS R3,R2,LSR #3 @除以2的3次方,得到以8个字为单位复制的次数
BEQ copywords
octcopy:
LDMIA R0!,{R4-R11}
STMIA R1!,{R4-R11}
SUBS R3,R3,#1
BNE octcopy
copywords:@以单个字为单位复制
ANDS R2,R2,#7 @总字数对8取余,得到剩余要复制的字数
BEQ stop
wordcopy:
LDR R3,[R0],#4
STR R3,[R1],#4
SUBS R2,R2,#1
BNE wordcopy
stop:
B stop
.data
src:
.word 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
dst:
.word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.end
实验
@ 亮第个灯
.text
.global _start
_start:
LDR R0,=0x114001E0 @GPF3CON
LDR R1,=0x114001E4 @GPF3DAT
/*Set CON 20~23 0001*/
LDR R2,[R0] @ R2 0x00000000
BIC R2, #0xF00000 @ R2 0x00000000 清楚之前 R2 残余的数据
ORR R2,R2, #0x100000 @ R2 0x00100000
STR R2,[R0] @ R0 0x114001E0 : 0x00100000
/*LED5 ON*/
LDR R2,[R1] @ R2 0x00000000
ORR R2, #0x20 @ R2 0x00200000
STR R2,[R1] @ R1 0x114001E4 : 0x00200000
B .
.end
生成裸机可执行文件
"C:\Program Files (x86)\CodeSourcery\Sourcery G++ Lite\bin\arm-none-eabi-gcc.exe" -c myprogram.S
"C:\Program Files (x86)\CodeSourcery\Sourcery G++ Lite\bin\arm-none-eabi-ld.exe" -Ttext 0x40008000 myprogram.o -o led.elf
"C:\Program Files (x86)\CodeSourcery\Sourcery G++ Lite\bin\arm-none-eabi-objcopy.exe" -O binary -S led.elf led.bin
下载并运行裸机程序
如何将文件从电脑发送到开发板的内存中?
loadb 0x40008000
0x40008000代表开发板上内存的地fs址
点击 File -> Transfer -> Kermit -> Send 选择 led.bin 文件
C:\Users\admin\Documents\Tencent Files\xxxx\FileRecv led.bin
go 0x40008000
执行裸机程序led.bin
|