当前位置:   article > 正文

ARM指令栈操作&软中断_mov sp arm

mov sp arm

书接上文:浅谈ARM处理器工作模式&内核寄存器&指令语句

栈操作

接上文LDM/STM指令部分提到的栈操作,栈操作主要分为两种:

  1. PUSH:压栈
  2. POP:弹栈

栈操作时又分为两种实现方式:

  1. 满栈:SP所指的地址有数据
  2. 空栈:SP所指的地址无数据

以下为不同的栈类型对应的栈操作指令:

栈类型压栈弹栈
满栈降序STMFD(STMDB,先减少,再操作)LDMFD(LDMIA,先操作,再增加)
满栈增序STMFA(STMIB,先增加,再操作)LDMFA(LDMDA,先操作,再减少)
空栈降序STMED(STMDA,先操作,后减少)LDMED(LDMIB,先操作,再增加)
空栈增序STMEA(SRMIA,先操作,后增加)LDMEA(LDMDB,先减少,再操作)

软中断

通过汇编指令软件实现中断称为软中断。通过软中段机制,运行在用户模式下的应用程序,可请求操作系统执行一系列的特权操作。

为了参考,我们再次将上一篇文章中的ARM内核寄存器组列表罗列于此:

寄存器
R0
R1
R2
R3
R4
R5
R6
R7
R8
R9
R10
R11
R12
SP(R13)
LR(R14)
PC(R15)
CPSR
SPSR
ELR_hyp
模式User/SystemHypSupervisorAbortUndefMoniterIRQFIQ

软中断命令

SWI{(cond)} <SWI NUMBER>
  • 1

SWI指令可以产生一个异常陷阱,从而跳转到异常向量表的SWI_handler,SWI NUMBER为中断号。

^符号可以在弹栈的同时将SPSR的值赋给CPSR。

软中断原理

软中断需要实现模式改变后寄存器现场的保存,和模式恢复后寄存器现场的恢复,分为以下几步:

  1. 初始化特殊模式的内存栈,将特殊模式的内存栈首地址赋值给特殊模式的SP寄存器,此处我们赋值给软中断模式的SP寄存器。
  2. SWI指令产生异常陷阱,同时生成中断号。
  3. 跳转入异常向量表,再由异常向量表跳转至代码段对应的指令段。
  4. 将之前公用寄存器现场保存压入特殊模式的内存栈中,因为这些公用的寄存器在特殊模式下也会使用,会造成之前模式的寄存器现场破坏。
  5. 获取中断号。
  6. 跳转至对应中断号的指令代码
  7. 中断程序执行完毕,将特殊模式内存栈中存储的上一模式的寄存器现场恢复,即弹栈恢复。
SVC USER 获取SVC内存栈首地址 内存栈首地址赋值给SVC:SP寄存器 SWI产生陷阱 异常向量表,模式变为SVC 将公用寄存器压入SVC:SP所指向的SVC内存栈 获取中断号 进入中断号对应的中断程序 将SVC内存栈的寄存器值弹出到公用寄存器 SPSR赋值给CPSR恢复USER模式 SVC USER

以上为软中断实现的基本步骤,以下为满栈降序式的内存栈为例,进行的软中断实现:

.text
.global _start
_start:
@0
	b reset
@4
	b undef_handler
@8
	b swi_handler @进入异常向量表后,工作模式由user转为svc,从异常向量表跳转到软中断代码段
	b perfetch_handler
	b databort_handler
	nop
	b irq_handler
	b fiq_handler
	

reset:
	@将SVC模式下的栈内存首地址赋给SVC模式的SP寄存器
	ldr r0,=svc_stack
	add r0,#128 @指到栈底
	mov sp,r0	@初始化svc的sp
	
	mrs r0,cpsr
	bic r0,#3
	msr cpsr,r0 @进入user模式
	
	@将USER模式下的栈内存首地址赋给USER模式的SP寄存器
	ldr r0,=user_stack
	add r0,#128 @指到栈底
	mov sp,r0	@初始化user的sp
	
	mov r1,#11
	mov r2,#12
	mov r3,#13
	
	@swi跳转到异常向量表
	swi 10
	nop
	nop
	nop
	
	b .
undef_handler:
swi_handler:
	@将r0~r12,lr寄存器的数据压入svc模式下的内存栈中
	@保护user模式的寄存器现场
	stmfd sp!,{r0-r12,lr} 
	mov r1,#1
	mov r2,#2
	mov r3,#3
	
	@取当前模式的中断号
	sub lr,#4
	ldr r4,[lr]
	bic r4,#0xff000000
	cmp r4,#10
	beq swi_10 @若中断号为10跳转
	cmp r4,#1
	b swi_end
	
	nop
	nop
	nop
	
	movs pc,lr	@跳转回reset

swi_10:
	@将svc模式下内存栈中的数据弹栈到寄存器r0~r12,lr
	@^ 出栈的同时将当前的spsr->cpsr,恢复模式改变前cpsr的寄存器状态
	@将中断前user模式下的寄存器现场恢复
	@将lr的值赋给pc,也就是将程序重新指向中断事件断点处。
	ldmfd sp!,{r0-r12,pc}^ 
swi_end:
	movs r0,#0
	ldmfd sp!,{r0-r12,pc}^	@^ 出栈的同时将当前的spsr->cpsr
perfetch_handler:
databort_handler:
irq_handler:
fiq_handler:
	
.data
svc_stack: .space 128
user_stack: .space 128
.end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/316169
推荐阅读
相关标签
  

闽ICP备14008679号