code:exec - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki

Source

  • exec 的系统调用函数
  • 将 现行进程 转化为 运行某一程序的进程
  • 传入参数
    • name : 欲运行程序的文件路径,保存在
      • u.u_arg[0]
      • u.u_dirp ,原因参看trap 2770
    • argv : 参数数组指针(指向用户态地址空间中参数数组的位置)
      • 参数数组 : 每项 指向 一个参数字符串 ( 用户态地址空间 )

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

3034     ip = namei(&uchar, 0);

3035     if(ip == NULL)

3036          return;

  • ip ← 程序文件的INODE
3037     while(execnt >= NEXEC)

3038          sleep(&execnt, EXPRI);

若同时执行exec进程过多,INODE耗尽,形成资源死锁
3039     execnt++;

3040     bp = getblk(NODEV);

  • 申请 临时缓存块 bp,用于保存参数
3041     if(access(ip, IEXEC) || (ip->i_mode&IFMT)!=0)

3042          goto bad;

  • 检查 ip 的执行权限
  • 检查 ip 是否是特殊文件
3043

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 - 3074
  • 将 参数 从用户态地址空间 读出,写入bp
3052     while(ap = fuword(u.u_arg[1])) {

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;

  • 若 参数字符数 超过 bp大小,则抛出错误
3066           }

3067           if(c == 0)

3068                break;

3069          }

3070     }

3071     if((nc&1) != 0) {

3072          *cp++ = 0;

3073          nc++;

3074     }

  • 若 字符数为奇数,则加入空字符补齐
  • 此处含义不明,列入遗留问题
3075
  • 3076 - 3109
  • 从 程序代码文件 读取 前4个字w[],保存到u.u_arg[0-3]
    • w[0] : 特殊位,用于标识程序特殊性,参看3079,及 man a.out
    • w[1] : 正文段大小
    • w[2] : 数据段大小
    • w[3] : bss区大小
  • 根据 特殊位,作相关设置
这里不详细说明,请参看 man a.out
3076     /* read in first 8 bytes

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

3085     u.u_base = &u.u_arg[0];

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     }

  • 若 程序文件含有正文段 (u.u_arg[1]!=0)
且 该文件作为数据文件被其他进程打开((ip->i_flag&ITEXT)==0&&ip->i_count!=1),则抛出错误
3109

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;

  • ts ← 正文段占用内存块数
  • ds ← 数据段占用内存块数
  • 调用estabur,不是为了 将参数装载到地址映照表,而是为了 检验ts,ds是否超出内存限制
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);
  • 内存图像空间 收缩到 PPDA区大小
  • 必要性 值得 讨论...(列入遗留问题)
3130     xalloc(ip);
3131     c = USIZE+ds+SSIZE;

3132     expand(c);

3133     while(--c >= USIZE)

3134          clearseg(u.u_procp->p_addr+c);

  • 分配 内存图像空间
  • 除PPDA区外,全部清零
3135

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];

3141     u.u_count = u.u_arg[2];

3142     readi(ip);

  • 从 程序文件 读入数据段
  • xalloc 4460 类似
3143

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 - 3165
  • 新用户栈 赋值 为以下形式

3166     /*

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 = &regloc[0]; cp < &regloc[6];)

3187          u.u_ar0[*cp++] = 0;

3188     u.u_ar0[R7] = 0;

  • 将 核心栈 中保存的寄存器值全部置0
  • R6的值不被清,在3155被置
3189     for(ip = &u.u_fsav[0]; ip < &u.u_fsav[25];)

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 /* ------------------------- */

Param

(exec = 11.)
sys exec; name; args
...
name: <...\0>
...
args: arg0; arg1; ...; 0
arg0: <...\0>
arg1: <...\0>
...
⚠️ **GitHub.com Fallback** ⚠️