<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.jackslab.org/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-cn">
		<id>http://wiki.jackslab.org/index.php?action=history&amp;feed=atom&amp;title=MIPS_Linux_O32_%E4%B9%8B%E9%97%B4%E6%8E%A5%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8</id>
		<title>MIPS Linux O32 之间接系统调用 - 版本历史</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.jackslab.org/index.php?action=history&amp;feed=atom&amp;title=MIPS_Linux_O32_%E4%B9%8B%E9%97%B4%E6%8E%A5%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8"/>
		<link rel="alternate" type="text/html" href="http://wiki.jackslab.org/index.php?title=MIPS_Linux_O32_%E4%B9%8B%E9%97%B4%E6%8E%A5%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8&amp;action=history"/>
		<updated>2026-09-11T05:16:45Z</updated>
		<subtitle>本wiki的该页面的版本历史</subtitle>
		<generator>MediaWiki 1.19.2</generator>

	<entry>
		<id>http://wiki.jackslab.org/index.php?title=MIPS_Linux_O32_%E4%B9%8B%E9%97%B4%E6%8E%A5%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8&amp;diff=257&amp;oldid=prev</id>
		<title>2013年1月18日 (五) 08:38 Comcat</title>
		<link rel="alternate" type="text/html" href="http://wiki.jackslab.org/index.php?title=MIPS_Linux_O32_%E4%B9%8B%E9%97%B4%E6%8E%A5%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8&amp;diff=257&amp;oldid=prev"/>
				<updated>2013-01-18T08:38:22Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table class='diff diff-contentalign-left'&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
			&lt;tr valign='top'&gt;
			&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←上一版本&lt;/td&gt;
			&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;2013年1月18日 (五) 08:38的版本&lt;/td&gt;
			&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第141行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第141行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;}&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&amp;#160;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;因此此处将 a3 写入 PT_R7(sp) 是有可能被覆盖的，为了保留 a3 以留他用，又将其保存于 k0 的坑中，根据 MIPS ABI，k0 和 k1 任何时候都是不需要保存的。&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;因此此处将 a3 写入 PT_R7(sp) 是有可能被覆盖的，为了保留 a3 以留他用，又将其保存于 k0 的坑中，根据 MIPS ABI，k0 和 k1 任何时候都是不需要保存的。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Comcat</name></author>	</entry>

	<entry>
		<id>http://wiki.jackslab.org/index.php?title=MIPS_Linux_O32_%E4%B9%8B%E9%97%B4%E6%8E%A5%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8&amp;diff=256&amp;oldid=prev</id>
		<title>Comcat：以“&lt;br&gt; arch/mips/kernel/scall32-o32.S 中实现了这么一个函数 sys_syscall，该函数位于 O32 之系统调用表的第一项，系统调用号为 4000：  &lt;pr...”为内容创建页面</title>
		<link rel="alternate" type="text/html" href="http://wiki.jackslab.org/index.php?title=MIPS_Linux_O32_%E4%B9%8B%E9%97%B4%E6%8E%A5%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8&amp;diff=256&amp;oldid=prev"/>
				<updated>2013-01-18T08:38:01Z</updated>
		
		<summary type="html">&lt;p&gt;以“&amp;lt;br&amp;gt; arch/mips/kernel/scall32-o32.S 中实现了这么一个函数 sys_syscall，该函数位于 O32 之系统调用表的第一项，系统调用号为 4000：  &amp;lt;pr...”为内容创建页面&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;br&amp;gt;&lt;br /&gt;
arch/mips/kernel/scall32-o32.S 中实现了这么一个函数 sys_syscall，该函数位于 O32 之系统调用表的第一项，系统调用号为 4000：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LEAF(sys_syscall)&lt;br /&gt;
subu    t0, a0, __NR_O32_Linux    # check syscall number&lt;br /&gt;
sltiu    v0, t0, __NR_O32_Linux_syscalls + 1&lt;br /&gt;
beqz    t0, einval        # do not recurse&lt;br /&gt;
sll    t1, t0, 3&lt;br /&gt;
beqz    v0, einval&lt;br /&gt;
lw    t2, sys_call_table(t1)        # syscall routine&lt;br /&gt;
&lt;br /&gt;
/* Some syscalls like execve get their arguments from struct pt_regs&lt;br /&gt;
and claim zero arguments in the syscall table. Thus we have to&lt;br /&gt;
assume the worst case and shuffle around all potential arguments.&lt;br /&gt;
If you want performance, don't use indirect syscalls. */&lt;br /&gt;
&lt;br /&gt;
move    a0, a1                # shift argument registers&lt;br /&gt;
move    a1, a2&lt;br /&gt;
move    a2, a3&lt;br /&gt;
lw    a3, 16(sp)&lt;br /&gt;
lw    t4, 20(sp)&lt;br /&gt;
lw    t5, 24(sp)&lt;br /&gt;
lw    t6, 28(sp)&lt;br /&gt;
sw    t4, 16(sp)&lt;br /&gt;
sw    t5, 20(sp)&lt;br /&gt;
sw    t6, 24(sp)&lt;br /&gt;
sw    a0, PT_R4(sp)            # .. and push back a0 - a3, some&lt;br /&gt;
sw    a1, PT_R5(sp)            # syscalls expect them there&lt;br /&gt;
sw    a2, PT_R6(sp)&lt;br /&gt;
sw    a3, PT_R7(sp)&lt;br /&gt;
sw    a3, PT_R26(sp)            # update a3 for syscall restarting&lt;br /&gt;
jr    t2&lt;br /&gt;
/* Unreached */&lt;br /&gt;
&lt;br /&gt;
einval:    li    v0, -ENOSYS&lt;br /&gt;
jr    ra&lt;br /&gt;
END(sys_syscall)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
其第一个参数 a0 是即将要执行的系统调用号，后面的参数是即将要执行的系统调用的参数，因此 sys_syscall 要完成内核栈的调整，然后去执行调用号为 a0 的系统调用，其原型可写为如下：&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  sys_syscall (real_syscall_no, arg1, arg2, arg3 ...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
可用如下测试程序加深理解：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.text                             &lt;br /&gt;
.globl    main                    &lt;br /&gt;
.ent      main                  &lt;br /&gt;
&lt;br /&gt;
main:                              &lt;br /&gt;
li        $4, 4011                # 现 a0 置 execve 系统调用号&lt;br /&gt;
lui       $5, %hi(cmd)            # Load Upper Immediate&lt;br /&gt;
addiu     $5, $5, %lo(cmd)       # execve 的第一个参数置于a1, 为字符串/bin/echo的首地址&lt;br /&gt;
&lt;br /&gt;
lui       $6, %hi(argv)            # %hi, %lo为汇编器定义的宏，分别求地址的高16和低16位&lt;br /&gt;
addiu     $6, $6, %lo(argv)       # execve的第二个参数置于a2, 为字符指针数组的首地址&lt;br /&gt;
&lt;br /&gt;
move      $7, $0                 # 第三个参数 a3 为0 (NULL)&lt;br /&gt;
li        $2, 4000                 # 将 sys_syscall 系统调用号置入v0寄存器&lt;br /&gt;
syscall                            # 触发系统调用&lt;br /&gt;
&lt;br /&gt;
move      $2, $0                  #main的返回值0, 置于v0&lt;br /&gt;
jr        $31                     #main返回&lt;br /&gt;
&lt;br /&gt;
.end   main                     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.data                             #以下内容位于目标文件的数据段&lt;br /&gt;
&lt;br /&gt;
cmd:&lt;br /&gt;
.asciiz     &amp;quot;/bin/echo&amp;quot;&lt;br /&gt;
&lt;br /&gt;
msg:&lt;br /&gt;
.asciiz     &amp;quot;Hello world!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
argv:&lt;br /&gt;
.word     cmd         # /bin/echo的首地址&lt;br /&gt;
.word     msg         # Hello world!的首地址&lt;br /&gt;
.word     0x0         # NULL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
有意思的是这个两个操作： sw    a3, PT_R7(sp); sw    a3, PT_R26(sp) &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
a3 保存入 pt_regs 结构后，又将其扔入 k0 (r26) 在 pt_regs 的坑中。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
事实上 Linux MIPS 之系统调用在设计时，将 a3 又设计为返回 error flag，因此在系统调用时将 error flag 适时放入 pt_regs 之 PT_R7 中，系统调用完，栈恢复时直接将该值恢复入 a3，用户态程序直接从 a3 中取 error flag 即可。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
如： arch/mips/kernel/scall32-o32.S&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
......&lt;br /&gt;
li  t0, -EMAXERRNO - 1  # error?&lt;br /&gt;
sltu    t0, t0, v0&lt;br /&gt;
sw  t0, PT_R7(sp)       # set error flag&lt;br /&gt;
......&lt;br /&gt;
&lt;br /&gt;
bad_stack:&lt;br /&gt;
negu    v0              # error&lt;br /&gt;
sw  v0, PT_R0(sp)&lt;br /&gt;
sw  v0, PT_R2(sp)&lt;br /&gt;
li  t0, 1               # set error flag&lt;br /&gt;
sw  t0, PT_R7(sp)&lt;br /&gt;
j   o32_syscall_exit&lt;br /&gt;
......&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
因此系统调用得这样封装：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#define _syscall1(type,fname,sname,atype,a) \&lt;br /&gt;
type fname(atype a) \&lt;br /&gt;
{ \&lt;br /&gt;
register unsigned long __a0 asm(&amp;quot;$4&amp;quot;) = (unsigned long) a; \&lt;br /&gt;
register unsigned long __a3 asm(&amp;quot;$7&amp;quot;); \&lt;br /&gt;
unsigned long __v0; \&lt;br /&gt;
\&lt;br /&gt;
__asm__ volatile ( \&lt;br /&gt;
&amp;quot;.set\tnoreorder\n\t&amp;quot; \&lt;br /&gt;
&amp;quot;li\t$2, %3\t\t\t# &amp;quot; #fname &amp;quot;\n\t&amp;quot; \&lt;br /&gt;
&amp;quot;syscall\n\t&amp;quot; \&lt;br /&gt;
&amp;quot;move\t%0, $2\n\t&amp;quot; \&lt;br /&gt;
&amp;quot;.set\treorder&amp;quot; \&lt;br /&gt;
: &amp;quot;=&amp;amp;r&amp;quot; (__v0), &amp;quot;=r&amp;quot; (__a3) \&lt;br /&gt;
: &amp;quot;r&amp;quot; (__a0), &amp;quot;i&amp;quot; (__NR_##sname) \&lt;br /&gt;
: &amp;quot;$2&amp;quot;, &amp;quot;$8&amp;quot;, &amp;quot;$9&amp;quot;, &amp;quot;$10&amp;quot;, &amp;quot;$11&amp;quot;, &amp;quot;$12&amp;quot;, &amp;quot;$13&amp;quot;, &amp;quot;$14&amp;quot;, &amp;quot;$15&amp;quot;, &amp;quot;$24&amp;quot;, \&lt;br /&gt;
&amp;quot;memory&amp;quot;); \&lt;br /&gt;
\&lt;br /&gt;
        if (__a3 == 0) \&lt;br /&gt;
return (type) __v0; \&lt;br /&gt;
return (type) -1; \&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
因此此处将 a3 写入 PT_R7(sp) 是有可能被覆盖的，为了保留 a3 以留他用，又将其保存于 k0 的坑中，根据 MIPS ABI，k0 和 k1 任何时候都是不需要保存的。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Comcat</name></author>	</entry>

	</feed>