ash: reduce global data/bss usage
authorDenis Vlasenko <vda.linux@googlemail.com>
Sun, 16 Dec 2007 17:20:38 +0000 (17:20 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sun, 16 Dec 2007 17:20:38 +0000 (17:20 -0000)
(add/remove: 4/29 grow/shrink: 76/21 up/down: 1007/-1713)    Total: -706 bytes
   text    data     bss     dec     hex filename
 777206    1084    8976  787266   c0342 busybox_old
 778077     908    7568  786553   c0079 busybox_unstripped

shell/ash.c

index 4c8a28911e596534bb20d5f93d600219be6640bd..f7604cf93041b07f1cc21bbcc2f16d92e4b585e5 100644 (file)
@@ -67,6 +67,13 @@ extern char **environ;
 #endif
 
 
+/* ============ Hash table sizes. Configurable. */
+
+#define VTABSIZE 39
+#define ATABSIZE 39
+#define CMDTABLESIZE 31         /* should be prime */
+
+
 /* ============ Misc helpers */
 
 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
@@ -127,30 +134,10 @@ static char optlist[NOPTS] ALIGN1;
 
 /* ============ Misc data */
 
-static char nullstr[1] ALIGN1;  /* zero length string */
 static const char homestr[] ALIGN1 = "HOME";
 static const char snlfmt[] ALIGN1 = "%s\n";
 static const char illnum[] ALIGN1 = "Illegal number: %s";
 
-static char *minusc;  /* argument to -c option */
-
-/* pid of main shell */
-static int rootpid;
-/* shell level: 0 for the main shell, 1 for its children, and so on */
-static int shlvl;
-#define rootshell (!shlvl)
-/* trap handler commands */
-static char *trap[NSIG];
-static smallint isloginsh;
-/* current value of signal */
-static char sigmode[NSIG - 1];
-/* indicates specified signal received */
-static char gotsig[NSIG - 1];
-static char *arg0; /* value of $0 */
-
-
-/* ============ Interrupts / exceptions */
-
 /*
  * We enclose jmp_buf in a structure so that we can declare pointers to
  * jump locations.  The global variable handler contains the location to
@@ -163,34 +150,84 @@ static char *arg0; /* value of $0 */
 struct jmploc {
        jmp_buf loc;
 };
-static struct jmploc *exception_handler;
-static int exception;
-/* exceptions */
+
+struct globals_misc {
+       /* pid of main shell */
+       int rootpid;
+       /* shell level: 0 for the main shell, 1 for its children, and so on */
+       int shlvl;
+#define rootshell (!shlvl)
+       char *minusc;  /* argument to -c option */
+
+       char *curdir; // = nullstr;     /* current working directory */
+       char *physdir; // = nullstr;    /* physical working directory */
+
+       char *arg0; /* value of $0 */
+
+       struct jmploc *exception_handler;
+       int exception;
+       /* exceptions */
 #define EXINT 0         /* SIGINT received */
 #define EXERROR 1       /* a generic error */
 #define EXSHELLPROC 2   /* execute a shell procedure */
 #define EXEXEC 3        /* command execution failed */
 #define EXEXIT 4        /* exit the shell */
 #define EXSIG 5         /* trapped signal in wait(1) */
-static volatile int suppressint;
-static volatile sig_atomic_t intpending;
-/* do we generate EXSIG events */
-static int exsig;
-/* last pending signal */
-static volatile sig_atomic_t pendingsig;
-
-/*
- * Sigmode records the current value of the signal handlers for the various
- * modes.  A value of zero means that the current handler is not known.
- * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
- */
-
+       volatile int suppressint;
+       volatile sig_atomic_t intpending;
+       /* do we generate EXSIG events */
+       int exsig;
+       /* last pending signal */
+       volatile sig_atomic_t pendingsig;
+
+       /* trap handler commands */
+       char *trap[NSIG];
+       smallint isloginsh;
+       char nullstr[1];                /* zero length string */
+       /*
+        * Sigmode records the current value of the signal handlers for the various
+        * modes.  A value of zero means that the current handler is not known.
+        * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+        */
+       char sigmode[NSIG - 1];
 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
 #define S_CATCH 2               /* signal is caught */
 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
 #define S_HARD_IGN 4            /* signal is ignored permenantly */
 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
 
+       /* indicates specified signal received */
+       char gotsig[NSIG - 1];
+};
+/* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
+static struct globals_misc *const ptr_to_globals_misc __attribute__ ((section (".data")));
+#define G_misc (*ptr_to_globals_misc)
+#define rootpid   (G_misc.rootpid  )
+#define shlvl     (G_misc.shlvl    )
+#define minusc    (G_misc.minusc   )
+#define curdir    (G_misc.curdir   )
+#define physdir   (G_misc.physdir  )
+#define arg0      (G_misc.arg0     )
+#define exception_handler (G_misc.exception_handler)
+#define exception         (G_misc.exception        )
+#define suppressint       (G_misc.suppressint      )
+#define intpending        (G_misc.intpending       )
+#define exsig             (G_misc.exsig            )
+#define pendingsig        (G_misc.pendingsig       )
+#define trap      (G_misc.trap     )
+#define isloginsh (G_misc.isloginsh)
+#define nullstr   (G_misc.nullstr  )
+#define sigmode   (G_misc.sigmode  )
+#define gotsig    (G_misc.gotsig   )
+#define INIT_G_misc() do { \
+       (*(struct globals_misc**)&ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
+       curdir = nullstr; \
+       physdir = nullstr; \
+} while (0)
+
+
+/* ============ Interrupts / exceptions */
+
 /*
  * These macros allow the user to suspend the handling of interrupt signals
  * over a period of time.  This is similar to SIGHOLD to or sigblock, but
@@ -1090,7 +1127,7 @@ enum {
         * on many machines.  */
        SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
        /* Minimum size of a block */
-       MINSIZE  = SHELL_ALIGN(504),
+       MINSIZE = SHELL_ALIGN(504),
 };
 
 struct stack_block {
@@ -1105,16 +1142,38 @@ struct stackmark {
        struct stackmark *marknext;
 };
 
-static struct stack_block stackbase;
-static struct stack_block *stackp = &stackbase;
-static struct stackmark *markp;
-static char *stacknxt = stackbase.space;
-static size_t stacknleft = MINSIZE;
-static char *sstrend = stackbase.space + MINSIZE;
-static int herefd = -1;
 
-#define stackblock() ((void *)stacknxt)
-#define stackblocksize() stacknleft
+struct globals_memstack {
+       struct stack_block *g_stackp; // = &stackbase;
+       struct stackmark *markp;
+       char *g_stacknxt; // = stackbase.space;
+       char *sstrend; // = stackbase.space + MINSIZE;
+       size_t g_stacknleft; // = MINSIZE;
+       int    herefd; // = -1;
+       struct stack_block stackbase;
+};
+/* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
+static struct globals_memstack *const ptr_to_globals_memstack __attribute__ ((section (".data")));
+#define G_memstack (*ptr_to_globals_memstack)
+#define g_stackp     (G_memstack.g_stackp    )
+#define markp        (G_memstack.markp       )
+#define g_stacknxt   (G_memstack.g_stacknxt  )
+#define sstrend      (G_memstack.sstrend     )
+#define g_stacknleft (G_memstack.g_stacknleft)
+#define herefd       (G_memstack.herefd      )
+#define stackbase    (G_memstack.stackbase   )
+#define INIT_G_memstack() do { \
+       (*(struct globals_memstack**)&ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
+       g_stackp = &stackbase; \
+       g_stacknxt = stackbase.space; \
+       g_stacknleft = MINSIZE; \
+       sstrend = stackbase.space + MINSIZE; \
+       herefd = -1; \
+} while (0)
+
+#define stackblock()     ((void *)g_stacknxt)
+#define stackblocksize() g_stacknleft
+
 
 static void *
 ckrealloc(void * p, size_t nbytes)
@@ -1158,7 +1217,7 @@ stalloc(size_t nbytes)
        size_t aligned;
 
        aligned = SHELL_ALIGN(nbytes);
-       if (aligned > stacknleft) {
+       if (aligned > g_stacknleft) {
                size_t len;
                size_t blocksize;
                struct stack_block *sp;
@@ -1171,16 +1230,16 @@ stalloc(size_t nbytes)
                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
                INT_OFF;
                sp = ckmalloc(len);
-               sp->prev = stackp;
-               stacknxt = sp->space;
-               stacknleft = blocksize;
-               sstrend = stacknxt + blocksize;
-               stackp = sp;
+               sp->prev = g_stackp;
+               g_stacknxt = sp->space;
+               g_stacknleft = blocksize;
+               sstrend = g_stacknxt + blocksize;
+               g_stackp = sp;
                INT_ON;
        }
-       p = stacknxt;
-       stacknxt += aligned;
-       stacknleft -= aligned;
+       p = g_stacknxt;
+       g_stacknxt += aligned;
+       g_stacknleft -= aligned;
        return p;
 }
 
@@ -1188,13 +1247,13 @@ static void
 stunalloc(void *p)
 {
 #if DEBUG
-       if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
+       if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
                write(2, "stunalloc\n", 10);
                abort();
        }
 #endif
-       stacknleft += stacknxt - (char *)p;
-       stacknxt = p;
+       g_stacknleft += g_stacknxt - (char *)p;
+       g_stacknxt = p;
 }
 
 /*
@@ -1210,9 +1269,9 @@ ststrdup(const char *p)
 static void
 setstackmark(struct stackmark *mark)
 {
-       mark->stackp = stackp;
-       mark->stacknxt = stacknxt;
-       mark->stacknleft = stacknleft;
+       mark->stackp = g_stackp;
+       mark->stacknxt = g_stacknxt;
+       mark->stacknleft = g_stacknleft;
        mark->marknext = markp;
        markp = mark;
 }
@@ -1227,13 +1286,13 @@ popstackmark(struct stackmark *mark)
 
        INT_OFF;
        markp = mark->marknext;
-       while (stackp != mark->stackp) {
-               sp = stackp;
-               stackp = sp->prev;
+       while (g_stackp != mark->stackp) {
+               sp = g_stackp;
+               g_stackp = sp->prev;
                free(sp);
        }
-       stacknxt = mark->stacknxt;
-       stacknleft = mark->stacknleft;
+       g_stacknxt = mark->stacknxt;
+       g_stacknleft = mark->stacknleft;
        sstrend = mark->stacknxt + mark->stacknleft;
        INT_ON;
 }
@@ -1252,13 +1311,13 @@ growstackblock(void)
 {
        size_t newlen;
 
-       newlen = stacknleft * 2;
-       if (newlen < stacknleft)
+       newlen = g_stacknleft * 2;
+       if (newlen < g_stacknleft)
                ash_msg_and_raise_error(bb_msg_memory_exhausted);
        if (newlen < 128)
                newlen += 128;
 
-       if (stacknxt == stackp->space && stackp != &stackbase) {
+       if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
                struct stack_block *oldstackp;
                struct stackmark *xmark;
                struct stack_block *sp;
@@ -1266,15 +1325,15 @@ growstackblock(void)
                size_t grosslen;
 
                INT_OFF;
-               oldstackp = stackp;
-               sp = stackp;
+               oldstackp = g_stackp;
+               sp = g_stackp;
                prevstackp = sp->prev;
                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
                sp = ckrealloc(sp, grosslen);
                sp->prev = prevstackp;
-               stackp = sp;
-               stacknxt = sp->space;
-               stacknleft = newlen;
+               g_stackp = sp;
+               g_stacknxt = sp->space;
+               g_stacknleft = newlen;
                sstrend = sp->space + newlen;
 
                /*
@@ -1283,20 +1342,20 @@ growstackblock(void)
                 */
                xmark = markp;
                while (xmark != NULL && xmark->stackp == oldstackp) {
-                       xmark->stackp = stackp;
-                       xmark->stacknxt = stacknxt;
-                       xmark->stacknleft = stacknleft;
+                       xmark->stackp = g_stackp;
+                       xmark->stacknxt = g_stacknxt;
+                       xmark->stacknleft = g_stacknleft;
                        xmark = xmark->marknext;
                }
                INT_ON;
        } else {
-               char *oldspace = stacknxt;
-               int oldlen = stacknleft;
+               char *oldspace = g_stacknxt;
+               int oldlen = g_stacknleft;
                char *p = stalloc(newlen);
 
                /* free the space we just allocated */
-               stacknxt = memcpy(p, oldspace, oldlen);
-               stacknleft += newlen;
+               g_stacknxt = memcpy(p, oldspace, oldlen);
+               g_stacknleft += newlen;
        }
 }
 
@@ -1304,8 +1363,8 @@ static void
 grabstackblock(size_t len)
 {
        len = SHELL_ALIGN(len);
-       stacknxt += len;
-       stacknleft -= len;
+       g_stacknxt += len;
+       g_stacknleft -= len;
 }
 
 /*
@@ -1343,7 +1402,7 @@ growstackstr(void)
 static char *
 makestrspace(size_t newlen, char *p)
 {
-       size_t len = p - stacknxt;
+       size_t len = p - g_stacknxt;
        size_t size = stackblocksize();
 
        for (;;) {
@@ -1568,41 +1627,26 @@ static unsigned long rseed;
 
 /* ============ Shell variables */
 
-/* flags */
-#define VEXPORT         0x01    /* variable is exported */
-#define VREADONLY       0x02    /* variable cannot be modified */
-#define VSTRFIXED       0x04    /* variable struct is statically allocated */
-#define VTEXTFIXED      0x08    /* text is statically allocated */
-#define VSTACK          0x10    /* text is allocated on the stack */
-#define VUNSET          0x20    /* the variable is not set */
-#define VNOFUNC         0x40    /* don't call the callback function */
-#define VNOSET          0x80    /* do not set variable - just readonly test */
-#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
-#ifdef DYNAMIC_VAR
-# define VDYNAMIC       0x200   /* dynamic variable */
-#else
-# define VDYNAMIC       0
-#endif
-
-#ifdef IFS_BROKEN
-static const char defifsvar[] ALIGN1 = "IFS= \t\n";
-#define defifs (defifsvar + 4)
-#else
-static const char defifs[] ALIGN1 = " \t\n";
-#endif
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+struct redirtab {
+       struct redirtab *next;
+       int renamed[10];
+       int nullredirs;
+};
 
 struct shparam {
        int nparam;             /* # of positional parameters (without $0) */
-       unsigned char malloc;   /* if parameter list dynamically allocated */
-       char **p;               /* parameter list */
 #if ENABLE_ASH_GETOPTS
        int optind;             /* next parameter to be processed by getopts */
        int optoff;             /* used by getopts */
 #endif
+       unsigned char malloced; /* if parameter list dynamically allocated */
+       char **p;               /* parameter list */
 };
 
-static struct shparam shellparam;      /* $@ current positional parameters */
-
 /*
  * Free the list of positional parameters.
  */
@@ -1611,7 +1655,7 @@ freeparam(volatile struct shparam *param)
 {
        char **ap;
 
-       if (param->malloc) {
+       if (param->malloced) {
                for (ap = param->p; *ap; ap++)
                        free(*ap);
                free(param->p);
@@ -1619,12 +1663,7 @@ freeparam(volatile struct shparam *param)
 }
 
 #if ENABLE_ASH_GETOPTS
-static void
-getoptsreset(const char *value)
-{
-       shellparam.optind = number(value);
-       shellparam.optoff = -1;
-}
+static void getoptsreset(const char *value);
 #endif
 
 struct var {
@@ -1642,7 +1681,31 @@ struct localvar {
        const char *text;               /* saved text */
 };
 
-/* Forward decls for varinit[] */
+/* flags */
+#define VEXPORT         0x01    /* variable is exported */
+#define VREADONLY       0x02    /* variable cannot be modified */
+#define VSTRFIXED       0x04    /* variable struct is statically allocated */
+#define VTEXTFIXED      0x08    /* text is statically allocated */
+#define VSTACK          0x10    /* text is allocated on the stack */
+#define VUNSET          0x20    /* the variable is not set */
+#define VNOFUNC         0x40    /* don't call the callback function */
+#define VNOSET          0x80    /* do not set variable - just readonly test */
+#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
+#ifdef DYNAMIC_VAR
+# define VDYNAMIC       0x200   /* dynamic variable */
+#else
+# define VDYNAMIC       0
+#endif
+
+#ifdef IFS_BROKEN
+static const char defifsvar[] ALIGN1 = "IFS= \t\n";
+#define defifs (defifsvar + 4)
+#else
+static const char defifs[] ALIGN1 = " \t\n";
+#endif
+
+
+/* Need to be before varinit_data[] */
 #if ENABLE_LOCALE_SUPPORT
 static void
 change_lc_all(const char *value)
@@ -1666,46 +1729,78 @@ static void changepath(const char *);
 static void change_random(const char *);
 #endif
 
-static struct var varinit[] = {
+static const struct {
+       int flags;
+       const char *text;
+       void (*func)(const char *);
+} varinit_data[] = {
 #ifdef IFS_BROKEN
-       { NULL, VSTRFIXED|VTEXTFIXED,           defifsvar,      NULL },
+       { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
 #else
-       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        NULL },
+       { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0"     , NULL            },
 #endif
 #if ENABLE_ASH_MAIL
-       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
-       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
+       { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0"    , changemail      },
+       { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail      },
 #endif
-       { NULL, VSTRFIXED|VTEXTFIXED,           bb_PATH_root_path, changepath },
-       { NULL, VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       NULL },
-       { NULL, VSTRFIXED|VTEXTFIXED,           "PS2=> ",       NULL },
-       { NULL, VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       NULL },
+       { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
+       { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
+       { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
+       { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
 #if ENABLE_ASH_GETOPTS
-       { NULL, VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
+       { VSTRFIXED|VTEXTFIXED       , "OPTIND=1"  , getoptsreset    },
 #endif
 #if ENABLE_ASH_RANDOM_SUPPORT
-       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
+       { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
 #endif
 #if ENABLE_LOCALE_SUPPORT
-       { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0",    change_lc_all },
-       { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0",  change_lc_ctype },
+       { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0"  , change_lc_all   },
+       { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
 #endif
 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
-       { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0",  NULL },
+       { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL            },
 #endif
 };
 
-#define vifs varinit[0]
+
+struct globals_var {
+       struct shparam shellparam;      /* $@ current positional parameters */
+       struct redirtab *redirlist;
+       int g_nullredirs;
+       int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
+       struct var *vartab[VTABSIZE];
+       struct var varinit[ARRAY_SIZE(varinit_data)];
+};
+/* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
+static struct globals_var *const ptr_to_globals_var __attribute__ ((section (".data")));
+#define G_var (*ptr_to_globals_var)
+#define shellparam    (G_var.shellparam   )
+#define redirlist     (G_var.redirlist    )
+#define g_nullredirs  (G_var.g_nullredirs )
+#define preverrout_fd (G_var.preverrout_fd)
+#define vartab        (G_var.vartab       )
+#define varinit       (G_var.varinit      )
+#define INIT_G_var() do { \
+       int i; \
+       (*(struct globals_var**)&ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
+       for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
+               varinit[i].flags = varinit_data[i].flags; \
+               varinit[i].text  = varinit_data[i].text; \
+               varinit[i].func  = varinit_data[i].func; \
+       } \
+} while (0)
+
+#define vifs    varinit[0]
 #if ENABLE_ASH_MAIL
-#define vmail (&vifs)[1]
-#define vmpath (&vmail)[1]
+#define vmail   (&vifs)[1]
+#define vmpath  (&vmail)[1]
 #else
-#define vmpath vifs
+#define vmpath  vifs
 #endif
-#define vpath (&vmpath)[1]
-#define vps1 (&vpath)[1]
-#define vps2 (&vps1)[1]
-#define vps4 (&vps2)[1]
+#define vpath   (&vmpath)[1]
+#define vps1    (&vpath)[1]
+#define vps2    (&vps1)[1]
+#define vps4    (&vps2)[1]
 #define voptind (&vps4)[1]
 #if ENABLE_ASH_GETOPTS
 #define vrandom (&voptind)[1]
@@ -1730,27 +1825,19 @@ static struct var varinit[] = {
 
 #define mpathset()      ((vmpath.flags & VUNSET) == 0)
 
-/*
- * The parsefile structure pointed to by the global variable parsefile
- * contains information about the current file being read.
- */
-struct redirtab {
-       struct redirtab *next;
-       int renamed[10];
-       int nullredirs;
-};
-
-static struct redirtab *redirlist;
-static int nullredirs;
-static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
-
-#define VTABSIZE 39
-
-static struct var *vartab[VTABSIZE];
 
 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 
+#if ENABLE_ASH_GETOPTS
+static void
+getoptsreset(const char *value)
+{
+       shellparam.optind = number(value);
+       shellparam.optoff = -1;
+}
+#endif
+
 /*
  * Return of a legal variable name (a letter or underscore followed by zero or
  * more letters, underscores, and digits).
@@ -2221,9 +2308,6 @@ setprompt(int whichprompt)
 
 static int docd(const char *, int);
 
-static char *curdir = nullstr;          /* current working directory */
-static char *physdir = nullstr;         /* physical working directory */
-
 static int
 cdopt(void)
 {
@@ -2310,7 +2394,7 @@ updatepwd(const char *dir)
 static char *
 getpwd(void)
 {
-       char *dir = getcwd(0, 0);
+       char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
        return dir ? dir : nullstr;
 }
 
@@ -2903,8 +2987,6 @@ static const char syntax_index_table[258] = {
 #define ALIASINUSE 1
 #define ALIASDEAD  2
 
-#define ATABSIZE 39
-
 struct alias {
        struct alias *next;
        char *name;
@@ -2912,7 +2994,12 @@ struct alias {
        int flag;
 };
 
-static struct alias *atab[ATABSIZE];
+
+static struct alias **atab; // [ATABSIZE];
+#define INIT_G_alias() do { \
+       atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
+} while (0)
+
 
 static struct alias **
 __lookupalias(const char *name) {
@@ -4797,7 +4884,7 @@ redirect(union node *redir, int flags)
        int fd;
        int newfd;
 
-       nullredirs++;
+       g_nullredirs++;
        if (!redir) {
                return;
        }
@@ -4807,10 +4894,10 @@ redirect(union node *redir, int flags)
                sv = ckmalloc(sizeof(*sv));
                sv->next = redirlist;
                redirlist = sv;
-               sv->nullredirs = nullredirs - 1;
+               sv->nullredirs = g_nullredirs - 1;
                for (i = 0; i < 10; i++)
                        sv->renamed[i] = EMPTY;
-               nullredirs = 0;
+               g_nullredirs = 0;
        }
        n = redir;
        do {
@@ -4861,7 +4948,7 @@ popredir(int drop)
        struct redirtab *rp;
        int i;
 
-       if (--nullredirs >= 0)
+       if (--g_nullredirs >= 0)
                return;
        INT_OFF;
        rp = redirlist;
@@ -4880,7 +4967,7 @@ popredir(int drop)
                }
        }
        redirlist = rp->next;
-       nullredirs = rp->nullredirs;
+       g_nullredirs = rp->nullredirs;
        free(rp);
        INT_ON;
 }
@@ -4896,7 +4983,7 @@ static void
 clearredir(int drop)
 {
        for (;;) {
-               nullredirs = 0;
+               g_nullredirs = 0;
                if (!redirlist)
                        break;
                popredir(drop);
@@ -6458,7 +6545,6 @@ static void find_command(char *, struct cmdentry *, int, const char *);
  * would make the command name "hash" a misnomer.
  */
 
-#define CMDTABLESIZE 31         /* should be prime */
 #define ARB 1                   /* actual size determined at run time */
 
 struct tblentry {
@@ -6469,8 +6555,13 @@ struct tblentry {
        char cmdname[ARB];      /* name of command */
 };
 
-static struct tblentry *cmdtable[CMDTABLESIZE];
-static int builtinloc = -1;             /* index in path of %builtin, or -1 */
+static struct tblentry **cmdtable;
+#define INIT_G_cmdtable() do { \
+       cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
+} while (0)
+
+static int builtinloc = -1;     /* index in path of %builtin, or -1 */
+
 
 static void
 tryexec(char *cmd, char **argv, char **envp)
@@ -7840,7 +7931,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
        savehandler = exception_handler;
        exception_handler = &jmploc;
        localvars = NULL;
-       shellparam.malloc = 0;
+       shellparam.malloced = 0;
        func->count++;
        funcnest++;
        INT_ON;
@@ -7851,7 +7942,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
        shellparam.optoff = -1;
 #endif
        evaltree(&func->n, flags & EV_TESTED);
-funcdone:
+ funcdone:
        INT_OFF;
        funcnest--;
        freefunc(func);
@@ -8979,7 +9070,7 @@ setparam(char **argv)
        }
        *ap = NULL;
        freeparam(&shellparam);
-       shellparam.malloc = 1;
+       shellparam.malloced = 1;
        shellparam.nparam = nparam;
        shellparam.p = newparam;
 #if ENABLE_ASH_GETOPTS
@@ -9094,7 +9185,7 @@ shiftcmd(int argc, char **argv)
        INT_OFF;
        shellparam.nparam -= n;
        for (ap1 = shellparam.p; --n >= 0; ap1++) {
-               if (shellparam.malloc)
+               if (shellparam.malloced)
                        free(*ap1);
        }
        ap2 = shellparam.p;
@@ -10971,7 +11062,7 @@ dotcmd(int argc, char **argv)
 
                if (argc > 2) {
                        saveparam = shellparam;
-                       shellparam.malloc = 0;
+                       shellparam.malloced = 0;
                        shellparam.nparam = argc - 2;
                        shellparam.p = argv + 2;
                };
@@ -12741,7 +12832,7 @@ procargs(int argc, char **argv)
        shellparam.optind = 1;
        shellparam.optoff = -1;
 #endif
-       /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+       /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
        while (*xargv) {
                shellparam.nparam++;
                xargv++;
@@ -12805,6 +12896,13 @@ int ash_main(int argc, char **argv)
        struct jmploc jmploc;
        struct stackmark smark;
 
+       /* Initialize global data */
+       INIT_G_misc();
+       INIT_G_memstack();
+       INIT_G_var();
+       INIT_G_alias();
+       INIT_G_cmdtable();
+
 #if PROFILE
        monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
 #endif