在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习。我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直达问题本质,把大家从大海捞针的痛苦中解脱出来。
DB(Decrease Before)寻址方式就是在传送数据之前地址递减。下面举例说明。
stmdb r0, {r1-r3} @ 示例汇编代码汇编代码的伪代码如下:
start_address = Rn - (Number_Of_Set_Bits_In(register_list)*4) = r0 - 3*4 = r0 - 12 end_address = Rn - 4 = r0 -4 if ConditionPassed(cond) then address = start_address for i = 0 to 15 @ 遍历所有的寄存器 if register_list[i] == 1 @ 如果在寄存器列表中 Memory[address] = Ri @ 将寄存器中的值存储到内存中 address = address + 4 @ 地址加4,这里是加不是减是因为start_address的计算方式导致的IA(Increase After)寻址方式就是在传送数据之后地址增加。下面举例说明。
ldmia r0, {r1-r3} @ 示例汇编代码汇编代码的伪代码如下:
start_address = Rn = r0 end_address = Rn + (Number_Of_Set_Bits_In(register_list)*4) - 4 = r0 + 3*4 - 4 = r0 + 8 if ConditionPassed(cond) then address = start_address for i = 0 to 15 @ 遍历所有的寄存器 if register_list[i] == 1 @ 如果在寄存器列表中 Ri = Memory[address,4]@ 将内存中的值传送到寄存器中 address = address + 4 @ 地址加4stmfd指令和stmdb指令类似,都使用DB寻址方式。下面以一个示例对stmfd指令进行说明。
指令示例如下:
stmfd sp!, {r4-r7, r9, lr}该示例的伪代码(只演示逻辑,和真正的压栈顺序可能有所不同)如下:
SP = SP - 6×4; @ sp最终指向栈顶(sp的值进行改变是指令中的!指示的) address = SP; @ 这里的address为start_address for i = 4 to 7, 9 @ 通用寄存器r4,r5,r6,r7和r9 Memory[address] = Ri; @ 将通用寄存器中的值压入到栈中 address = address + 4; @ 地址加4(这里是加不是减是由start_address的计算来决定的) Memory[address] = LR; @ 将lr寄存器的值也进行压栈(而且必须放在局部栈的栈底),为了保证函数可以返回压栈过程示意图如下:
Tips:寄存器列表与内存单元的对应关系:编号低的寄存器对应于内存中低地址单元;编号高的寄存器对应于内存中高地址单元。
ldmfd指令和ldmia指令类似,都使用IA寻址方式。下面以一个示例对ldmfd指令进行说明。
指令示例如下:
ldmfd sp!, {r4-r7, r9, pc}该示例的伪代码(仅演示逻辑)如下:
address = SP; @ 这里的address为start_address for i = 4 to 7, 9 @ 通用寄存器r4,r5,r6,r7和r9 Ri = Memory[address,4]; @ 将通用寄存器中的值从栈中弹出到寄存器中 address = address + 4; @ 地址加4 PC = Memory[address,4]; @ 将lr的值(局部栈的栈底存放的是lr的值),令函数返回 SP = address + 4; @ 将end_address+4赋值给SP弹栈过程示意图如下:
lookup_processor_type函数是__lookup_processor_type 函数的C语言格式,所以需要在 __lookup_processor_type的基础上增加压栈和弹栈,以及入参和返回值的处理代码。有了上述指令的详细分析作铺垫,该函数就不难理解了,详见代码注释。
Tips:Arm9汇编和C语言少量传参和返回值一般使用寄存器r0-r3。
/* * This provides a C-API version of the above function. */ ENTRY(lookup_processor_type) stmfd sp!, {r4 - r7, r9, lr} @ 压栈操作(ARM为满减栈),保存现场 mov r9, r0 @ r0是C语言调用汇编时的入参,cpuid bl __lookup_processor_type mov r0, r5 @ r0是C语言调用汇编时的出参,pro_info_list指针 ldmfd sp!, {r4 - r7, r9, pc} @ 弹栈操作,恢复现场<完>