Annotation of coherent/b/bin/c/n0/i386/bind.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * n0/i386/bind.c
        !             3:  * Machine-specific parts of the C compiler parser.
        !             4:  * i386.
        !             5:  */
        !             6: 
        !             7: #ifdef   vax
        !             8: #include "INC$LIB:cc0.h"
        !             9: #else
        !            10: #include "cc0.h"
        !            11: #endif
        !            12: 
        !            13: /* Local stack: local offset and register mask. */
        !            14: typedef        struct  locals  {
        !            15:        struct  locals *l_lstp;
        !            16:        ival_t  l_lofs;
        !            17:        int     l_mask;
        !            18: }      LOCALS;
        !            19: 
        !            20: LOCALS *clstp;                 /* Local stack                  */
        !            21: ival_t clofs;                  /* Current local offset         */
        !            22: int    cmask;                  /* Current mask                 */
        !            23: ival_t llofs;                  /* Last local offset reported   */
        !            24: int    lmask;                  /* Last register mask reported  */
        !            25: int    alignment;              /* Alignment from #pragma       */
        !            26: 
        !            27: /*
        !            28:  * This table is indexed by C type to obtain the size
        !            29:  * in bytes of a machine object.
        !            30:  */
        !            31: int     mysizes[] = {
        !            32:        0,                      /* T_NONE               */
        !            33:        1,      1,              /* T_CHAR    T_UCHAR    */
        !            34:        2,      2,              /* T_SHORT   T_USHORT   */
        !            35:        4,      4,              /* T_INT     T_UINT     */
        !            36:        4,                      /* T_PTR                */
        !            37:        4,      4,              /* T_LONG    T_ULONG    */
        !            38:        4,      8,              /* T_FLOAT   T_DOUBLE   */
        !            39:        0,                      /* T_VOID               */
        !            40:        0,      0,              /* T_STRUCT  T_FSTRUCT  */
        !            41:        0,      0,              /* T_UNION   T_FUNION   */
        !            42:        0,      0               /* T_ENUM    T_FENUM    */
        !            43: };
        !            44: 
        !            45: /*
        !            46:  * This table is indexed by C type to obtain the machine type,
        !            47:  * as defined in 'mch.h'.
        !            48:  */
        !            49: char    mytypes[] = {
        !            50:        0,                      /* T_NONE               */
        !            51:        S8,     U8,             /* T_CHAR    T_UCHAR    */
        !            52:        S16,    U16,            /* T_SHORT   T_USHORT   */
        !            53:        S32,    U32,            /* T_INT     T_UINT     */
        !            54:        PTR,                    /* T_PTR                */
        !            55:        S32,    U32,            /* T_LONG    T_ULONG    */
        !            56:        F32,    F64,            /* T_FLOAT   T_DOUBLE   */
        !            57:        S32,                    /* T_VOID               */
        !            58:        BLK,    0,              /* T_STRUCT  T_FSTRUCT  */
        !            59:        BLK,    0,              /* T_UNION   T_FUNION   */
        !            60:        0,      0               /* T_ENUM    T_FENUM    */
        !            61: };
        !            62: 
        !            63: /*
        !            64:  * main() calls this routine to perform machine-dependent parser setup.
        !            65:  */
        !            66: vinit()
        !            67: {
        !            68: #if    MONOLITHIC
        !            69:        alignment = 0;
        !            70: #endif
        !            71: }
        !            72: 
        !            73: /*
        !            74:  * Empty the local binding stack and mark the unavailable registers.
        !            75:  */
        !            76: initlocals()
        !            77: {
        !            78:        clstp = NULL;
        !            79:        llofs = clofs = 0;
        !            80:        lmask = cmask = BESP|BEBP;
        !            81:        bput(AUTOS);
        !            82:        iput(clofs);
        !            83:        iput((ival_t)cmask);
        !            84: }
        !            85: 
        !            86: /*
        !            87:  * Save the current state of the local bindings.
        !            88:  */
        !            89: savelocals()
        !            90: {
        !            91:        register LOCALS *lstp;
        !            92: 
        !            93:        lstp = (LOCALS *) new(sizeof(LOCALS));
        !            94:        lstp->l_lstp = clstp;
        !            95:        lstp->l_lofs = clofs;
        !            96:        lstp->l_mask = cmask;
        !            97:        clstp = lstp;
        !            98: }
        !            99: 
        !           100: /*
        !           101:  * Restore locals.
        !           102:  * Tell the code generator if it changes.
        !           103:  */
        !           104: restlocals()
        !           105: {
        !           106:        register LOCALS *lstp;
        !           107: 
        !           108:        if ((lstp=clstp) == NULL)
        !           109:                cbotch("restlocals");
        !           110:        clstp = lstp->l_lstp;
        !           111:        clofs = lstp->l_lofs;
        !           112:        cmask = lstp->l_mask;
        !           113:        putautos();
        !           114:        free((char *) lstp);
        !           115: }
        !           116: 
        !           117: /*
        !           118:  * Inform the code generator (and perhaps the optimizer)
        !           119:  * about the current automatic variable allocation.
        !           120:  */
        !           121: putautos()
        !           122: {
        !           123:        if (clofs != llofs || cmask != lmask) {
        !           124:                llofs = clofs;
        !           125:                lmask = cmask;
        !           126:                bput(AUTOS);
        !           127:                iput(-clofs);
        !           128:                iput((ival_t)cmask);
        !           129:        }
        !           130: }
        !           131: 
        !           132: /*
        !           133:  * Bind locals to the correct place on the stack frame.
        !           134:  * Locals grow down from EBP, e.g. EBP-4, EBP-8, etc.
        !           135:  */
        !           136: bindlocal(sp) register SYM *sp;
        !           137: {
        !           138:        register int c, regno;
        !           139: 
        !           140:        if ((c = sp->s_class) == C_REG) {
        !           141:                if ((regno = grabreg(sp)) >= 0) {
        !           142:                        sp->s_value = regno;
        !           143:                        return;
        !           144:                }
        !           145:                /* Demote register local to auto. */
        !           146:                setclass(sp, C_AUTO);
        !           147:        }
        !           148:        if (c==C_AUTO || c==C_REG) {
        !           149:                clofs -= ssize(sp);
        !           150:                /* Keep stack dword-aligned. */
        !           151:                if ((clofs & 3) != 0)
        !           152:                        clofs &= ~3;
        !           153:                sp->s_value = clofs;
        !           154:                if (clofs >= 0)
        !           155:                        cerror("auto \"%s\" is not addressable", sp->s_id);
        !           156:        }
        !           157: }
        !           158: 
        !           159: /*
        !           160:  * Attempt to get a register for symbol 'sp'.
        !           161:  * Only integer dword objects go in registers currently.
        !           162:  * Chars, shorts and floats could go in registers if loadreg() were changed.
        !           163:  * Return register id if successful, -1 otherwise.
        !           164:  */
        !           165: grabreg(sp) register SYM *sp;
        !           166: {
        !           167:        register DIM *dp;
        !           168:        register int type;
        !           169: 
        !           170:        if ((dp = sp->s_dp) != NULL)
        !           171:                return (dp->d_type == D_PTR) ? allocreg() : -1;
        !           172:        type = sp->s_type;
        !           173:        if (type >= T_INT && type <= T_ULONG)
        !           174:                return allocreg();
        !           175:        return -1;
        !           176: }
        !           177: /*
        !           178:  * Allocate a register.
        !           179:  * Currently allocates EBX, ESI and EDI.
        !           180:  * Return register id if successful, -1 otherwise.
        !           181:  */
        !           182: int
        !           183: allocreg()
        !           184: {
        !           185:        if ((cmask&BEBX) == 0) {
        !           186:                cmask |= BEBX;
        !           187:                return EBX;
        !           188:        } else if ((cmask&BESI) == 0) {
        !           189:                cmask |= BESI;
        !           190:                return ESI;
        !           191:        } else if ((cmask&BEDI) == 0) {
        !           192:                cmask |= BEDI;
        !           193:                return EDI;
        !           194:        } else
        !           195:                return -1;
        !           196: }
        !           197: 
        !           198: /*
        !           199:  * Bind arguments.
        !           200:  * Stack frame during function execution:
        !           201:  *             ...
        !           202:  *     ebp+8   arg1
        !           203:  *     ebp+4   return address
        !           204:  *     ebp     saved ebp
        !           205:  *     ebp-4   auto1
        !           206:  *             ...
        !           207:        ebp-n   autolast
        !           208:  *     ebp-n-4 saved esi       [if required]
        !           209:  *     ebp-n-8 saved edi       [if required]
        !           210:  *     ebp-n-12 saved ebx      [if required]
        !           211:  */
        !           212: bindargs()
        !           213: {
        !           214:        register SYM *sp;
        !           215:        register int i;
        !           216:        register ival_t offset;
        !           217: 
        !           218:        offset = 8;                             /* arg1 offset */
        !           219:        for (i = 0; i < nargs; ++i) {
        !           220:                sp = args[i];
        !           221:                if (sp->s_class != C_PREG)
        !           222:                        sp->s_class = C_PAUTO;
        !           223:                sp->s_value = offset;
        !           224:                offset += ssize(sp);
        !           225:                /* Keep parameters dword-aligned. */
        !           226:                if ((offset & 3) != 0)
        !           227:                        offset = (offset + 3) & ~3;
        !           228:        }
        !           229: }
        !           230: 
        !           231: /*
        !           232:  * Copy register arguments from the stack into the register.
        !           233:  * Change class of the argument to plain register.
        !           234:  * Note that bindargs() has put the stack displacement
        !           235:  * into the 's_value' field of the argument symbol.
        !           236:  */
        !           237: loadargs()
        !           238: {
        !           239:        register SYM *sp;
        !           240:        register int i, r;
        !           241:        register ival_t v;
        !           242: 
        !           243:        for (i = 0; i < nargs; ++i) {
        !           244:                sp = args[i];
        !           245:                if (sp->s_class == C_PREG) {
        !           246:                        if ((r=grabreg(sp)) >= 0) {
        !           247:                                v = sp->s_value;        /* stack offset */
        !           248:                                sp->s_class = C_REG;
        !           249:                                sp->s_value = r;        /* register number */
        !           250:                                loadreg(sp, v);
        !           251:                                continue;
        !           252:                        }
        !           253:                        /* Demote parametric register to parametric auto. */
        !           254:                        setclass(sp, C_PAUTO);
        !           255:                }
        !           256:        }
        !           257: }
        !           258: 
        !           259: /*
        !           260:  * Change the storage class of sp.
        !           261:  * Issue a 'strict' warning if desired.
        !           262:  */
        !           263: setclass(sp, c) register SYM *sp; int c;
        !           264: {
        !           265:        sp->s_class = c;
        !           266:        if (isvariant(VSNREG))
        !           267:                cstrict("identifier \"%s\" not bound to register", sp->s_id);
        !           268: }
        !           269: 
        !           270: /*
        !           271:  * Load symbol 'sp' from offset 'offset' in the frame.
        !           272:  * Since register variables are always dwords,
        !           273:  * the type can always be setup to T_INT.
        !           274:  */
        !           275: loadreg(sp, offset) SYM *sp; ival_t offset;
        !           276: {
        !           277:        register TREE   *lp, *rp, *tp;
        !           278: 
        !           279:        newtree(sizeof(TREE));
        !           280:        lp = talloc();
        !           281:        lp->t_op = REG;
        !           282:        lp->t_type = T_INT;
        !           283:        lp->t_reg = sp->s_value;
        !           284:        rp = talloc();
        !           285:        rp->t_op = PID;
        !           286:        rp->t_type = T_INT;
        !           287:        rp->t_offs = offset;
        !           288:        tp = build(ASSIGN, lp, rp);
        !           289:        putautos();
        !           290:        tput(EEXPR, 0, tp);
        !           291: }
        !           292: 
        !           293: /*
        !           294:  * Process a #pragma.
        !           295:  * Currently recognizes only "#pragma align [n]".
        !           296:  * Return 1 if recognized, 0 if not.
        !           297:  */
        !           298: pragma(p) char *p;
        !           299: {
        !           300:        static char align[] = "align";
        !           301: 
        !           302:        while (*p == ' ' || *p == '\t')
        !           303:                ++p;
        !           304:        if (strncmp(align, p, sizeof(align)-1) == 0) {
        !           305:                alignment = atoi(p + sizeof(align)-1);
        !           306:                if (alignment < 0) {
        !           307:                        cerror("#pragma align: bad alignment %d", alignment);
        !           308:                        alignment = 0;
        !           309:                }
        !           310:                return 1;
        !           311:        }
        !           312:        return 0;
        !           313: }
        !           314: 
        !           315: /*
        !           316:  * Look at type 't', DIM list 'dp' and field width 'w' (0 for non fields)
        !           317:  * and return the bit offset of the base of the structure member.
        !           318:  * The 'offset' argument is the current bit offset in the structure or union.
        !           319:  * Check for fields that are too wide, bad field base types, and arrange
        !           320:  * that the byte, word or dword that spans the field can be grabbed in one grab.
        !           321:  * See comments in bindlocal() above concerning reals and bitfield alignment.
        !           322:  */
        !           323: long
        !           324: fieldalign(t, dp, ip, w, offset)
        !           325: register DIM   *dp;
        !           326: INFO           *ip;
        !           327: register int   w;
        !           328: long           offset;
        !           329: {
        !           330:        register long bitwidth, amask, a;
        !           331: 
        !           332:        /*
        !           333:         * Find bit width of type t;
        !           334:         * e.g. 8 for char, 16 for short, 32 for int or ptr.
        !           335:         */
        !           336:        if (dp != NULL) {
        !           337:                switch(dp->d_type) {
        !           338:                case D_FUNC:    t = T_PTR;      break;
        !           339:                case D_PTR:     t = T_PTR;      break;
        !           340:                case D_ARRAY:                   break;
        !           341:                case D_MOSAR:                   break;
        !           342:                default:        cbotch("fieldalign %d", dp->d_type);
        !           343:                }
        !           344:        } else if (t == T_FENUM)
        !           345:                t = T_INT;
        !           346:        else if (t == T_ENUM)
        !           347:                t = ip->i_type;
        !           348:        if (alignment == 0) {
        !           349:                if (t == T_STRUCT || t == T_UNION)
        !           350:                        bitwidth = 8 * saligntype(ip);
        !           351:                else
        !           352:                        bitwidth = 8 * mysizes[t];
        !           353:                if (bitwidth == 0)
        !           354:                        bitwidth = 32;
        !           355:                amask = bitwidth - 1;
        !           356:        } else {
        !           357:                if (t == T_STRUCT || t == T_UNION)
        !           358:                        a = saligntype(ip);
        !           359:                else
        !           360:                        a = (mysizes[t] == 0) ? 4 : mysizes[t];
        !           361:                amask = 8 * ((a < alignment) ? a : alignment) - 1;
        !           362:                bitwidth = 8 * a;
        !           363:        }
        !           364:        if (w != 0) {
        !           365:                /* Nonzero width bitfield. */
        !           366:                if (dp != NULL)
        !           367:                        cerror("non scalar field");
        !           368:                if (bitwidth > 32)
        !           369:                        cerror("bad base type for field");
        !           370: #if    0
        !           371:                if (w > bitwidth)
        !           372:                        cerror("field too wide");
        !           373: #endif
        !           374:                /* Bump to next alignment boundary if necessary. */
        !           375:                if ((offset & amask) + w > bitwidth)
        !           376:                        offset = (offset + amask) & ~amask;
        !           377:        } else {
        !           378:                /* Zero width bitfield or non field. */
        !           379:                offset = (offset + amask) & ~amask;
        !           380:        }
        !           381:        return offset;
        !           382: }
        !           383: 
        !           384: /*
        !           385:  * Convert a tree into its low level form.
        !           386:  * Fill in the machine type byte looking at the C type
        !           387:  * and the segment information.
        !           388:  */
        !           389: TREE *
        !           390: transform(tp, why, above) register TREE *tp; int why, above;
        !           391: {
        !           392:        register TREE *lp;
        !           393:        register int t;
        !           394:        register int wd;
        !           395: 
        !           396:        /*
        !           397:         * The way that this code looks at the DIM lists to decide
        !           398:         * what type of conversion is inserted makes me sick.
        !           399:         * The correct type of conversion node (MUL, DIV, etc.)
        !           400:         * should really be inserted when the tree is constructed,
        !           401:         * guided by a table.
        !           402:         */
        !           403:        if (tp->t_op == CONVERT) {
        !           404:                lp = tp->t_lp;
        !           405:                if (tp->t_dp!=NULL && lp->t_dp==NULL && why!=REXPR) {
        !           406:                        tp->t_op = MUL;
        !           407:                        tp->t_dp = NULL;
        !           408:                        if (lp->t_type != T_INT)
        !           409:                                tp->t_lp = bconvert(lp, T_INT, NULL,NULL,NULL);
        !           410:                        tp->t_type = T_INT;
        !           411:                } else if (tp->t_dp==NULL && lp->t_dp!=NULL && tp->t_rp!=NULL) {
        !           412:                        tp->t_op = DIV;
        !           413:                        lp->t_dp = NULL;
        !           414:                        lp->t_type = T_INT;
        !           415:                }
        !           416:        }
        !           417: 
        !           418:        /* Fixup any remaining ZCONs. */
        !           419:        if (tp->t_op == ZCON) {
        !           420:                tp->t_op = ICON;
        !           421:                tp->t_type = T_INT;
        !           422:                tp->t_ival = tp->t_zval;
        !           423:        }
        !           424: 
        !           425:        /* Set the type field. */
        !           426:        if (tp->t_dp != NULL)
        !           427:                tp->t_type = mytypes[T_PTR];
        !           428:        else if ((t=tp->t_type)==T_FSTRUCT || t==T_FUNION || t==T_FENUM) {
        !           429:                unksize(t, tp->t_ip);
        !           430:                tp->t_type = S32;               /* default to S32 */
        !           431:        } else {
        !           432:                if (t == T_ENUM)
        !           433:                        t = tp->t_ip->i_type;   /* enum base type */
        !           434:                tp->t_type = mytypes[t];
        !           435:        }
        !           436: 
        !           437:        if (tp->t_op >= MIOBASE) {
        !           438:                wd = why;
        !           439:                if (why == REXPR)
        !           440:                        wd = EEXPR;
        !           441:                tp->t_lp = transform(tp->t_lp, wd, tp->t_op);
        !           442:                if (tp->t_op!=FIELD && tp->t_rp!=NULL)
        !           443:                        tp->t_rp = transform(tp->t_rp, wd, -1);
        !           444:                if (tp->t_op==CONVERT && tp->t_rp==NULL) {
        !           445:                        lp = tp->t_lp;
        !           446:                        if (tp->t_type == lp->t_type)
        !           447:                                tp = lp;
        !           448:                }
        !           449:        }
        !           450:        return tp;
        !           451: }
        !           452: 
        !           453: /*
        !           454:  * Check if the operator 'op' applied to C types 'lt' and 'rt'
        !           455:  * (which are outputs from tltype(), which means that all pointers
        !           456:  * have been converted to type T_PTR) involves no conversions.
        !           457:  * This means the code generator must deal with the type mismatch.
        !           458:  */
        !           459: noconvert(op, lt, rt) register int op, lt, rt;
        !           460: {
        !           461:        if (op==ASSIGN || op==CAST || (op>=EQ && op<=ULT)) {
        !           462:                if ((lt>=T_CHAR && lt<=T_UCHAR)
        !           463:                &&  (rt>=T_CHAR && rt<=T_UCHAR))
        !           464:                        return 1;               /* 8-bit types */
        !           465:                if ((lt>=T_SHORT && lt<=T_USHORT)       
        !           466:                &&  (rt>=T_SHORT && rt<=T_USHORT))
        !           467:                        return 1;               /* 16-bit types */
        !           468:                if ((lt>=T_INT  && lt<=T_ULONG)
        !           469:                &&  (rt>=T_INT  && rt<=T_ULONG))
        !           470:                        return 1;               /* 32-bit types */
        !           471:                if (op==CAST && lt==T_FLOAT && rt==T_DOUBLE)
        !           472:                        return 1;               /* (float)double */
        !           473:        }
        !           474:        return 0;
        !           475: }
        !           476: 
        !           477: /*
        !           478:  * Align the location counter well enough for the object 'sp'.
        !           479:  */
        !           480: align(sp) SYM *sp;
        !           481: {
        !           482:        bput(ALIGN);
        !           483:        bput(aligntype(sp));
        !           484: }
        !           485: 
        !           486: /*
        !           487:  * Return the appropriate alignment type for 'sp'.
        !           488:  * The alignment type is 1 for byte, 2 for word, 4 for dword.
        !           489:  */
        !           490: aligntype(sp) SYM *sp;
        !           491: {
        !           492:        register int type, atype, dtype;
        !           493:        register DIM *dp;
        !           494: 
        !           495:        if (alignment != 0)
        !           496:                return alignment;       /* use #pragma-defined alignment */
        !           497:        type = sp->s_type;
        !           498:        atype = mysizes[type];
        !           499:        if ((dp = sp->s_dp) != NULL) {
        !           500:                while (dp != NULL
        !           501:                    && ((dtype = dp->d_type) == D_ARRAY || dtype == D_MOSAR))
        !           502:                        dp = dp->d_dp;
        !           503:                if (dtype == D_PTR || dtype == D_FUNC)
        !           504:                        return 4;       /* pointer to, function returning */
        !           505:        }
        !           506:        if (atype == 1 || atype == 2 || (atype == 4 && type != T_PTR))
        !           507:                return atype;           /* chars, shorts, ints, longs, floats */
        !           508:        else if (type == T_DOUBLE)
        !           509:                return 4;               /* dword alignment, not qword */
        !           510:        else if (type == T_STRUCT || type == T_UNION)
        !           511:                return saligntype(sp->s_ip);
        !           512:        else if (type == T_ENUM)
        !           513:                return mytypes[sp->s_ip->i_type];       /* enum base type */
        !           514:        else if (type == T_FSTRUCT || type == T_FUNION || type == T_FENUM) {
        !           515:                cerror("alignment of %s \"%s\" is not known",
        !           516:                        (type == T_FSTRUCT) ? "struct"
        !           517:                      : (type == T_FUNION)  ? "union"
        !           518:                      : "enum",
        !           519:                        sp->s_id);
        !           520:                return 4;
        !           521:        }
        !           522:        /* T_NONE, T_PTR, T_VOID */
        !           523:        cbotch("aligntype type=%d", type);
        !           524: }
        !           525: 
        !           526: /*
        !           527:  * Run down a struct INFO list to find alignment type.
        !           528:  */
        !           529: int
        !           530: saligntype(ip) register INFO *ip;
        !           531: {
        !           532:        register int i, j, max, n;
        !           533: 
        !           534:        if (alignment != 0)
        !           535:                return alignment;
        !           536:        n = ip->i_nsp;                  /* number of members */
        !           537:        for (i = max = 0; i < n; i++) {
        !           538:                j = aligntype(ip->i_sp[i]);
        !           539:                if (j > max)
        !           540:                        max = j;
        !           541:        }
        !           542:        return max;
        !           543: }
        !           544: 
        !           545: /*
        !           546:  * Given a field type, return an appropriate alignment type.
        !           547:  */
        !           548: int
        !           549: faligntype(t) register int t;
        !           550: {
        !           551:        if (t <= T_ULONG && t != T_PTR)
        !           552:                return mysizes[t];
        !           553:        cbotch("faligntype %d", t);
        !           554: }
        !           555: 
        !           556: /*
        !           557:  * Check object sizes for overflow.
        !           558:  */
        !           559: sizeof_t
        !           560: szcheck(n, a, s) sizeof_t n; int a; char *s;
        !           561: {
        !           562:        return n;
        !           563: }
        !           564: 
        !           565: #if    FOLD_DOUBLES
        !           566: /*
        !           567:  * Convert DCON to/from host double.
        !           568:  * Used by the double constant folder in n0/fold.c.
        !           569:  * Assumes host fp representation == target fp representation!
        !           570:  * The byte orders of the double and DCON are reversed.
        !           571:  */
        !           572: double
        !           573: dval_to_d(tp) TREE *tp;
        !           574: {
        !           575:        double d;
        !           576:        register char *src, *dst;
        !           577: 
        !           578:        for (src = tp->t_dval, dst = ((char *)&d) + sizeof(d) - 1; dst >= &d; )
        !           579:                *dst-- = *src++;
        !           580:        return d;
        !           581: }
        !           582: 
        !           583: void
        !           584: d_to_dval(tp, d) TREE *tp; double d;
        !           585: {
        !           586:        register char *src, *dst;
        !           587: 
        !           588:        for (dst = tp->t_dval, src = ((char *)&d) + sizeof(d) - 1; src >= &d; )
        !           589:                *dst++ = *src--;
        !           590: }
        !           591: #endif
        !           592: 
        !           593: /* end of n0/i386/bind.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.