本文始作于2012年1月29日,刊登于人人网,于2013年2月13日迁移至此
现在是19:16,上午九点多就被曲叫去他家吃饭了,还喝了酒,不过不多。起得太早了,感觉一天都特别困。回来之后开机登录额xmii,它第一次使用是有简单入门提示的,提示还挺简单,很快的功夫就已经能进行基本的界面操作了,操作还都比较简单,但是没说关于配置文件的问题。刚才睡了一觉,现在醒来感觉好多了,越来越感觉现在不像话了,寒假还有不到一个月了,要赶紧写实验,写开发了啊,过两天《和声学》的答案到了,就得开始学和声了,后面还有pureweber的开发任务呢。
昨天最后一点一直过不去,errno一直运作不正确,老是显示-1,昨天晚上的想法是有可能是errno设置的方法不对,可能系统里面有专门设置errno用的函数,一般像Java/C++这样的工程语言都好干这事,明明一句话就能设置,非得调一个函数,用专门的函数设置。今天我在虚拟机里用a.c调试的时候,突然想到这个errno是用户态的啊,他是在who.c里面定义的宏,而我写的who.c里面定义的errno是编译操作系统时的宏,跟本就不是一个变量啊,这根本就是两个地址啊,而且还是一个在用户区一个在内核区,于是我就明白了,在who.c里面自己开一个errno根本就属于掩耳盗铃,自欺欺人嘛,他俩根本就不在一个时代,这就好比一个是真实的人,一个小说中的人物。然后我又进一步想,既然这样,那我要是想把a.c里面errno进行修改就属于修改调用函数外面的变量了,这必须得通过传参啊,而且还是跨界传参,但是iam()和whoiam()参数表不给你传这种东西啊。得动用户态的东西,还传不了地址,这怎么可能办得到呢?后来百度,根本就没有类似的问题,在google,事实证明还是google好使:
errno是libc的全局变量,内核并不会直接访问它。
系统调用返回时,把错误结果放在寄存器%eax中,
libc会把这个%eax复制给errno,然后返回-1给调用的程序。
这样,程序得到的系统调用的结果是-1,具体的错误在errno中。
然后我猛然想到,这是那段汇编代码的事啊,转头看include/unistd.h,就是这段代码:
1 #define _syscall1(type,name,atype,a) \ 2 type name(atype a) \ 3 { \ 4 long __res; \ 5 __asm__ volatile ("int $0x80" \ 6 : "=a" (__res) \ 7 : "0" (__NR_##name),"b" ((long)(a))); \ 8 if (__res >= 0) \ 9 return (type) __res; \ 10 errno = -__res; \ 11 return -1; \ 12 }
宏展开之后他会被展开成:
int iam(const char *name) { long __res; __asm__ volatile ( "int $0x80" : "=a" (__res) : "0" (__NR_iam),"b" ((long)(name))); if (__res >= 0) return int __res; errno = -__res; return -1; }
原来每个系统调用都必须传errno,而且在嵌入汇编的时候就已经写好了,我却还琢磨着自己写呢。还是代码读得不到位啊。更令我惊异的是,从这短代码里可以看出来,传给errno竟然是iam()的return的值!!!我iam()return的值竟然是给errno的!!!还取反了!!!那我return的就应该是-EINVAL了,怪不得昨天看别的系统调用函数的时候看见好多函数return的都是一个宏取负,原来传的就是错误类型。总结一下,在设计系统调用函数的时候,return的是错误类型号,如果return的是非负数则有自己的含义,你自己规定,在这里就表示传过去几个字符串,如果传的是非负数则代表出错类型,把它取反就可以在error.h里查找到是哪种错误。好了,现在改好了,果然就是这个问题,然后就满分了:
testlab2.c 测试通过
testlab2.sh 测试通过

iam.c 代码:
#include <string.h> #include <assert.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #define __LIBRARY__ #include <unistd.h> _syscall1(int, iam, const char*, name); int main(int argc, char *argv[]) { if (strlen(*(argv + 1)) > 23) return 0; iam(*(argv + 1)); return 0; } whoiam.c 代码: #include <string.h> #include <assert.h> #include <stdio.h> #include <errno.h> #define __LIBRARY__ #include <unistd.h> _syscall2(int, whoiam, char *, name, unsigned int, size); int main(void) { char str[100]; whoiam(str, 100); printf("%s\n", str); return 0; } who.c 代码: /* * linux/kernel/who.c * * Copyleft 2012 BlackSun2012 */ #include <errno.h> #include <linux/kernel.h> #include <asm/segment.h> #define MAX 23 char str[MAX + 1]; int sys_iam(const char *name) { int i; for (i = 0; i <= MAX; ++i) { str[i] = get_fs_byte(name + i); if (str[i] == '\0') return i; } return -EINVAL; } int sys_whoiam(char *name, unsigned int size) { int i; extern int errno; for (i = 0; i <= size; ++i) { put_fs_byte(str[i], name + i); if (str[i] == '\0') return i; } return -EINVAL; }
浙公网安备 33010602011771号