preserve8 ;使用栈,需要8字节对齐
area reset, code, readonly
code32
entry
;初始化异常向量表
b start ;reset 复位
nop ;undef 未定义指令
b deal_swi ;swi 软中断
nop ;prefetch abort 预取中止
nop ;data abort 数据中止
nop ;reserved 保留
nop ;irq 中断
nop ;fiq 快中断
deal_swi ;类似于C语言中的信号处理函数
stmfd sp!, {r4-r12, lr}
sub r0, lr, #4 ;获取swi #7的地址
ldr r1, [r0] ;[r0]表示取r0地址里的值,类似指针的*运算
bic r0, r1, #0xff000000 ;r0 = 7
import c_deal_swi ;处理swi的C函数
bl c_deal_swi
ldmfd sp!,{r4-r12, pc}^ ;^ 带模式切换的恢复现场
start
ldr sp, =0x40001000 ;初始化svc模式的栈 ldr : 加载一个内存地址
;切换到user模式,切换模式后,原来的栈也就没了,因为每种工作模式都有自己的栈
mrs r0, cpsr ;mrs:读取cpsr的值 将cpsr的值读取r0中
bic r0, r0, #0x1f ;先清零
orr r0, r0, #0x10 ;再置一
msr cpsr_c, r0 ;msr:把值写入cpsr cpsr_c(修改工作模式==>修改低5位) 域叠加:cpsr_fsxc
ldr sp, =0x40000c00 ;初始化user模式的栈 3k
mov r0, #1 ;立即数:一个数右移偶数位或按位取反后,所有的1都能放进低八位中
mov r1, #2
add r2, r0, r1
sub r3, r1, r0
mov r0, #0xff
mov r1, #0x55
and r2, r0, r1
orr r3, r0, r1
eor r4, r0, r1
mov r0, #0xff
mov r1, #0x0f ;0xf <==> 0x0f
bic r2, r0, r1 ;按位与,再取反
;0x 0001 ffff ffff
;0x 0002 0000 0003 相加
;相加结果应为:0x 0004 0000 0002
;实现了在32位计算机里进行64位数字的运算
mov r0, #0xffffffff
mov r1, #1
mov r2, #0x3
mov r3, #0x2
adds r4, r0, r2 ;adds 更新进位标志,cpsr中的C位变为1
adc r5, r1, r3 ;adc 带进借位的加法
;cmp cmn tst teq
;这些比较和测试指令都是专门用来影响cpsr的那几个标志的
mov r0, #4
mov r1, #5
cmp r0, r1 ;cmp 比较大小 为负 C位为0 N位为1表示ALU运算结果为负
movlt r2, r0 ;<==>if(r0 < r1)
; r2 = r0; lt gt eq 分别为 < > = 都是条件码的一种
swi #5 ;软中断指令,当复位或者软中断指令执行的时候,就会切换到SVC模式
mov r0, #5
mov r1, #6
mov r2, #7
cmp r0, r1 ;<==>if(r0 < r1 && r0 < r2) {
cmplt r0, r2 ; r3 = r0;
movlt r3, r0 ; r4 = r0;
movlt r4, r0 ; }
movlt r5, r0 ;<==> if(r0 > r2) r5 = r0;
;1+ ..... + 100 实现1到100的累加
mov r0, #1
mov r1, #0
loop
add r1, r1, r0
add r0, r0, #1
cmp r0, #100
ble loop ; 条件码 le 表示 <=
mov r0, #1 ;函数传参规则: r0 - r3 以及 栈 栈指针就是SP所指的地址 (满减栈)
mov r1, #2 ;函数的返回值存放在r0中
import c_add ;import --> 声明,c_add 是定义的一个C语言的函数
bl c_add ; bl 带链接返回的调整,自动把返回地址保存在LR里边
mov r0, #1
mov r1, #2
mov r6, #6
bl asm_add
nop
b start ; b 类似于 C中的go to
export asm_add ;汇编里的一个符号要被外部使用,需要用 export 声明
asm_add
stmfd sp!, {r4-r12, lr} ;保护现场 stmfd:入栈,{}里放着的是要入栈的寄存器 封装函数时必须要将返回地址入栈
add r0, r0, r1
mov r6, #7 ;不希望外部的数据因为调用函数而发生改变,所以需要入栈,保护这些数据
ldmfd sp!,{r4-r12, pc} ;恢复现场 ldmfd:出栈 这两条出入栈指令是封装函数必备的
end
汇编语言的学习
于 2024-09-27 09:43:04 首次发布