ARM汇编中BL指令不能实现跳转

hhhhjjaa 2011-05-01 04:06:58
USR_STACK_LEGTH EQU 64
SVC_STACK_LEGTH EQU 0
FIQ_STACK_LEGTH EQU 16
IRQ_STACK_LEGTH EQU 64
ABT_STACK_LEGTH EQU 0
UND_STACK_LEGTH EQU 0
AREA Example5,CODE,READONLY
ENTRY
CODE32
START MOV R0,#0
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R5,#5
MOV R6,#6
MOV R7,#7
MOV R8,#8
MOV R9,#9
MOV R10,#10
MOV R11,#11
MOV R12,#12

BL InitStack
MRS R0,CPSR
BIC R0,R0,#80
MSR CPSR_cxsf,R0

MSR CPSR_c,#0xd0
MRS R0,CPSR

MSR CPSR_c,#0xdf
MRS R0,CPSR

HALT B HALT

InitStack MOV R0,LR
MSR CPSR_c,#0xd3
LDR SP,StackSvc

MSR CPSR_c,#0xd2
LDR SP,StackIrq

MSR CPSR_c,#0xd1
LDR SP,StackFiq

MSR CPSR_c,#0xd7
LDR SP,StackAbt

MSR CPSR_c,#0xdb
LDR SP,StackUnd

MSR CPSR_c,#0xdf
LDR SP,StackUsr

MOV PC,R0

StackUsr DCD UsrStackSpace+(USR_STACK_LEGTH-1)*4
StackSvc DCD SvcStackSpace+(SVC_STACK_LEGTH-1)*4
StackIrq DCD IrqStackSpace+(IRQ_STACK_LEGTH-1)*4
StackFiq DCD FiqStackSpace+(FIQ_STACK_LEGTH-1)*4
StackAbt DCD AbtStackSpace+(ABT_STACK_LEGTH-1)*4
StackUnd DCD UndStackSpace+(UND_STACK_LEGTH-1)*4

AREA MyStacks,DATA,NOINIT,ALIGN=2
UsrStackSpace SPACE USR_STACK_LEGTH*4
SvcStackSpace SPACE SVC_STACK_LEGTH*4
IrqStackSpace SPACE IRQ_STACK_LEGTH*4
FiqStackSpace SPACE FIQ_STACK_LEGTH*4
AbtStackSpace SPACE ABT_STACK_LEGTH*4
UndStackSpace SPACE UND_STACK_LEGTH*4

END

为啥BL不能实现跳转呢?而用B的话就可以?
期待各位大侠回答。
...全文
1202 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
梅希的博客 2011-07-26
  • 打赏
  • 举报
回复
你的程序没有问题。问题在于你调式时的方法。

原因:BL调的是子程序,这就是相当于你在vc上跟c的代码一样,F10与F11的区别
hhhhjjaa 2011-05-03
  • 打赏
  • 举报
回复
谢谢xiaopoy兄耐心的讲解,现在明白了许多。
hhhhjjaa 2011-05-03
  • 打赏
  • 举报
回复
五楼那位仁兄说的对,要用step in来进入子程序。那是不是说BL指令把标号和MOV PC,LR之间的代码当做子程序,因而只能用step in进入。而B指令不能够返回,所以没有MOV PC,LR指令,B只是跳到纯粹的一个标号而已。不明白的是B指令用step和step in都可进行跳转,用step in时它把哪部分当做子程序,难道它把标号之后直至结束的代码当做子程序?
xiaopoy 2011-05-03
  • 打赏
  • 举报
回复
首先说明下,我不懂ARM的,因为这个是RISC体系的,以前反编译过MIPS的东西,所以有点了解。
希望不会误导到你也希望可以帮到你,但你应该再去查查相关资料的。 /:^]

是这样的:
BL是arm汇编中用来调用子程序的指令,它把BL后面一条指令的地址放到R14寄存器里,R15寄存器(PC当前指针地址)就设置成要跳往的地址。这样在这个子程序返回时,再mov PC, R14就可以返回到BL后面的地址了。
B不一样,B是直接 mov PC, 目标地址;而不保存其后的地址到R14。
这对于调试而言是大有区别的,跳转在正常的程序里都是用在一段函数里自己的流程中的,而子程序调用却是到另一个函数的执行流程里了。
比方
char * FormatTime (char * Out, char * Day, char * Hour, char * Minutes, char * Seconds)
{
Out[0]= '\0';
strcat ( Out, "天:");
strcat ( Out, Day);
strcat ( Out, "小时:");
strcat ( Out, Hour);
strcat ( Out, "分钟:");
strcat ( Out, Minutes);
strcat ( Out, "秒:");
strcat ( Out, Seconds);
}
调试这个FormatTime 时不会想要跟进strcat看它怎么把你的时间和"天:"们连接起来的,这时就需要一个调试方式可以步过strcat这种子函数,在BL strcat的时候直接到R14指定的返回地址等执行过来。
而正常的流程里的
if (TRUE)
{
//blabla 1
}
else
{
//blabla 2
}
这样的if判断,就是一个B或者带条件的B了,而需要弄明白它是怎样执行的,就肯定需要跟着B执行过去的目标,一步步沿着CPU执行指令的流程跟踪。这样就需要一种每个指令都中断一下的方式,对应步入,这样的方式就叫做步入了。

我简单搜索了下,发现SWI(软件使用的中断,通常这样的设计是给操作系统使用),BKPT(软件模拟抛出硬件中断)这二个是arm里的产生中断的指令,根据经验,步过这种调试方式,应该是用BKPT软件模拟中断指令实现的,在碰到BL时候,调试器会把BL后面的指令替换成一个BKPT,然后执行回来到BKPT上时候,抛出的异常会被调试器捕获到,自然实现了需要的步过效果了。
而步入的效果,一般是CPU自己所支持的,但需要一个标志位或类似的什么设置来开启CPU每执行一个指令就抛出异常给调试器捕获。我在arm_architecture里找了半天,没有发现有对应的标志位,再搜索发现gdb对arm上的步入是用这种方式实现的,碰到BL之类的指令(BLX, mov PC, reg等等操作当前PC的指令)时,都会预测出来要跳转过去的指令地址,然后在目标的指令地址上下一个BKPT断点,这样来在目标位置断下的。 /:^]

而一个子程序的结束位置,这是没有一个可以绝对确定的定义的,特别是在RISC CPUs体系上面,可以操作PC的指令超多,怎么返回也不为过啊。不过一般可以这样认为,把R14寄存器里的值设置到PC上的指令,它的位置就是子函数结束的位置了。当然还有这样一种常见的情况,把一些需要备份的寄存器和返回地址保存在堆栈里,
STMFD r13!, {其他reg, R14};//r13是arm里的sp堆栈指针,大部分的RISC都这样的。
在需要返回时候再给从堆栈弹回来:
LDMFD r13!, {其他reg, PC};
同时一个函数可能有多个返回的位置,所以不必强究一个子函数的结束地址在哪儿。可以跟踪明白它内部的处理流程就好了。
xiaopoy 2011-05-03
  • 打赏
  • 举报
回复
我觉得是你调试时的问题,应该用 步入,而不是步过子程序。这样就可以看到bl所进入的子程序InitStack的执行过程了。
zouxunlong 2011-05-02
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 elkyboy2010 的回复:]

用JMP进行语句跳转
[/Quote]

这是ARM,不是Intel,实际上他们的原理都差不多。我们如果C学得不错,那么汇编也会学得好。
zouxunlong 2011-05-02
  • 打赏
  • 举报
回复
BL用于子程序调用,将InitStack改为子程序试试。
Elkyboy2010 2011-05-02
  • 打赏
  • 举报
回复
用JMP进行语句跳转
大熊猫侯佩 2011-05-01
  • 打赏
  • 举报
回复
顶,ARM不熟。
原作者:宛城布衣。 本文件已移除PDF签名,如内容有误,欢迎大家指正。 目录 前言 i 目录 I ARM7TDMI(-S)指令集及汇编1 ARM 处理器寻址方式2 寄存器寻址2 立即寻址2 寄存器偏移寻址2 寄存器间接寻址3 基址寻址3 多寄存器寻址4 堆栈寻址4 块拷贝寻址5 相对寻址5 指令集介绍7 ARM 指令集7 指令格式7 第 2 个操作数7 #immed_8r 7 Rm8 Rm,shift8 条件码9 ARM 存储器访问指令 11 LDR 和 STR 11 LDM 和 STM14 SWP 17 ARM 数据处理指令19 数据传送指令20 MOV 20 MVN 20 算术逻辑运算指令20 ADD 20 SUB21 RSB 21 ADC 21 SBC 21 RSC 22 AND 22 ORR22 EOR22 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII BIC 23 第 I 页常用 ARM 指令集及汇编 Ver:1010 比较指令23 CMP 23 CMN23 TST24 TEQ24 乘法指令25 MUL25 MLA25 UMULL25 UMLAL26 SMULL 26 SMLAL 26 ARM 跳转指令27 B27 BL27 BX 27 ARM 协处理器指令28 CDP28 LDC29 STC 29 MCR30 MRC30 ARM 杂项指令31 SWI 31 MRS 32 MSR 33 ARM指令34 ADR 35 ADRL35 LDR36 NOP37 Thumb 指令集39 Thumb 指令集与 ARM 指令集的区别 39 Thumb 存储器访问指令 40 LDR 和 STR 41 PUSH 和 POP 43 LDMIA 和 STMIA 43 Thumb 数据处理指令 45 数据传送指令46 MOV 46 MVN 46 NEG47 算术逻辑运算指令47 ADD 47 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 第 II 页常用 ARM 指令集及汇编 Ver:1010 SUB48 ADC 49 SBC 49 MUL50 AND 50 ORR50 EOR51 BIC 51 ASR51 LSL52 LSR 52 ROR53 比较指令53 CMP 53 CMN54 TST54 Thumb 跳转指令 55 B 55 BL55 BX 55 Thumb 杂项指令 56 SWI 56 Thumb 伪指令 57 ADR 57 LDR57 NOP58 伪指令59 符号定义伪指令59 GBLA、GBLL、GBLS 59 LCLA、LCLL、LCLS60 SETA、SETL、SETS 61 RLIST61 CN 62 CP62 DN、SN62 FN63 数据定义伪指令63 LTORG64 MAP64 FIELD 65 SPACE66 DCB 66 DCD 和 DCDU67 DCDO 67 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 第 III 页常用 ARM 指令集及汇编 Ver:1010 DCFD 和 DCFDU68 DCFS 和 DCFSU68 DCI69 DCQ 和 DCQU69 DCW 和 DCWU 70 报告伪指令70 ASSERT 70 INFO 71 OPT 71 TTL 和 SUBT 72 汇编控制伪指令73 IF、ELSE 和 ENDIF73 MACRO 和 MEND 74 WHIL 和 WEND 75 杂项伪指令76 ALIGN 77 AREA78 CODE16 和 CODE32 79 END 80 ENTRY80 EQU 81 EXPORT 和 GLOBAL 81 IMPORT 和 EXTERN 82 GET 和 INCLUDE 83 INCBIN83 KEEP83 NOFP 84 REQUIRE 84 PEQUIRE8 和 PRESERVE8 84 RN 84 ROUT85 ARM指令86 ADR 86 ADRL86 LDR86
详细解释了uboot的start.s的每行代码; 添加了相关知识点的详细解释,包括: 4.1. 如何查看C或汇编的源代码所对应的真正的汇编代码 67 4.2. uboot初始化,为何要设置CPU为SVC模式而不是设置为其他模式 69 4.3. 什么是watchdog + 为何在要系统初始化的时候关闭watchdog 70 4.3.1. 什么是watchdog 71 4.3.2. 为何在要系统初始化的时候关闭watchdog 71 4.4. 为何ARM7PC=PC+8 71 4.4.1. 为何ARM9和ARM7一样,也是PC=PC+8 73 4.5. AMR寄存器的别名 + APCS 79 4.5.1. ARM的寄存器的别名 79 4.5.2. 什么是APCS 81 4.6. 为何C语言(的函数调用)需要堆栈,而汇编语言却不需要堆栈 81 4.6.1. 保存现场/上下文 82 4.6.1.1. 什么叫做上下文context 82 4.6.2. 传递参数 82 4.6.3. 举例分析C语言函数调用是如何使用堆栈的 83 4.7. 关于为何不直接用mov指令,而非要用adr伪指令 84 4.8. mov指令的操作数的取值范围到底是多少 85 4.9. 汇编学习总结记录 89 4.9.1. 汇编的标号=C的标号 89 4.9.2. 汇编跳转指令=C的goto 89 4.9.3. 汇编的.globl=C语言的extern 90 4.9.4. 汇编bl指令和mov pc,lr来实现子函数调用和返回 90 4.9.5. 汇编的对应位置有存储值的标号 = C语言的指针变量 91 4.9.6. 汇编的ldr+标号,来实现C的函数调用 93 4.9.7. 汇编设置某个寄存器的值或给某个地址赋值 94

21,458

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧