历史上的今天
今天是:2024年09月16日(星期一)
2021年09月16日 | TQ2440开发板学习纪实(9)--- 利用Undefined异常模拟BLX指令
2021-09-16 来源:eefocus
本文就利用这个Undefined异常,来模拟BLX指令,从而让使用BLX指令的程序可以正常运行在S3C2440上。
1 Undefined异常的处理流程
ARM9在执行未定义指令时,会跳转到0x00000004处执行,进入Undefined模式,并把下一条指令的地址存入LR。
2 指令模拟的思路
利用Undefined异常处理的一个非常重要的作用就是用来扩展CPU指令集,模拟执行硬件不能直接支持的指令。原理非常简单,在Undefined异常处理中,通过(LR-#4)这个地址就可以获取未定义的指令,然而根据不同的指令写出不同的等价程序即可。
例如本节将要实现的BLX指令,下面是源码事例:
ldr r3, [pc, #32]
ldr r3, [r3]
mov r0, r2
blx r3
其中blx r3的等效源码为:
mov lr, pc
bx r3
需要注意的是:
进入Undefined异常处理时,CPU处于Undefined模式,此时的堆栈与异常前模式不同;
我们的模拟指令程序应该运行在原模式下,而不是Undefined模式下,否则无法获取原来的寄存器环境;
运行模拟指令程序前应保存所有用到的寄存器,运行返回前恢复。否则就会破坏原来的执行环境;
保存寄存器的通用方法就是入栈,而入栈保存需要一定的技巧来保证返回的同时恢复所有寄存器;
在Undefined模式下需要保存LR(此时存放的是原指令的下一条指令),此时不能通过入栈保存,因为Undfined的栈是独立的。变通方式,是存放LR的值到内存中。
3 BLX模拟实现
/* save the instruction's address after the undefined one. */
.global AddrUnd
AddrUnd:
.word 0x00000000
UndHandler:
sub sp, sp, #8
str r0, [sp]
ldr r0, =AddrUnd
str lr, [r0]
ldr r0, =asm_und_handler
str r0, [sp, #4]
ldmfd sp!, {r0, pc}^
这段代码非常简单,实现的功能是保存原指令的下一条指令地址到AddrUnd中,然后跳转到asm_und_handler执行。注意此次跳转也会导致运行模式的变化。
另外为了不破坏寄存器环境,必须采用ldmfd sp!, {r0, pc}的形式来跳转,否则无法恢复r0的值。
实际的指令模拟在asm_und_handler中实现:
.global asm_und_handler
asm_und_handler:
sub sp, sp, #4 /* reserved space for AddrUnd */
stmfd sp!, {r0-r12}
ldr r0, =AddrUnd
ldr r0, [r0]
str r0, [sp, #52]
ldr r0, [r0, #-4] /* get the undefined instruction */
bic r1, r0, #0xF
ldr r2, =0xE12FFF30
cmp r1, r2
beq handle_BLX
ldmfd sp!, {r0-r12, pc}
handle_BLX:
ldr r3, =0xFFFFFFF0
bic r0, r0, r3
cmp r0, #0
beq BLX_R0
cmp r0, #1
beq BLX_R1
cmp r0, #2
beq BLX_R2
cmp r0, #3
beq BLX_R3
cmp r0, #4
beq BLX_R4
cmp r0, #5
beq BLX_R5
cmp r0, #6
beq BLX_R6
cmp r0, #7
beq BLX_R7
cmp r0, #8
beq BLX_R8
cmp r0, #9
beq BLX_R9
cmp r0, #10
beq BLX_R10
cmp r0, #11
beq BLX_R11
cmp r0, #12
beq BLX_R12
ldmfd sp!, {r0-r12, pc}
BLX_R0:
ldmfd sp!, {r0-r12, lr}
bx r0
BLX_R1:
ldmfd sp!, {r0-r12, lr}
bx r1
BLX_R2:
ldmfd sp!, {r0-r12, lr}
bx r2
BLX_R3:
ldmfd sp!, {r0-r12, lr}
bx r3
BLX_R4:
ldmfd sp!, {r0-r12, lr}
bx r4
BLX_R5:
ldmfd sp!, {r0-r12, lr}
bx r5
BLX_R6:
ldmfd sp!, {r0-r12, lr}
bx r6
BLX_R7:
ldmfd sp!, {r0-r12, lr}
bx r7
BLX_R8:
ldmfd sp!, {r0-r12, lr}
bx r8
BLX_R9:
ldmfd sp!, {r0-r12, lr}
bx r9
BLX_R10:
ldmfd sp!, {r0-r12, lr}
bx r10
BLX_R11:
ldmfd sp!, {r0-r12, lr}
bx r11
BLX_R12:
ldmfd sp!, {r0-r12, lr}
bx r12
因为实际中BLX 可以有
BLX r0
BLX r1
…
BLX r12
等12中方式,所以必须对每种方式都加以模拟。
需要注意的是,必须要在执行 bx r12之前确保寄存器环境与原指令运行时的环境完全相同,还是使用了ldmfd的方式来解决这个问题。因为ldmfd要求按照顺序加载寄存器,所以需要一点小技巧了合理安排栈中寄存器的分布。
本例中,对于除了BLX之外的未定义指令,直接忽略并跳转到下一条指令执行。
4 测试
GCC的C语言编译器对于函数指针形式的调用,会产生处BLX汇编指令,下面就是C源码和编译产生的汇编码。
int(*f)(const char*) = puts;
f("Hello BLXn");
对应的汇编码:
ldr r3, .L3+24
str r3, [fp, #-8]
ldr r3, [fp, #-8]
ldr r0, .L3+28
blx r3
S3C2440A这款CPU不支持BLX指令,如果不进行模拟实现,那么就无法实现函数调用的功能。幸好我们上面刚刚实现了BLX的模拟,此时该测试程序顺利执行,并打印出了Hello BLX。
Initialize Keys...[OK]
Initialize LEDs...[OK]
Initialize Beep...[OK]
Hello BLX
I'm idle, waiting for your order
I'm idle, waiting for your order
下一篇: 初始化片外RAM,让程序有更大内存空间
史海拾趣
|
我的平台是wince5.0 用pxa270接wm8750的dac进行音频解码输出,现在想外接dac,那位dx可以解答一下pxa270输出给wm8750的信号是什么格式的?… 查看全部问答> |
|
采用MAX232转换芯片进行串口通信,主要是用于对液晶通过串口的通信,但是液晶总是无法传入数据,无法进行串口中断。麻烦各位前辈帮忙看一下。 void UART1_Init (void) { SCON1 = 0x50;   ...… 查看全部问答> |
|
请教:带 SPI 的 MCU 和 带 SPI 的 Flash 到底怎么连接,谢谢! 大哥,您好! 想您请教一个 MCU 引脚和 flash 引脚相连的问题,好吗? 谢谢! 请教: 芯片手册原文: 20.1.4 从选择(NSS) 从选择(NSS)信号的功能取决于SPI0CN寄存器中NSSMD1和NSSMD0位的设置。有3种可能的方式: 1. NSSMD[1:0] = 00:3 ...… 查看全部问答> |
|
IAR Embedded Workbench Version 3+ for MSP430(tm) User's Guide [ 本帖最后由 wstt 于 2011-9-14 13:34 编辑 ]… 查看全部问答> |
|
之前能仿真的。能下载程序的。 后来设置了一下 就只有不行了 一直是 AXD Uable to halt ARM core 我也不知道哪里出了问题。.   ...… 查看全部问答> |
|
按照网上教程一步一步来做的,但我的出现下面的错误,虚拟机显示界面如下: 在上面的界面停留一段时间后显示下面的界面: 而且在这整个过程中我的 FTP Server 上没有任何信息显示,FTP server日志已打开,用户名 密码也都正确。 co ...… 查看全部问答> |
|
本帖最后由 paulhyde 于 2014-9-15 03:10 编辑 我在申请linear的第一种样片时,加入了购物车,返回在申请第二种时,结果账号强制注销了,登入发现购物车又没样片了 到头来只能有一种能申请。我在TI ADI都没遇到过这种问题,不知怎么解决? ...… 查看全部问答> |




