Fix a potential bug in lib/c1 where struct ftconst was not compatible with struct...
[211bsd.git] / readme.txt
1 Nick Downing downing.nick@gmail.com
2 2.11BSD source tree modified for cross compilation from x86-64 linux
3
4 Initial commit was an unmodified 2.11BSD source tree taken from a boot tape.
5
6 Unpacked from http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.11BSD:
7 7263558ebfb676b4b9ddacc77da464c5  file7.tar.gz
8 77397e6d554361c127592b1fea2d776f  file8.tar.gz
9     
10 The root of this repository is "/usr/src" on a running 2.11BSD system.
11 The boot tape file7.tar.gz provides "/usr/src/include" and "/usr/src/sys".
12 The boot tape file8.tar.gz provides everything else in "/usr/src".
13
14 To compile this repository, simply run "./n.sh" (this stands for "Nick"). It
15 will clean the source tree, compile and install a cross toolchain into "cross",
16 clean again, then compile and install a 2.11BSD filesystem tree into "stage".
17
18 The cross toolchain installed into "cross" consists of the following files:
19         cross/bin/ar
20         cross/bin/as
21         cross/bin/cc
22         cross/bin/ld
23         cross/bin/nm
24         cross/bin/size
25         cross/lib/c0
26         cross/lib/c1
27         cross/lib/c2
28         cross/lib/cpp
29         cross/usr/bin/lorder
30         cross/usr/bin/mkdep
31         cross/usr/bin/ranlib
32         cross/usr/lib/libvmf.a
33         cross/usr/lib/libvmf_p.a
34         cross/usr/man/cat1/ar.0
35         cross/usr/man/cat1/ld.0
36         cross/usr/man/cat1/ranlib.0
37         cross/usr/man/cat3/vmf.0
38         cross/usr/man/cat5/ar.0
39         cross/usr/man/cat5/ranlib.0
40         cross/usr/ucb/strcompact
41         cross/usr/ucb/symcompact
42         cross/usr/ucb/symdump
43         cross/usr/ucb/symorder
44
45 The cross toolchain is created by modifying the appropriate sources in this
46 tree to compile under gcc for x86-64 linux. I created a compatibility header
47 file called "krcompat.h", copied to various source directories, which contains
48 definitions for prototypes and varargs functions. So we should have a common
49 source for the toolchain which can compile under x86-64 linux and 2.11BSD.
50
51 I have fixed or suppressed all compiler warnings. A great many of these are due
52 to the K&R to ANSI conversion, I fixed them by introducing a standard way of
53 declaring function headers, etc. Declarations in the original source code like
54         somefunc(a, p)
55         char *p;
56         {
57                 register b;
58                 ...
59         }
60 become
61         int somefunc(a, p) int a; char *p; {
62                 register int b;
63                 ...
64         }
65 and functions which do not return a value have "int" changed (by me) to "void".
66 Note that "void" is apparently not K&R, it is "extended K&R". However, I have
67 just used "void", and if this causes any problems later, I'll change to "VOID",
68 which I can then suppress by means of a compatibility define in "krcompat.h".
69
70 In the course of this, I have changed all function headers to one line, and I
71 have changed parameters like "char *p, *q;" to "char *p; char *q;". This occurs
72 because I use "cproto" and a VERY ROUGH script (not included in the repository)
73 to convert them automatically. It is also because I prefer the source that way.
74
75 The varargs conversion is pretty simple. The K&R code is first converted to use
76 <varargs.h> rather than any ad-hoc convention it might have used before. Then,
77 if __STDC__ is defined, it uses <stdarg.h> instead of <varargs.h>, and defines
78 the function using an ANSI header rather than K&R. Example in "lib/ccom/c01.c":
79         #ifdef __STDC__
80         void werror(char *s, ...)
81         #else
82         void werror(s, va_alist) char *s; va_dcl
83         #endif
84         {
85                 va_list ap;
86         
87                 if (Wflag)
88                         return;
89                 if (filename[0])
90                         fprintf(stderr, "%s:", filename);
91                 fprintf(stderr, "%d: warning: ", line);
92                 va_start(ap, s);
93                 vfprintf(stderr, s, ap);
94                 va_end(ap);
95                 fprintf(stderr, "\n");
96         }
97 Note: With <varargs.h> it should be "va_start(ap)" but I hope the above is OK.
98
99 In many cases the toolchain source code relied on running under 2.11BSD, e.g.
100 the linker and symbol-related utilities are directly manipulating struct exec
101 and struct nlist etc, and expecting the on-disk format to match the in-memory.
102 To fix this I defined macros like OFF_T, INT, UNSIGNED_INT and whatever else
103 was appropriate, which are the original types (off_t, int, unsigned int) on
104 2.11BSD but compatibility types (int32_t, int16_t, uint16_t) on x86-64 linux.
105 Then I intercepted disk read/writes to occur through a temporary buffer, e.g.:
106         #ifdef pdp11
107                 fwrite(&stroff, sizeof (OFF_T), 1, fpin);
108         #else
109                 temp[0] = (stroff >> 16) & 0xff;
110                 temp[1] = (stroff >> 24) & 0xff;
111                 temp[2] = stroff & 0xff;
112                 temp[3] = (stroff >> 8) & 0xff;
113                 fwrite(temp, sizeof (OFF_T), 1, fpin);
114         #endif
115 This handles byte order issues, in particular the PDP-11 convention of storing
116 a long with the high word first (but storing each word low byte first). Since
117 x86-64 is little-endian like the PDP-11 there may be a few places which are not
118 fully converted. In particular, the conversion of "ld", "ar" and "nm" is a bit
119 rough, and I plan to go back and make it similar to "symcompact" and friends.
120 I used a temporary buffer instead of an in-place conversion like htons() and
121 friends, because I'm concerned about C's aliasing rules and gcc's optimizer.
122
123 Another issue was the compiler second pass "/lib/c1" when it generates floating
124 point constaints or performs constant folding. The host system uses IEEE-754,
125 whereas the PDP-11 uses its own conventions. Since I want the cross toolchain
126 to generate EXACTLY the same binaries as the traditional PDP-11 hosted tools,
127 I had to take the floating-point emulation code from "simh" and put it in "c1".
128
129 A further issue was the definition of struct nlist (and others) like this:
130         struct nlist {
131                 union {
132                         char *n_name;   /* In memory address of symbol name */
133                         OFF_T n_strx;   /* String table offset (file) */
134                 } n_un;
135                 u_char  n_type;         /* Type of symbol - see below */
136                 char    n_ovly;         /* Overlay number */
137                 U_INT   n_value;        /* Symbol value */
138         };
139 Unfortunately the n_name pointer breaks things on a 64-bit system because it is
140 larger than OFF_T and causes sizeof(struct nlist) to be wrong. So I have made
141 all the client programs that refer to this structure use n_strx exclusively,
142 n_name is only defined when compiling for PDP-11. This was an easy change since
143 there is always an associated string table so we just offset into it as needed.
144
145 Since the above conversions tend to increase code bloat, and the PDP-11 tools
146 are often running on the limit of memory, they do not apply when "pdp11" is
147 defined, although in theory there should be no need to make this distinction.
148
149 Since the host system is very similar to the target system, we can use tools
150 like "/bin/sort", "/bin/sed" and the gnu "make" tool provided by the host,
151 although it would also be possible to build cross versions of these tools. It
152 is easier to use the native tools and work around occasional incompatibilities,
153 for example I changed "sort -t/ +1" in a Makefile to simply "sort -t/" since
154 the comparison of the first field was not going to change the outcome anyway.
155
156 One problem with the host system being similar to the target system, is that
157 when the cross tools include something like <a.out.h>, the host wants to
158 provide its own version. This is rather delicate to work around, for the sake
159 of minimal change I created a subdirectory called "include" alongside any
160 affected sources, for example "bin/ld/ld.c" includes <a.out.h> so it gets a
161 directory "bin/ld/include". In this directory there is a collection of links:
162         a.out.h -> ../../../include/a.out.h
163         ar.h -> ../../../include/ar.h
164         nlist.h -> ../../../include/nlist.h
165         ranlib.h -> ../../../include/ranlib.h
166         vmf.h -> ../../../include/vmf.h
167 There is also a further directory "bin/ld/include/sys" containing this link:
168         exec.h -> ../../../../sys/h/exec.h
169 This is a bit fragile since we cannot say whether the host might be trying to
170 use its own <sys/exec.h> deep inside some other include file like <stdlib.h>,
171 so it's not really the best solution to the problem. It would be better to have
172 a define saying where to include the files from, and perhaps even alternative
173 names like "struct nlist_211bsd" instead of "struct nlist", but this is rather
174 bloated, and I got around the problem by doing the above hacks for the moment.
175
176 To build the cross toolchain from a common source which can also build the
177 PDP-11 hosted toolchain, my strategy was to change the Makefiles as little as
178 possible. The most significant change is to modify "cc" to "${CC}" and so on,
179 in many cases it was already like this, but I had to introduce aliases for all
180 of the cross build tools, so "mkdep" becomes "${MKDEP}" and so on. The "make"
181 tool included in 2.11BSD only provides "CC" and "AS" by default, so each
182 Makefile is supposed to have lines like "MKDEP=/usr/bin/mkdep", so as not to
183 break the PDP-11 hosted buildsystem. BUT, I suspect most of these are missing,
184 since I have not tested the PDP-11 hosted buildsystem yet. I will fix it later.
185
186 So the "make" commands to build the cross toolchain look something like this:
187         make CC="cc -Iinclude -Wall -Wno-char-subscripts -Wno-deprecated-declarations -Wno-format -Wno-maybe-uninitialized -Wno-parentheses -Wno-unused-result" CROSSDIR="/home/nick/src/211bsd.git/cross" STAGEDIR="/home/nick/src/211bsd.git/stage" SEPFLAG=
188         make DESTDIR="/home/nick/src/211bsd.git/stage" install
189 The above example is taken from building "cross/bin/cc" since it needs to know
190 both CROSSDIR and STAGEDIR so it is a good example of how I handle directories.
191 The compiled "bin/cc" expects to find things in various places which are hard
192 coded into the source, so I changed the Makefile to pass the CROSSDIR and the
193 STAGEDIR into the compilation using defines, giving a compilation command like:
194         cc -Iinclude -Wall -Wno-char-subscripts -Wno-deprecated-declarations -Wno-format -Wno-maybe-uninitialized -Wno-parentheses -Wno-unused-result -DCROSSDIR="\"/home/nick/src/211bsd.git/cross\"" -DSTAGEDIR="\"/home/nick/src/211bsd.git/stage\""   -c -o cc.o cc.c
195 Inside the source file "bin/cc/cc.c", I've adjusted the hard coded paths like:
196         char    *cpp = CROSSDIR "/lib/cpp";
197         char    *ccom = CROSSDIR "/lib/c0";
198         char    *ccom1 = CROSSDIR "/lib/c1";
199         char    *c2 = CROSSDIR "/lib/c2";
200         char    *as = CROSSDIR "/bin/as";
201         char    *ld = CROSSDIR "/bin/ld";
202         char    *crt0 = STAGEDIR "/lib/crt0.o";
203 This means before we can link, we'll have to build the C library into STAGEDIR.
204
205 Since the "make" commands are hard to remember and inconvenient to type, and
206 the top-level "n.sh" command is overkill since it builds everything and since
207 it cleans instead of just rebuilding what has changed: I have put a smaller
208 script "n.sh" in each directory I've visited, which gives the correct commands
209 and installs the result (if it's a tool, it gets built as a cross tool and
210 installed into CROSSDIR, otherwise it gets built for the target and installed
211 into STAGEDIR). So it's easy to add debugging statements, compile with -g, etc.
212
213 Most of the development work so far has gone into building and debugging the
214 cross toolchain. We can't yet build all of the target, but we can build this:
215         stage/lib/crt0.o
216         stage/lib/libc.a
217         stage/lib/mcrt0.o
218         stage/include (copied from the source tree using "make install")
219         stage/unix
220         stage/usr/lib/libc_p.a
221         stage/usr/lib/libkern.a
222 I have done some ad-hoc tests, and these files work correctly when copied to an
223 existing 2.11BSD system under "simh". For instance, I can compile and run the
224 "adventure" game using the above C startup code and libraries. I can boot the
225 kernel. I have verified that the kernel and all its object files are binary
226 identical to what the PDP-11 hosted build produces. I do not yet have a way of
227 making "ar" and "ranlib" produce a binary identical copy of a library, so I
228 have not definitively verified these are the same, but I see no problem so far.