织梦CMS - 轻松建站从此开始!

罗索

MIPS 汇编语言编程的艺术(龙芯适用)

落鹤生 发布于 2010-04-01 22:16 点击:次 
分析系统调用的实现时看到这么一段代码,令人不禁拍案叫绝。系统调用的参数传递,前4个参数通过a0~a3传,后面的参数要通过栈来传,目前内核系统调用最长的参数个数为8。
TAG:

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

系统调用的参数传递,前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平台下的延迟槽有深刻的理解,故而才能有如此神乎其技的妙用。

(秩名)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201004/8970.html]
本文出处:网络博客 作者:秩名
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容