cross-compilation of sh(1) from x86 to arm
Jilles Tjoelker
jilles at stack.nl
Sun Mar 3 23:19:35 UTC 2013
There has long been a bug in sh(1) where it assumes (in mksyntax.c) that
the properties of char are the same between build and run environments.
This assumption does not hold if a cross build is done for arm on an x86
machine. The main effect is that such a miscompiled sh incorrectly
handles characters with bit 7 set. Various tests in
tools/regression/bin/sh start failing, possibly in ways that eat huge
amounts of CPU time and memory.
Christoph Mallon has submitted a fix for this and I have committed it to
head and stable/9. It has, however, only been tested on x86 using the
-funsigned-char compiler option to create the discrepancy.
Below is a backport of the fix to stable/8. It needs r247733 or at least
the bin/sh/mksyntax.c of that revision.
Because I had to fix some conflicts and stable/8's sh differs quite a
bit from head's, I would like to have some testing first before
committing this. I again tested only on amd64 with and without the
-funsigned-char compiler option and tools/regression/bin/sh. If the
cross-compilation need not be supported on stable/8, I am fine with
leaving it unfixed in stable/8.
Index: bin/sh
===================================================================
--- bin/sh (revision 247733)
+++ bin/sh (working copy)
Property changes on: bin/sh
___________________________________________________________________
Modified: svn:mergeinfo
Merged /head/bin/sh:r246522
Index: bin/sh/mksyntax.c
===================================================================
--- bin/sh/mksyntax.c (revision 247733)
+++ bin/sh/mksyntax.c (working copy)
@@ -101,23 +101,16 @@
static FILE *cfile;
static FILE *hfile;
-static const char *syntax[513];
-static int base;
-static int size; /* number of values which a char variable can have */
-static int nbits; /* number of bits in a character */
-static void filltable(const char *);
-static void init(void);
+static void add_default(void);
+static void finish(void);
+static void init(const char *);
static void add(const char *, const char *);
-static void print(const char *);
static void output_type_macros(void);
int
main(int argc __unused, char **argv __unused)
{
- char c;
- char d;
- int sign;
int i;
char buf[80];
int pos;
@@ -134,28 +127,9 @@
fputs(writer, hfile);
fputs(writer, cfile);
- /* Determine the characteristics of chars. */
- c = -1;
- sign = (c > 0) ? 0 : 1;
- for (nbits = 1 ; ; nbits++) {
- d = (1 << nbits) - 1;
- if (d == c)
- break;
- }
-#if 0
- printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
-#endif
- if (nbits > 9) {
- fputs("Characters can't have more than 9 bits\n", stderr);
- exit(2);
- }
- size = (1 << nbits) + 1;
- base = 1;
- if (sign)
- base += 1 << (nbits - 1);
-
fputs("#include <sys/cdefs.h>\n", hfile);
fputs("#include <ctype.h>\n", hfile);
+ fputs("#include <limits.h>\n\n", hfile);
/* Generate the #define statements in the header file */
fputs("/* Syntax classes */\n", hfile);
@@ -176,8 +150,8 @@
fprintf(hfile, "/* %s */\n", is_entry[i].comment);
}
putc('\n', hfile);
- fprintf(hfile, "#define SYNBASE %d\n", base);
- fprintf(hfile, "#define PEOF %d\n\n", -base);
+ fputs("#define SYNBASE (1 - CHAR_MIN)\n", hfile);
+ fputs("#define PEOF -SYNBASE\n\n", hfile);
putc('\n', hfile);
fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
@@ -188,10 +162,13 @@
putc('\n', hfile);
/* Generate the syntax tables. */
+ fputs("#include \"parser.h\"\n", cfile);
fputs("#include \"shell.h\"\n", cfile);
fputs("#include \"syntax.h\"\n\n", cfile);
- init();
+
fputs("/* syntax table used when not in quotes */\n", cfile);
+ init("basesyntax");
+ add_default();
add("\n", "CNL");
add("\\", "CBACK");
add("'", "CSQUOTE");
@@ -200,9 +177,11 @@
add("$", "CVAR");
add("}", "CENDVAR");
add("<>();&| \t", "CSPCL");
- print("basesyntax");
- init();
+ finish();
+
fputs("\n/* syntax table used when in double quotes */\n", cfile);
+ init("dqsyntax");
+ add_default();
add("\n", "CNL");
add("\\", "CBACK");
add("\"", "CENDQUOTE");
@@ -211,16 +190,20 @@
add("}", "CENDVAR");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-", "CCTL");
- print("dqsyntax");
- init();
+ finish();
+
fputs("\n/* syntax table used when in single quotes */\n", cfile);
+ init("sqsyntax");
+ add_default();
add("\n", "CNL");
add("'", "CENDQUOTE");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-", "CCTL");
- print("sqsyntax");
- init();
+ finish();
+
fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+ init("arisyntax");
+ add_default();
add("\n", "CNL");
add("\\", "CBACK");
add("`", "CBQUOTE");
@@ -230,99 +213,94 @@
add("}", "CENDVAR");
add("(", "CLP");
add(")", "CRP");
- print("arisyntax");
- filltable("0");
+ finish();
+
fputs("\n/* character classification table */\n", cfile);
+ init("is_type");
add("0123456789", "ISDIGIT");
add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
add("_", "ISUNDER");
add("#?$!-*@", "ISSPECL");
- print("is_type");
+ finish();
+
exit(0);
}
-
/*
- * Clear the syntax table.
+ * Output the header and declaration of a syntax table.
*/
static void
-filltable(const char *dftval)
+init(const char *name)
{
- int i;
+ fprintf(hfile, "extern const char %s[];\n", name);
+ fprintf(cfile, "const char %s[SYNBASE + CHAR_MAX + 1] = {\n", name);
+}
- for (i = 0 ; i < size ; i++)
- syntax[i] = dftval;
+
+static void
+add_one(const char *key, const char *type)
+{
+ fprintf(cfile, "\t[SYNBASE + %s] = %s,\n", key, type);
}
/*
- * Initialize the syntax table with default values.
+ * Add default values to the syntax table.
*/
static void
-init(void)
+add_default(void)
{
- filltable("CWORD");
- syntax[0] = "CEOF";
- syntax[base + CTLESC] = "CCTL";
- syntax[base + CTLVAR] = "CCTL";
- syntax[base + CTLENDVAR] = "CCTL";
- syntax[base + CTLBACKQ] = "CCTL";
- syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
- syntax[base + CTLARI] = "CCTL";
- syntax[base + CTLENDARI] = "CCTL";
- syntax[base + CTLQUOTEMARK] = "CCTL";
+ add_one("PEOF", "CEOF");
+ add_one("CTLESC", "CCTL");
+ add_one("CTLVAR", "CCTL");
+ add_one("CTLENDVAR", "CCTL");
+ add_one("CTLBACKQ", "CCTL");
+ add_one("CTLBACKQ + CTLQUOTE", "CCTL");
+ add_one("CTLARI", "CCTL");
+ add_one("CTLENDARI", "CCTL");
+ add_one("CTLQUOTEMARK", "CCTL");
}
/*
- * Add entries to the syntax table.
+ * Output the footer of a syntax table.
*/
static void
-add(const char *p, const char *type)
+finish(void)
{
- while (*p)
- syntax[*p++ + base] = type;
+ fputs("};\n", cfile);
}
-
/*
- * Output the syntax table.
+ * Add entries to the syntax table.
*/
static void
-print(const char *name)
+add(const char *p, const char *type)
{
- int i;
- int col;
+ for (; *p; ++p) {
+ char c = *p;
+ switch (c) {
+ case '\t': c = 't'; break;
+ case '\n': c = 'n'; break;
+ case '\'': c = '\''; break;
+ case '\\': c = '\\'; break;
- fprintf(hfile, "extern const char %s[];\n", name);
- fprintf(cfile, "const char %s[%d] = {\n", name, size);
- col = 0;
- for (i = 0 ; i < size ; i++) {
- if (i == 0) {
- fputs(" ", cfile);
- } else if ((i & 03) == 0) {
- fputs(",\n ", cfile);
- col = 0;
- } else {
- putc(',', cfile);
- while (++col < 9 * (i & 03))
- putc(' ', cfile);
+ default:
+ fprintf(cfile, "\t[SYNBASE + '%c'] = %s,\n", c, type);
+ continue;
}
- fputs(syntax[i], cfile);
- col += strlen(syntax[i]);
+ fprintf(cfile, "\t[SYNBASE + '\\%c'] = %s,\n", c, type);
}
- fputs("\n};\n", cfile);
}
-
/*
* Output character classification macros (e.g. is_digit). If digits are
* contiguous, we can test for them quickly.
--
Jilles Tjoelker
More information about the freebsd-arm
mailing list