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



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

系统调用的参数传递,前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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值