在汇编程序中实现内存块移动xx_memmove的子程序
实验内容:
试编写ARM汇编程序和C语言程序,实现下面的功能:
在汇编程序中实现内存块移动xx_memmove的子程序;
参数1:源地址:
参数2:目的地址;
参数3:移动字节数;
实验步骤:
(一) 在C程序中实现compare函数
compare的功能是比较两个地址参数的大小,并被汇编程序glj_memmove调用;
代码+注释:
int compare(int src, int dest)
{//进来后篡改了R2的值,size(r2)要备份
if(src < dest)//
return 0;//src_dest,src在dest左边,src从后往前拷贝
return 1;//dest_src,否则src在dest右边,src从前往后拷贝
}
(二) 使用给定的memmove_test调用汇编实现的内存块移动函数
代码+注释:
IMPORT cFun
IMPORT compare ;导入compare()
AREA asmfile, CODE, READONLY
EXPORT glj_memmove ;导出glj_memmove()
ENTRY
glj_memmove
;src=M[R[R0]]=M[0x10000FC4]="1234567890ABABABABABABABABABABABABABABABAB"
;dest=M[R[R1]]=M[0x10000FD8]="ABABABABABABABABABABAB"
;size=R[R2]=12
STMFD sp!,{r0-r12,lr};保存进入函数前的现场资源,保存的函数返回地址
mov r4,r0 ;备份src
mov r5,r1 ;备份dest
mov r6,r2 ;备份size
bl compare
cmp r0,#0
mov r0,r4 ;恢复src
mov r1,r5 ;恢复dest
mov r2,r6 ;恢复size
beq src_dest ;src<dest 考虑重叠 src从后往前拷贝
bne dest_src ;src>dest 无所谓重叠 src从前往后拷贝
src_dest
;先判断src,dest是否4字节对齐
;再判断size是否为4字节对齐
mvn r8,#3 ;r8=~0b0011=0b1100
bics r7,r0,r8 ;r7=src&(~0b1100) 保留后两位,与上0x03不是同样的效果?
bics r7,r1,r8 ;r7=dest&(~0b1100) 保留后两位
movne r8,#0 ;此时r8作为标志位,ne满足则r8清零
bne src_dest_1 ;低两位不为0,说明不是4字节对齐
bics r7,r2,r8 ;r7=size&(~0b1100) 保留后两位即为需要1字节拷贝的size
beq src_dest_4 ;若r7=0即没有,则只用四字节拷贝即可
bne src_dest_1 ;r7不为0,需要1字节拷贝
src_dest_4
sub r2,r2,#4 ;r2=r2-4,为后面计算ldr末起始地址服务
add r0,r0,r2 ;r0=src+size-4
add r1,r1,r2 ;r1=dest+size-4
add r2,r2,#4 ;恢复r2 size
src_dest_loop_4 ;注:size非4对齐,末地址也不对齐,可以先一字节搬运,当
ldr r4,[r0],#-4 ;用r4来搬运内存数据(按字),搬完地址-4
str r4,[r1],#-4 ;最后的时候r0,r1多减了4
subs r2,r2,#4 ;统计剩余字节数
bgt src_dest_loop_4 ;还有size,继续重复搬运
b out ;否则,搬完结束,退出子程序
src_dest_1 ;可以分支也可以不分,不分就重写一个;方便起见干脆重写一个src_dest_1_all
sub r2,r2,#1 ;r2=r2-1,为后面计算末地址服务
add r0,r0,r2 ;r0=src+size-1 0+10-1=9
add r1,r1,r2 ;r1=dest+size-1
add r2,r2,#1 ;恢复r2 size
cmp r8,#0
beq src_dest_loop_1_all ;r7!=0
mov r8,r7 ;备份r7
src_dest_loop_1_4
ldrb r4,[r0],#-1;
strb r4,[r1],#-1;结束后r0,r1修正+1 -> ldr -4
;mov r8,r7 ;这玩意不能放循环里,这里r8没用了可以被覆盖,但r7原值后面还有用,先备份
subs r7,r7,#1 ;r7递减计数; 10-8=2; 2-1-1=0; src -> 9-1-1=7 r0,r1修正+1 -> ldr -4这里r8没用了,可以被覆盖
;sub r2,r2,#1 ;同步更新剩余的字节数,多此一举了(这里没法设标志位,否则后面害得cmp)
bne src_dest_loop_1_4
add r0,r0,#1 ;src地址修正为实际末地址+1
add r1,r1,#1 ;dest同上
sub r0,r0,#4 ;
sub r1,r1,#4
subs r2,r2,r8 ;更新剩余的字节数
beq out
b src_dest_loop_4 ;修正好,直接进入循环就可
src_dest_loop_1_all
ldrb r4,[r0],#-1
strb r4,[r1],#-1
sub r2,r2,#1
bne src_dest_loop_1_all
b out
dest_src
mvn r8,#3 ;r8=~0b0011=0b1100
bic r7,r0,r8 ;r7=src&(~0b1100) 保留后两位
bic r8,r1,r8 ;r7=dest&(~0b1100) 保留后两位
orrs r7,r7,r8
bgt dest_src_loop_1;正序不对齐先4后1
dest_src_loop_4
ldr r4,[r0],#4
str r4,[r1],#4
sub r2,r2,#4 ;统计剩余字节数
cmp r2,#4 ;看看剩余字节数是否有4个,若有则正常运行,若无则跳转1字节move
bpl dest_src_loop_4 ;还有size,继续重复搬运
subs r2,r2,#0 ;r2<4,再看r2是否为0,同时更新剩余size
beq out
sub r0,r0,#4 ;地址修正
sub r1,r1,#4
dest_src_loop_1 ;r2不为0,继续1字节move
ldrb r4,[r0],#1 ;!!!
strb r4,[r1],#1 ;!!!
subs r2,r2,#1
bgt dest_src_loop_1
b out
out
LDMFD sp!,{r0-r12,pc};恢复进入函数前的现场资源,把先前保存的函数返回地址传给pc
end
(三) 调试查看结果(debug-watch)
可通过所有测试。
(四) 结果分析
个人制作,仅供参考