code:exec - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki
3008
3009 /*
3010 * exec system call.
3011 * Because of the fact that an I/O buffer is used
3012 * to store the caller’s arguments during exec,
3013 * and more buffers are needed to read in the text file,
3014 * deadly embraces waiting for free buffers are possible.
3015 * Therefore the number of processes simultaneously
3016 * running in exec has to be limited to NEXEC.
3017 */
3018 #define EXPRI -1
3019
3020 exec()
3021 {
3022 int ap, na, nc, *bp;
3023 int ts, ds, sep;
3024 register c, *ip;
3025 register char *cp;
3026 extern uchar;
3027
3028 /*
3029 * pick up file names
3030 * and check various modes
3031 * for execute permission
3032 */
3033
3035 if(ip == NULL)
3036 return;
3037 while(execnt >= NEXEC)
- ip ← 程序文件的INODE
3038 sleep(&execnt, EXPRI);
若同时执行exec进程过多,INODE耗尽,形成资源死锁3039 execnt++;
3040 bp = getblk(NODEV);
3041 if(access(ip, IEXEC) || (ip->i_mode&IFMT)!=0)
- 申请 临时缓存块 bp,用于保存参数
3042 goto bad;
3043
- 检查 ip 的执行权限
- 检查 ip 是否是特殊文件
3044 /*
3045 * pack up arguments into
3046 * allocated disk buffer
3047 */
3048
3049 cp = bp->b_addr;
3050 na = 0;
3051 nc = 0;
- na : 参数个数
- nc : 参数包含的字符数
3052 - 30743052 while(ap = fuword(u.u_arg[1])) {
- 将 参数 从用户态地址空间 读出,写入bp
3053 na++;
3054 if(ap == -1)
3055 goto bad;
3056 u.u_arg[1] =+ 2;
3057 for(;;) {
3058 c = fubyte(ap++);
3059 if(c == -1)
3060 goto bad;
3061 *cp++ = c;
3062 nc++;
3063 if(nc > 510) {
3064 u.u_error = E2BIG;
3065 goto bad;
3066 }
- 若 参数字符数 超过 bp大小,则抛出错误
- 错误代码 : E2BIG
3067 if(c == 0)
3068 break;
3069 }
3070 }
3071 if((nc&1) != 0) {
3072 *cp++ = 0;
3073 nc++;
3074 }
3075
- 若 字符数为奇数,则加入空字符补齐
- 此处含义不明,列入遗留问题
3076 /* read in first 8 bytes这里不详细说明,请参看 man a.out
- 3076 - 3109
- 从 程序代码文件 读取 前4个字w[],保存到u.u_arg[0-3]
- w[0] : 特殊位,用于标识程序特殊性,参看3079,及 man a.out
- w[1] : 正文段大小
- w[2] : 数据段大小
- w[3] : bss区大小
- 根据 特殊位,作相关设置
3077 * of file for segment
3078 * sizes:
3079 * w0 = 407/410/411 (410 -> RO text) (411 -> sep ID)
3080 * w1 = text size
3081 * w2 = data size
3082 * w3 = bss size
3083 */
3084
3086 u.u_count = 8;
3087 u.u_offset[1] = 0;
3088 u.u_offset[0] = 0;
3089 u.u_segflg = 1;
3090 readi(ip);
3091 u.u_segflg = 0;
3092 if(u.u_error)
3093 goto bad;
3094 sep = 0;
3095 if(u.u_arg[0] == 0407) {
3096 u.u_arg[2] =+ u.u_arg[1];
3097 u.u_arg[1] = 0;
3098 } else
3099 if(u.u_arg[0] == 0411)
3100 sep++; else
3101 if(u.u_arg[0] != 0410) {
3102 u.u_error = ENOEXEC;
3103 goto bad;
3104 }
3105 if(u.u_arg[1]!=0&&(ip->i_flag&ITEXT)==0&&ip->i_count!=1){
3106 u.u_error = ETXTBSY;
3107 goto bad;
3108 }
3109且 该文件作为数据文件被其他进程打开((ip->i_flag&ITEXT)==0&&ip->i_count!=1),则抛出错误
- 若 程序文件含有正文段 (u.u_arg[1]!=0)
- 错误代码 : ETXTBSY
- 原因 : 正文段不可被修改
3110 /*
3111 * find text and data sizes
3112 * try them out for possible
3113 * exceed of max sizes
3114 */
3115
3116 ts = ((u.u_arg[1]+63)>>6) & 01777;
3117 ds = ((u.u_arg[2]+u.u_arg[3]+63)>>6) & 0177;
3118 if(estabur(ts, ds, SSIZE, sep))
3119 goto bad;
3120
3121 /*
3122 * allocate and clear core
3123 * at this point, committed
3124 * to the new image
3125 */
3126
3127 u.u_prof[3] = 0;
3128 xfree();
- 停止统计 程序统计直方图
3129 expand(USIZE);
- 释放 当前进程 的共享正文段
3130 xalloc(ip);
- 内存图像空间 收缩到 PPDA区大小
- 必要性 值得 讨论...(列入遗留问题)
3131 c = USIZE+ds+SSIZE;
- 分配 共享正文段
3132 expand(c);
3133 while(--c >= USIZE)
3134 clearseg(u.u_procp->p_addr+c);
3135
- 分配 内存图像空间
- 除PPDA区外,全部清零
3136 /* read in data segment */
3137
3138 estabur(0, ds, 0, 0);
3139 u.u_base = 0;
3140 u.u_offset[1] = 020+u.u_arg[1];
3142 readi(ip);
3143
- 从 程序文件 读入数据段
- 与xalloc 4460 类似
3144 /*
3145 * initialize stack segment
3146 */
3147
3148 u.u_tsize = ts;
3149 u.u_dsize = ds;
3150 u.u_ssize = SSIZE;
3151 u.u_sep = sep;
3152 estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep);
3153 cp = bp->b_addr;
- 置 新的参数,并置 地址映照表
3154 ap = -nc - na*2 - 4;
3155 u.u_ar0[R6] = ap;
3156 suword(ap, na);
3157 c = -nc;
3158 while(na--) {
3159 suword(ap=+2, c);
3160 do
3161 subyte(c++, *cp);
3162 while(*cp++);
3163 }
3164 suword(ap+2, -1);
3165
3153 - 31653166 /*
- 新用户栈 赋值 为以下形式
- 寻址方式: 参看编程技巧#负数表示堆栈区
3167 * set SUID/SGID protections, if no tracing
3168 */
3169
3170 if ((u.u_procp->p_flag&STRC)==0) {
3171 if(ip->i_mode&ISUID)
3172 if(u.u_uid != 0) {
3173 u.u_uid = ip->i_uid;
3174 u.u_procp->p_uid = ip->i_uid;
3175 }
3176 if(ip->i_mode&ISGID)
3177 u.u_gid = ip->i_gid;
3178 }
3179
3180 /* clear sigs, regs, and return */
3181
3182 c = ip;
3183 for(ip = &u.u_signal[0]; ip < &u.u_signal[NSIG]; ip++)
3184 if((*ip & 1) == 0)
3185 *ip = 0;
3186 for(cp = ®loc[0]; cp < ®loc[6];)
- 清 用户 信号处理函数
- 参看 信号系统
3187 u.u_ar0[*cp++] = 0;
3188 u.u_ar0[R7] = 0;
3189 for(ip = &u.u_fsav[0]; ip < &u.u_fsav[25];)
- 将 核心栈 中保存的寄存器值全部置0
- R6的值不被清,在3155被置
3190 *ip++ = 0;
3191 ip = c;
3192
3193 bad:
3194 iput(ip);
3195 brelse(bp);
3196 if(execnt >= NEXEC)
3197 wakeup(&execnt);
3198 execnt--;
3199 }
3200 /* ------------------------- */
- (exec = 11.)
- sys exec; name; args
- ...
- name: <...\0>
- ...
- args: arg0; arg1; ...; 0
- arg0: <...\0>
- arg1: <...\0>
- ...