查看MIPS Linux O32 之间接系统调用的源代码
←
MIPS Linux O32 之间接系统调用
跳转到:
导航
,
搜索
因为以下原因,你没有权限编辑本页:
您刚才请求的操作只有这个用户组中的用户才能使用:
用户
您可以查看并复制此页面的源代码:
<br> arch/mips/kernel/scall32-o32.S 中实现了这么一个函数 sys_syscall,该函数位于 O32 之系统调用表的第一项,系统调用号为 4000: <pre> LEAF(sys_syscall) subu t0, a0, __NR_O32_Linux # check syscall number sltiu v0, t0, __NR_O32_Linux_syscalls + 1 beqz t0, einval # do not recurse sll t1, t0, 3 beqz v0, einval lw t2, sys_call_table(t1) # syscall routine /* Some syscalls like execve get their arguments from struct pt_regs and claim zero arguments in the syscall table. Thus we have to assume the worst case and shuffle around all potential arguments. If you want performance, don't use indirect syscalls. */ move a0, a1 # shift argument registers move a1, a2 move a2, a3 lw a3, 16(sp) lw t4, 20(sp) lw t5, 24(sp) lw t6, 28(sp) sw t4, 16(sp) sw t5, 20(sp) sw t6, 24(sp) sw a0, PT_R4(sp) # .. and push back a0 - a3, some sw a1, PT_R5(sp) # syscalls expect them there sw a2, PT_R6(sp) sw a3, PT_R7(sp) sw a3, PT_R26(sp) # update a3 for syscall restarting jr t2 /* Unreached */ einval: li v0, -ENOSYS jr ra END(sys_syscall) </pre> 其第一个参数 a0 是即将要执行的系统调用号,后面的参数是即将要执行的系统调用的参数,因此 sys_syscall 要完成内核栈的调整,然后去执行调用号为 a0 的系统调用,其原型可写为如下: sys_syscall (real_syscall_no, arg1, arg2, arg3 ...) 可用如下测试程序加深理解: <pre> .text .globl main .ent main main: li $4, 4011 # 现 a0 置 execve 系统调用号 lui $5, %hi(cmd) # Load Upper Immediate addiu $5, $5, %lo(cmd) # execve 的第一个参数置于a1, 为字符串/bin/echo的首地址 lui $6, %hi(argv) # %hi, %lo为汇编器定义的宏,分别求地址的高16和低16位 addiu $6, $6, %lo(argv) # execve的第二个参数置于a2, 为字符指针数组的首地址 move $7, $0 # 第三个参数 a3 为0 (NULL) li $2, 4000 # 将 sys_syscall 系统调用号置入v0寄存器 syscall # 触发系统调用 move $2, $0 #main的返回值0, 置于v0 jr $31 #main返回 .end main .data #以下内容位于目标文件的数据段 cmd: .asciiz "/bin/echo" msg: .asciiz "Hello world!" argv: .word cmd # /bin/echo的首地址 .word msg # Hello world!的首地址 .word 0x0 # NULL </pre> 有意思的是这个两个操作: sw a3, PT_R7(sp); sw a3, PT_R26(sp) a3 保存入 pt_regs 结构后,又将其扔入 k0 (r26) 在 pt_regs 的坑中。 事实上 Linux MIPS 之系统调用在设计时,将 a3 又设计为返回 error flag,因此在系统调用时将 error flag 适时放入 pt_regs 之 PT_R7 中,系统调用完,栈恢复时直接将该值恢复入 a3,用户态程序直接从 a3 中取 error flag 即可。 如: arch/mips/kernel/scall32-o32.S <pre> ...... li t0, -EMAXERRNO - 1 # error? sltu t0, t0, v0 sw t0, PT_R7(sp) # set error flag ...... bad_stack: negu v0 # error sw v0, PT_R0(sp) sw v0, PT_R2(sp) li t0, 1 # set error flag sw t0, PT_R7(sp) j o32_syscall_exit ...... </pre> 因此系统调用得这样封装: <pre> #define _syscall1(type,fname,sname,atype,a) \ type fname(atype a) \ { \ register unsigned long __a0 asm("$4") = (unsigned long) a; \ register unsigned long __a3 asm("$7"); \ unsigned long __v0; \ \ __asm__ volatile ( \ ".set\tnoreorder\n\t" \ "li\t$2, %3\t\t\t# " #fname "\n\t" \ "syscall\n\t" \ "move\t%0, $2\n\t" \ ".set\treorder" \ : "=&r" (__v0), "=r" (__a3) \ : "r" (__a0), "i" (__NR_##sname) \ : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "memory"); \ \ if (__a3 == 0) \ return (type) __v0; \ return (type) -1; \ } </pre> 因此此处将 a3 写入 PT_R7(sp) 是有可能被覆盖的,为了保留 a3 以留他用,又将其保存于 k0 的坑中,根据 MIPS ABI,k0 和 k1 任何时候都是不需要保存的。 <br><br> <br><br> <br><br> <br><br>
返回到
MIPS Linux O32 之间接系统调用
。
个人工具
登录
名字空间
页面
讨论
变换
查看
阅读
查看源代码
查看历史
操作
搜索
导航
首页
社区专页
新闻动态
最近更改
随机页面
帮助
工具箱
链入页面
相关更改
特殊页面