龙芯汇编语言编程艺术

转自   http://comcat.blog.openrays.org/blog.php?do=showone&tid=368   作者: comcat 发表日期: 2007-04-27 17:49

 

分析系统调用的实现时看到这么一段代码,令人不禁拍案叫绝。

系统调用的参数传递,前4个参数通过a0~a3传,后面的参数要通过栈来传,目前内核
系统调用最长的参数个数为8。

用栈传递参数时,涉及到要将位于用户空间的参数先复制到内核空间(内核栈)。

因为系统调用的参数个数不定,因此就需要判断参数个数为5、6、7、8 不同情况时,
相应的复制操作个数。5个参数时需要复制个数为1,6个时为2,以此类推。

通常的解决方法是用switch语句,这个编译出来,得要四条分支判断语句吧

看看内核的一些牛人怎么实现:



la t1, 5f # 标号5所示之地址入t1
subu t1, t3 # t3 的内容为当前系统调用参数个数减去5,再乘以4
# 这个已经预先计算好,保存于系统调用表每项的第二个
# 字段,用时直接载入。

# 另外,此前已经判断过,t3 的内容大于等于0

1: lw t5, 16(t0) # t0 的内容为用户空间第一个参数的地址

.set push
.set noreorder
.set nomacro

jr t1
addiu t1, 6f - 5f # 妙用分支延迟槽

2: lw t8, 28(t0) # 取用户空间第8个参数
3: lw t7, 24(t0) # 取用户空间第7个参数
4: lw t6, 20(t0) # 取用户空间第6个参数
5: jr t1
sw t5, 16(sp) # 第5个参数进入内核栈

C: sw t8, 28(sp) # 第8个参数进入内核栈
B: sw t7, 24(sp) # 第7个参数进入内核栈
A: sw t6, 20(sp) # 第6个参数进入内核栈
6: j stack_done # 参数复制完毕,返回
nop


只用两条 jr 指令,效率大大提高!简直妙不可言!

下面详细分析之:

(1) t3 的值,在参数个数为5 时,t3 为0,6 时为4,7 时为8,8 时为12
这个 t3 在这里,实际上是用来表示相对于标号5处的地址偏移! 因为mips/godson下,
指令的长度都是4个字节。因此 t3 值为4(参数个数为6)时,第一个 jr t1 是跳转到
标号4处开始执行的。

(2) 第一个 jr t1 用来解决从用户空间复制数据操作的个数问题,相对应的,则是解决写入
操作的个数问题,这个用第二个 jr t1 来解决。在此之前,更新 t1 的指令(addiu)的
位置放的很巧妙,置于第一个 jr t1 的延迟槽中,不占用标号4与标号5之间的空间。

(3) 可以看到参数个数为5时,第二个 jr t1 直接跳转到标号6处执行,将第5个参数写入内
核栈的操作置于延迟槽中;参数个数为6时,会跳转到标号A处执行;参数个数为8时,会
跳转到标号C处执行,依次完成第5、8、7、6参数的写入。


结论:

该段程序的作者对MIPS平台下的延迟槽有深刻的理解,故而才能有如此神乎其技的妙用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值