aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Lee <alee14498@protonmail.com>2021-08-15 00:16:45 -0400
committerAndrew Lee <alee14498@protonmail.com>2021-08-15 00:16:45 -0400
commit723428bebe3105ad3c3406e416402d1831b482c4 (patch)
treeff990e306163515973746ddfb261f29ba8765441
downloadlinux-0.01-distro-723428bebe3105ad3c3406e416402d1831b482c4.tar.gz
linux-0.01-distro-723428bebe3105ad3c3406e416402d1831b482c4.tar.bz2
linux-0.01-distro-723428bebe3105ad3c3406e416402d1831b482c4.zip
Inital commit
-rw-r--r--LICENSE0
-rw-r--r--README.md0
-rw-r--r--binutils-1.9.tar.bz2bin0 -> 146132 bytes
-rw-r--r--binutils-1.9/COPYING249
-rw-r--r--binutils-1.9/ChangeLog1647
-rw-r--r--binutils-1.9/Makefile167
-rw-r--r--binutils-1.9/README38
-rw-r--r--binutils-1.9/README-ENCAP55
-rw-r--r--binutils-1.9/a.out.encap.h134
-rw-r--r--binutils-1.9/a.out.gnu.h272
-rw-r--r--binutils-1.9/ar.c2070
-rw-r--r--binutils-1.9/cplus-dem.c925
-rw-r--r--binutils-1.9/error.c104
-rw-r--r--binutils-1.9/getopt.c596
-rw-r--r--binutils-1.9/getopt.h102
-rw-r--r--binutils-1.9/getopt1.c160
-rw-r--r--binutils-1.9/gmalloc.c1116
-rw-r--r--binutils-1.9/gmon.h48
-rw-r--r--binutils-1.9/gprof.c2737
-rw-r--r--binutils-1.9/gprof.texinfo943
-rw-r--r--binutils-1.9/hp-bin/Makefile15
-rw-r--r--binutils-1.9/hp-bin/chatr.c214
-rw-r--r--binutils-1.9/hp-bin/hpxt.c1077
-rw-r--r--binutils-1.9/hp-bin/ioutil.c332
-rw-r--r--binutils-1.9/hp-bin/ioutil.h20
-rwxr-xr-xbinutils-1.9/hp-bin/mkhplib30
-rw-r--r--binutils-1.9/hp-include/a.out.h79
-rw-r--r--binutils-1.9/hp-include/stab.def115
-rw-r--r--binutils-1.9/hp-include/stab.h17
-rw-r--r--binutils-1.9/ld.c6312
-rwxr-xr-xbinutils-1.9/libconvert46
-rw-r--r--binutils-1.9/nm.c1204
-rw-r--r--binutils-1.9/objdump.c418
-rw-r--r--binutils-1.9/ranlib.c241
-rw-r--r--binutils-1.9/ranlib.h17
-rw-r--r--binutils-1.9/robotussin.c579
-rw-r--r--binutils-1.9/signame.c248
-rw-r--r--binutils-1.9/signame.h42
-rw-r--r--binutils-1.9/size.c400
-rw-r--r--binutils-1.9/stab.def115
-rw-r--r--binutils-1.9/stab.h17
-rw-r--r--binutils-1.9/strip.c915
-rw-r--r--binutils-1.9/symseg.h511
-rw-r--r--linux-0.01.tar.gzbin0 -> 73091 bytes
-rw-r--r--linux/Makefile96
-rw-r--r--linux/boot/boot.s329
-rw-r--r--linux/boot/head.s175
-rw-r--r--linux/fs/Makefile95
-rw-r--r--linux/fs/bitmap.c158
-rw-r--r--linux/fs/block_dev.c86
-rw-r--r--linux/fs/buffer.c254
-rw-r--r--linux/fs/char_dev.c50
-rw-r--r--linux/fs/exec.c306
-rw-r--r--linux/fs/fcntl.c69
-rw-r--r--linux/fs/file_dev.c84
-rw-r--r--linux/fs/file_table.c3
-rw-r--r--linux/fs/inode.c288
-rw-r--r--linux/fs/ioctl.c40
-rw-r--r--linux/fs/namei.c678
-rw-r--r--linux/fs/open.c188
-rw-r--r--linux/fs/pipe.c92
-rw-r--r--linux/fs/read_write.c97
-rw-r--r--linux/fs/stat.c51
-rw-r--r--linux/fs/super.c102
-rw-r--r--linux/fs/truncate.c59
-rw-r--r--linux/fs/tty_ioctl.c166
-rw-r--r--linux/include/a.out.h220
-rw-r--r--linux/include/asm/io.h24
-rw-r--r--linux/include/asm/memory.h14
-rw-r--r--linux/include/asm/segment.h38
-rw-r--r--linux/include/asm/system.h66
-rw-r--r--linux/include/const.h15
-rw-r--r--linux/include/ctype.h34
-rw-r--r--linux/include/errno.h60
-rw-r--r--linux/include/fcntl.h55
-rw-r--r--linux/include/linux/config.h53
-rw-r--r--linux/include/linux/fs.h185
-rw-r--r--linux/include/linux/hdreg.h99
-rw-r--r--linux/include/linux/head.h20
-rw-r--r--linux/include/linux/kernel.h8
-rw-r--r--linux/include/linux/mm.h10
-rw-r--r--linux/include/linux/sched.h230
-rw-r--r--linux/include/linux/sys.h80
-rw-r--r--linux/include/linux/tty.h74
-rw-r--r--linux/include/signal.h65
-rwxr-xr-xlinux/include/stdarg.h28
-rw-r--r--linux/include/stddef.h19
-rw-r--r--linux/include/string.h405
-rw-r--r--linux/include/sys/stat.h58
-rw-r--r--linux/include/sys/times.h15
-rw-r--r--linux/include/sys/types.h46
-rw-r--r--linux/include/sys/utsname.h16
-rw-r--r--linux/include/sys/wait.h23
-rw-r--r--linux/include/termios.h222
-rw-r--r--linux/include/time.h42
-rw-r--r--linux/include/unistd.h247
-rw-r--r--linux/include/utime.h13
-rw-r--r--linux/init/main.c147
-rw-r--r--linux/kernel/Makefile90
-rw-r--r--linux/kernel/asm.s157
-rw-r--r--linux/kernel/console.c550
-rw-r--r--linux/kernel/exit.c135
-rw-r--r--linux/kernel/fork.c136
-rw-r--r--linux/kernel/hd.c413
-rw-r--r--linux/kernel/keyboard.s409
-rw-r--r--linux/kernel/mktime.c52
-rw-r--r--linux/kernel/panic.c11
-rw-r--r--linux/kernel/printk.c33
-rw-r--r--linux/kernel/rs_io.s141
-rw-r--r--linux/kernel/sched.c254
-rw-r--r--linux/kernel/serial.c53
-rw-r--r--linux/kernel/sys.c216
-rw-r--r--linux/kernel/system_call.s219
-rw-r--r--linux/kernel/traps.c199
-rw-r--r--linux/kernel/tty_io.c306
-rw-r--r--linux/kernel/vsprintf.c227
-rw-r--r--linux/lib/Makefile44
-rw-r--r--linux/lib/_exit.c7
-rw-r--r--linux/lib/close.c4
-rw-r--r--linux/lib/ctype.c29
-rw-r--r--linux/lib/dup.c4
-rw-r--r--linux/lib/errno.c1
-rw-r--r--linux/lib/execve.c4
-rw-r--r--linux/lib/open.c19
-rw-r--r--linux/lib/setsid.c4
-rw-r--r--linux/lib/string.c8
-rw-r--r--linux/lib/wait.c10
-rw-r--r--linux/lib/write.c4
-rw-r--r--linux/mm/Makefile37
-rw-r--r--linux/mm/memory.c264
-rw-r--r--linux/mm/page.s34
-rw-r--r--linux/tools/build.c68
132 files changed, 34566 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/LICENSE
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README.md
diff --git a/binutils-1.9.tar.bz2 b/binutils-1.9.tar.bz2
new file mode 100644
index 0000000..ebc20db
--- /dev/null
+++ b/binutils-1.9.tar.bz2
Binary files differ
diff --git a/binutils-1.9/COPYING b/binutils-1.9/COPYING
new file mode 100644
index 0000000..9a17037
--- /dev/null
+++ b/binutils-1.9/COPYING
@@ -0,0 +1,249 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The license agreements of most software companies try to keep users
+at the mercy of those companies. By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must tell them their rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License. The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications. Each
+licensee is addressed as "you".
+
+ 1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program. You may charge a fee for the physical act of
+transferring a copy.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating that
+ you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish, that
+ in whole or in part contains the Program or any part thereof, either
+ with or without modifications, to be licensed at no charge to all
+ third parties under the terms of this General Public License (except
+ that you may choose to grant warranty protection to some or all
+ third parties, at your option).
+
+ c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the simplest and most usual way, to print or display an
+ announcement including an appropriate copyright notice and a notice
+ that there is no warranty (or else, saying that you provide a
+ warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this General
+ Public License.
+
+ d) You may charge a fee for the physical act of transferring a
+ copy, and you may at your option offer warranty protection in
+ exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+ 3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+ a) accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal charge
+ for the cost of distribution) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it. For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+ 4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License. However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+ 5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+
+ 7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+ 8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+ To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19xx name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (a program to direct compilers to make passes
+ at assemblers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/binutils-1.9/ChangeLog b/binutils-1.9/ChangeLog
new file mode 100644
index 0000000..e2ea724
--- /dev/null
+++ b/binutils-1.9/ChangeLog
@@ -0,0 +1,1647 @@
+Wed Apr 17 15:33:33 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * Make version number be 1.9.
+
+Wed Apr 10 18:19:15 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * strip.c (xmalloc): Handle allocation request of 0 (make it 1).
+
+Tue Apr 9 13:40:31 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * strip.c (rewrite_file_symbols): Instead of tell(fd),
+ use the more portable lseek(fd, 0L, 1).
+
+Mon Apr 8 17:31:17 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * Makefile: Replaced mis-spelled and obsolete -DPIGNAL_MISSING
+ by -DSYS_SIGLIST_MISSING in sample CFLAGS for COFF systems.
+
+Sun Mar 31 23:06:42 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * Increment version number to 1.8.
+
+Fri Mar 29 15:29:55 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * ld.c (do_relocation_warnings): Add some paranoia checking
+ in case of a corrupted binary.
+
+Thu Mar 28 17:21:24 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * ld.c (subfile_wanted_p): Not quite as minimalist:
+ If a subfile defines a common that is needed (i.e. currently
+ undefined), don't load the subfile, just define the undefined
+ symbol as a common.
+ This brings back some of the logic from Roland's change.
+ It is needed to handle a dubious libc.a in SunOS.
+
+Sat Mar 23 13:25:07 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu)
+
+ * ld.c (subfile_wanted_p): Try a minimalist approach:
+ Treat an existing common definition as a true definition
+ wrt the decision as to whether a subfile is needed -
+ i.e. don't pull in the subfile in that case.
+
+Tue Mar 19 01:01:34 1991 Per Bothner (bothner at mole.ai.mit.edu)
+
+ * ld.c (subfile_wanted_p): A compromise solution, suggested by Mike:
+ Restore the old #if 1 behavior, with the following changes:
+ + allow a library member to grow a common symbol only if some other
+ library member is already known to reference that symbol
+ + allow a library member to replace a common symbol with some other
+ definition if some other library member is already known to
+ reference that symbol.
+
+Sun Mar 17 00:47:44 1991 Per Bothner (bothner at pogo.ai.mit.edu)
+
+ * Makefile: Add $(LIBS) to dependencies for most programs,
+ to make sure signame.o and alloca.o get built when needed.
+ * ar.c: Don't include fcntl.h again if USG.
+ * ar.c: Initialize program_name variable.
+ * ar.c: Changes from Arnold Robbins <arnold@audiofax.com>:
+ "gnu ar didn't properly use just the trailing component
+ of filenames. If creating an archive, it would put members in
+ with names like ./foo. If updating an archive with a member
+ foo with /some/path/foo, the new file would get appended to
+ the archive instead of replacing the old one."
+ So add basename routine to skip directory prefix, and use it
+ to name archive elements with just the basename.
+ Also some System V stuff:
+ "System V machines (of course) use a slightly different version
+ of the archive format header, and allow a leading '-' on the
+ flags. Also, the temp file name didn't allow for 14 character
+ file names."
+ I (Per) incorporated these changes. It seemed reasonable to always
+ allow an initial '-' to the flags.
+ * ar.c: Improved argc/argv/usage() checking.
+ * ar.c: Unlink if we fail to open after "touch" for create.
+ * gprof.c: Reformat, adding white space between = and &.
+ Without it, pcc thinks it's an old-style &=.
+ * ld.c: Code for ns32000 from Jyrki Kuoppala <jkp@sauna.hut.fi>,
+ some of it by Ian Dall.
+ * ld.c (subfile_wanted_p): For now, undo the change made for 1.7.
+ (It causes problems, and anyway I'm unconvinced by the justification.)
+ * ranlib.c (main): Removed emulation of psignal when PSIGNAL_MISSING
+ is defined, since there is a version in signame.c.
+
+Thu Mar 7 17:29:09 1991 Mike Haertel (mike at ducky)
+
+ * a.out.gnu.h [sequent && i386]: Changes to support the
+ sequent symmetry.
+ * ar.c (update_symdefs): Loop to original_num_symdefs rather
+ than nsymdefs, since the latter changes inside the loop.
+ * gprof.c (main): Divide by (nhist - 1) to get the correct
+ histogram increment.
+ * hp-bin/hpxt.c (process_archive_entry): Deal correctly with
+ names containing '/'.
+ * ld.c [tek4300, LARMAG]: Add UTek support.
+ [hp300]: Mark the filename symbol with N_FN|N_EXT not N_TEXT.
+ (deduce_file_type): Remove forward reference to coffheader.
+ (read_a_out_header): Likewise.
+ (read_a_out_header) [NMAGIC]: Adjust orig_data_address when
+ reading NMAGIC files.
+ (enter_global_ref): Update symbol's last_library_ref for
+ use by subfile_wanted_p().
+ (subfile_wanted_p): Never use a library member to define
+ a common symbol unless some other library member already known
+ to be needed references that symbol.
+ (do_file_warnings): Warn for multiply defined N_ABS symbols.
+ (do_warnings: Warn if -e entry symbol is never defined.
+ (perform_relocation): Make sure we never carry out of the
+ relocation masked bits.
+ (getsym): Clear last_library_ref to NULL when initializing
+ a new symbol, for subfile_wanted_p().
+ ranlib.c [PSIGNAL_MISSING]: Don't use psignal().
+ strip.c (file_close): Use -1 for invalid descriptor flag value.
+ (read_file_symbols): Close the file if an error occurs.
+ (rewrite_file_symbols): Use ~ prefixed temp file to avoid
+ problems with 14 character limits on file names. Use open()
+ instead of creat() since the file will need to be read later.
+ Be sure to close all input files. Cast lseek() arguments
+ correctly.
+
+Wed Nov 28 23:42:48 1990 Jim Kingdon and Roland McGrath (roland@ai.mit.edu)
+
+ * ld.c (subfile_wanted_p): If the subfile has a common def of
+ a symbol already defined as common, look at the subfile's def
+ to find the largest-sized common def. But do not include the
+ subfile if the symbol is already defined at all.
+
+Mon Oct 15 13:07:24 1990 Mike Haertel (mike at albert.ai.mit.edu)
+
+ * ld.c (digest_symbols): Align the end of the data segment
+ to sizeof (double) after allocating set vectors, not before.
+
+Wed Sep 26 12:51:05 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
+
+ * gprof.c When closing /dev/kmem, use fclose instead of ck_fclose
+ because some systems erroniously return NOT_OWNER on close. . .
+
+Mon Sep 3 18:14:35 1990 Mike Haertel (mike at wookumz.ai.mit.edu)
+
+ * ar.c (insert_in_map): Always insert __.SYMDEF at the front
+ of the archive.
+
+Mon Aug 13 19:01:27 1990 Chris Hanson (cph at kleph)
+
+ * ranlib.c (main): Remove emulation of `psignal' from last
+ change. There is already an emulation that was accidentally
+ omitted from the last release.
+
+Thu Aug 9 13:57:53 1990 Chris Hanson (cph at kleph)
+
+ * hp-bin/ioutil.c (iou_open): Remove external declaration of
+ `open', which conflicts with that supplied in hp-ux 7.0.
+
+ * hp-bin/hpxt.c: Add compile-time test that signals an error
+ if this file is compiled on the wrong kind of machine.
+
+ * nm.c (getpagesize): Add emulation for USG machines. This is
+ needed for GNU malloc, and perhaps should be placed there
+ instead.
+
+ * strip.c, ar.c: Make conditionalization of BSD features be
+ more selective. Previously these features were not used if
+ USG was defined -- but HP-UX supports them.
+
+ * ranlib.c (main): Add emulation of `psignal' for USG
+ machines.
+
+Tue Jul 10 02:07:08 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * ar.c: Remove unused variables.
+ (copy_out_member): Declare `outname' as char *.
+ Use `program_name' instead of hardcoded "ar" in messages.
+
+ * robotussin.c: Use `program_name' instead of hardcoded
+ "robotussin" in messages.
+
+ * objdump.c: Indent. Declare a lot of functions void.
+ Improve comments. Rename option variables to reflect their
+ meanings rather than the short option names.
+ Use error instead of fprintf and perror. Include filename in messages.
+ (main): Exit with 0 status normally. Change +reloc to +relocation.
+ (dump_file): Renamed from doit.
+ (dump_reloc1): Do nothing if sun and sparc (structure isn't defined).
+ (getpagesize): Add emulations for USG and sparc, copied from ld.c.
+
+ * size.c: Declare some functions void. Use `program_name'
+ instead of hardcoded "size" in messages.
+
+ * gprof.c, robotussin.c: Use VPRINTF_MISSING, to be consistent
+ with error.c.
+
+ * nm.c: Declare some functions void. Remove unused variables.
+
+ * strip.c: Declare some functions void.
+ Make `strip_symbols' and `discard_locals' enums instead of ints.
+ Remove unused variables.
+ (fatal, error_with_file, usage): Use `program_name' instead of
+ hardcoded "strip".
+ (main): Set `program_name'.
+ (error, error_with_file, perror_file, perror_name, fatal,
+ print_file_name, prline_file_name): Replace with a single
+ `error' function, and change callers.
+
+Fri Jul 6 01:22:26 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * ranlib.c (main): Print usage message if no files given.
+ (usage): New function.
+ Global: Use `program_name' instead of hardcoded "ranlib" in
+ messages.
+
+Thu Jul 5 11:31:12 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * Makefile (dist): Put the list of files to distribute into
+ the Makefile instead of ARCHLIST. Include signame.c and not TAGS.
+ (ranlib): Link with signame.o.
+
+Thu Jun 28 17:03:51 1990 Mike Haertel (mike at ducky)
+
+ * ld.c: (compute_mach_o_section_offsets): Bug fix for -r.
+ (relocate_file_addresses): Replace ~N_EXT with N_TYPE,
+ undoing earlier change which broke -g.
+
+Wed Jun 20 13:34:11 1990 Mike Haertel (mike at thor.acc.stolaf.edu)
+
+ * gprof.c: Make qsort compare functions take const void *
+ arguments for compatibility with the standard.
+
+Tue Jun 19 19:23:41 1990 Mike Haertel (mike at ducky)
+
+ * ld.c: (do_file_warnings, do_relocation_warnings):
+ Always print the object file name in error messages,
+ even if we also know a source file name. Use
+ print_file_name() to properly print the names of
+ files that came from libraries.
+ (getpagesize): Fake getpagesize() for sun 4's.
+
+Wed Jun 13 13:11:21 1990 Mike Haertel (mike at ducky)
+
+ * Makefile: (ld): Link the demangler.
+ * cplus-dem.c: Don't include <memory.h> on NeXT.
+ * ld.c: Include <sys/resource.h> unless USG.
+ (demangler): New variable; unconditionally set
+ to cplus_demangle(). This is different from how
+ ld++ did it, but conditionalizing on whether -lg++
+ is specified seems too much of a kludge. The
+ demangler will only demangle names that look like
+ they came from g++ anyway.
+ (main): Attempt to raise the stack limit so we
+ don't barf on large files.
+ (decode_command): Add new option `-nostdlib', with
+ new flag `no_standard_dirs'.
+ (file_open): Eliminate unused variable `p'.
+ Deal with the case of no standard library dirs.
+ (enter_file_symbols): Eliminate unused `lowest_set_vector'.
+ (enter_global_ref): Logically and nlist.n_type with
+ ~N_EXT rather than N_TYPE; otherwise, e.g., <stab.h>'s
+ N_FUN would get turned into N_TEXT, which we don't want.
+ (subfile_wanted_p): Eliminate Kingdon's "if the user
+ declares 'int pipe;' we don't want to get 'pipe()'
+ from the library" bugfix, because (first of all)
+ it breaks g++, and secondly, it was generally wrong.
+ If the user declares "int errno;" and the library
+ declares "int errno = 0;" we want to get the library's
+ version. The proper fix will require some thought.
+ (digest_symbols): Eliminated unused variable `erred'.
+ (relocate_file_addresses): Use ~N_EXT instead of N_TYPE.
+ (address_to_line): Likewise.
+ (do_relocation_warnings): Eliminate unused variables
+ `next' and `source'. Use the demangler to print names.
+ (do_file_warnings): Use the demangler when possible.
+ (do_warnings): Eliminate unused variable `i'.
+ (initialize_a_out_data_start): If no entry symbol
+ was given, set it to "start", if sequent.
+ (perform_relocation): Eliminate variable `data_input_address'
+ performing copy propogation by hand to the one place it
+ was used. Get rid of misleading comments.
+ (coptxtrel): Use ~N_EXT instead of N_TYPE.
+ (copdatrel): Likewise.
+ (write_syms): Likewise.
+
+Tue Jun 12 11:16:26 1990 Mike Haertel (mike at ducky)
+
+ * Makefile: Use $(CFLAGS) when linking.
+ * ar.c: (struct member_desc): date is long.
+ (scan): Fully initialize member_desc.
+ (delete_from_map): Clobber info.name instead
+ of unlinking from list.
+ (update_symdefs): Only install new symdefs for
+ members that *have* them.
+ Changes for MACH_O:
+ (read_header_info): New function.
+ (make_new_symdefs): Use it.
+ * gprof.c: fread() returns size_t for ANSI.
+ Declare qsort() properly for ANSI.
+ Move #include <assert.h> to the top.
+ size_t is an unsigned int.
+ Changes for MACH_O:
+ (read_header_info): New function.
+ (main): Use it.
+ (badsym): Allow N_SECT symbols.
+ (fatal): Print a space after the colon.
+ * ld.c: Changes for MACH_O:
+ (struct file_entry): New fields containing header
+ info but no explicit struct exec, as well as file type info.
+ Also section ordinals for Mach-O files.
+ (output_file_type): New global variable.
+ (output_style): New global variable, also supersedes
+ the flag relocatable_output.
+ Removed a.out specific stuff from global variables.
+ (output_*_offset): New global variables initialized
+ according to the output file type.
+ (decode_command): Remove a.out specific stuff.
+ (deduce_file_type): New function.
+ (read_a_out_header): New function.
+ (read_mach_o_header): New function.
+ (read_header): Use the above functions.
+ (read_entry_symbols): Use new file_entry fields;
+ call translate_mach_o_symbols().
+ (read_entry_strings): Use new file_entry fields;
+ no longer deduce symseg presence.
+ (read_file_symbols): Use deduce_file_type().
+ (enter_file_symbols): Use new file_entry fields.
+ Display N_INDR refs differently. Move default: in
+ display switch out of #ifdef sequent.
+ (contains_symbol): Use new file_entry fields.
+ (symdef_library): Use xmalloc(). Remember to
+ free subentry->strings, but only if we allocated them.
+ (process_subentry): Use new file_entry fields.
+ (subfile_wanted_p): Likewise.
+ (digest_symbols): Use new functions initialize_text_start()
+ and initialize_data_start(). Remove a.out specific stuff.
+ (consider_file_section_lengths): Use new file_entry fields.
+ (relocate_file_addresses): Use new file_entry fields.
+ (describe_file_sections): Likewise.
+ (list_file_locals): Likewise.
+ (next_debug_entry): Likewise.
+ (init_debug_scan): Likewise.
+ (do_relocation_warnings): Likewise.
+ (do_file_warnings): Likewise.
+ (do_warnings): Use new global output_style.
+ (initialize_a_out_text_start): New function.
+ (initialize_a_out_data_start): New function.
+ (compute_a_out_section_offsets): New function.
+ (compute_more_a_out_section_offsets): New function.
+ (write_a_out_header): New function.
+ (translate_mach_o_symbols): New function.
+ (translate_mach_o_relocation): New function.
+ (initialize_mach_o_text_start): New function.
+ (initialize_mach_o_data_start): New function.
+ (compute_mach_o_section_offsets): New function.
+ (compute_more_mach_o_section_offsets): New function.
+ (write_mach_o_header): New function.
+ (generate_mach_o_symbols): New function.
+ (generate_mach_o_relocations): New function.
+ (initialize_text_start): New function switch on
+ ouput_file_type.
+ (initialize_data_start): Likewise.
+ (compute_section_offsets): Likewise.
+ (compute_more_section_offsets): Likewise.
+ (write_header): Switch on output_file_type.
+ (write_output): Use the above functions. Bug fix
+ for umask().
+ (write_text): Use output_text_offset.
+ (text_offset): No longer used.
+ (read_file_relocation): Use new file_entry fields.
+ Call translate_mach_o_relocation() for Mach-O input files.
+ (copy_text): Likewise.
+ (write_data): Use output_data_offset.
+ (copy_data): Use new file_entry fields. Call
+ translate_mach_o_relocation() for Mach-O input files.
+ (perform_relocation): Use new file_entry fields.
+ (write_rel): Use output_*rel_offset.
+ (coptxtrel): Use new file_entry fields. Call
+ generate_mach_o_relocations() for Mach-O output files.
+ (copdatrel): Likewise.
+ (write_string_table): Use output_strs_{offset,size}.
+ (write_syms):Use output_{syms,strs}_{offset,size}.
+ Use n_sect field if N_SECT is defined. Call
+ generate_mach_o_symbols() for Mach-O output files.
+ (write_file_syms): Likewise.
+ (write_symsegs): Use output_symseg_offset.
+ (write_file_symseg): Use new file_entry fields.
+ Changes for NeXT:
+ (N_TXTADDR): Provide version for NeXT.
+ (N_DATADDR): Provide version for NeXT.
+ (enter_global_ref): Deal with NeXT N_INDR weirdness.
+ (compute_a_out_section_offsets): Likewise.
+ (CPU_TYPE, et al): Mach-O info for the NeXT.
+ (compute_mach_o_section_offsets): Deal with N_INDR
+ strangeness.
+ (write_rel): Likewise.
+ (coptxtrel): Likewise.
+ (copdatrel): Likewise.
+ (write_syms): Likewise.
+ (symtab_init): Deal with NeXT shared library strangeness.
+ * nm.c: Changes for MACH_O:
+ (do_one_file): Remove a.out specific stuff.
+ (read_header_info): New function.
+ (do_one_rel_file): Use it.
+ (read_header): Removed.
+ (print_one_symbol): Deal with Mach-O section ordinals.
+ * size.c: Changes for MACH_O:
+ (do_one_file): Remove a.out specific stuff.
+ (read_header_info): New function.
+ (do_one_rel_file): Use it.
+ (read_header): Removed.
+ * strip.c: Changes for MACH_O:
+ (struct file_entry): Remove struct exec; add generic
+ fields to contain necessary information.
+ (main): Use new file_entry fields.
+ (file_open): Remove a.out specific stuff.
+ (read_header): Use new file_entry fields. Handle
+ Mach-O files.
+ (read_entry_symbols): Use new file_entry fields.
+ (count_file_symbols): Likewise.
+ (rewrite_file_symbols): Likewise.
+ (write_file_syms): Likewise.
+ (modify_relocation): Likewise.
+
+Mon May 28 16:25:59 1990 Mike Haertel (mike at apple-gunkies)
+
+ * Copied the binutils home to work on. So please anyone
+ else don't make any changes!!!!
+
+ * Removed gprof.texinfo from ARCHLIST because the file
+ it was symbolically linked to mysteriously disappeared.
+
+Mon May 21 18:39:33 1990 Jim Kingdon (kingdon at mole.ai.mit.edu)
+
+ * Makefile (clean): Also remove $(archpfx)*.o.
+
+ * nm.c (print_one_symbol): Cast n_other and n_desc to unsigned
+ before passing to printf.
+
+Tue May 15 15:19:49 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * ARCHLIST: Add signame.h.
+
+Sun May 6 23:41:35 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * Makefile (dist): Don't make an uncompressed tar file.
+
+Sat Apr 7 22:58:27 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * Makefile (MALLOC): Add.
+ ARCHLIST: Add gmalloc.c.
+ gmalloc.c: New file linked from ../lib/malloc.
+
+Fri Apr 6 00:02:22 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * Makefile: Make objdump depend on a.out.gnu.h.
+
+ * gprof.c: Remove never-used declaration of getopt.
+
+ * gprof.c: Add REMOVE_TIME_IF_THERE to not complain on gcc-compiled
+ programs.
+
+Tue Mar 20 15:41:22 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * hp-bin/mkhplib: Create a dummy libg.a.
+
+Thu Mar 1 14:22:02 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * ld.c (classify_arg, decode_option): Functions removed, with
+ some of the code moved to decode_command.
+ (decode_command): Use getopt_long_only instead of custom arg parser.
+ (usage, fatal, fatal_with_file): Use `progname' instead
+ of hardcoded name.
+ (usage): If STRING is null, don't print it.
+
+ * Makefile: Link ld with GNU_GETOPT_LONG.
+
+Wed Feb 28 14:32:06 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * ranlib.c (main): Call psignal() with arguments in the correct order.
+ signame.c, signame.h: New files (linked from ../lib).
+ ranlib.c: Include signame.h.
+
+ * Makefile: Make sure LIBS is after every program which
+ uses GNU_GETOPT_LONG (for alloca()).
+
+Thu Feb 15 23:35:07 1990 Jim Kingdon (kingdon at mole.ai.mit.edu)
+
+ * ar.c (mywrite): New function which checks for errors.
+ All over: Use it instead of write.
+ (perror_with_name): If errno >= sys_nerr, print "unknown error"
+ not "can't open".
+ (extract_member): Use ferror to check for error.
+
+Tue Feb 13 14:29:24 EST 1990 Jay Fenlason (hack@wookumz.ai.mit.edu)
+
+ * strip.c (rewrite_file_symbols) Seek to the right place in
+ COFF files. A three line patch from Eliot Dresselhaus
+ (eliot@mgm.mit.edu).
+
+Wed Jan 31 22:15:11 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * hp-include: Remove sys/fcntl.h
+
+ * nm.c [USG], ar.c [LOCKS]: Include <fcntl.h> not <sys/fcntl.h>.
+
+Fri Jan 26 20:13:12 1990 Mike Haertel (mike at rice-chex)
+
+ * Makefile: Removed references to GNU CC in copyright notice.
+
+Thu Jan 11 03:32:52 1990 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * ARCHLIST: Include ARCHLIST in distribution.
+
+ * ranlib.c: If X_OK is not defined, define it (for USG).
+ (main, touch_symdefs): Include program name in error messages.
+
+ * strip.c (xmalloc): Don't check for size != 0.
+ (usage): New function.
+ (main): Call usage instead of fprintf or fatal.
+
+Wed Jan 10 15:06:00 1990 Jim Kingdon (kingdon at pogo)
+
+ * ld.c (subfile_wanted_p): Never use a library to satisfy a
+ program's common symbol.
+
+ * ld.c (symtab_init) [sun]: Use symbol_define for __DYNAMIC.
+ [sequent]: Same for _i387_flt.
+
+Wed Jan 10 01:44:58 1990 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * size.c (main): Exit with 0 status normally, instead of garbage.
+ * strip.c (main): Make -g a recognized option. Document -g in
+ usage message. Exit with 0 status normally.
+ * nm.c (main): Exit with 0 status normally.
+ * gprof.c (main): Ditto.
+
+Mon Jan 8 00:06:55 1990 Mike Haertel (mike at rice-chex)
+
+ * strip.c (main): Made -g a synonym for -S (strip debugging
+ symbols) for greater mnemonic value.
+
+Thu Dec 28 02:41:37 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * objdump.c, ld.c, nm.c, size.c (xmalloc, xrealloc): Take the
+ change to return 0 if size is 0 back out. bfox convinced me
+ that, assuming that programs do not allocate 0 bytes
+ intentionally, printing an error message if they try makes
+ it easier to track down the bug.
+
+Sat Dec 23 00:49:43 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * ld.c (usage): Mention some options that were missing from the
+ usage message.
+
+ * ranlib.c (main): stbf wasn't defined. Use access instead
+ of stat, since it tests for execute permission.
+
+Fri Dec 22 23:38:15 1989 David J. MacKenzie (djm at rice-chex)
+
+ * ar.c, ld.c, nm.c: Put various alloca declaration stuff in
+ one place, and declare it as char * if not GNU C or sparc.
+
+ * ld.c, nm.c, size.c (xmalloc, xrealloc): Return char *, not int.
+ Ok to return 0 if 0 bytes requested (ANSI C).
+ Fix declarations for [x][re]alloc.
+
+ * strip.c (main): Combine fprintf calls for usage.
+
+Fri Dec 22 11:23:26 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ranlib.c (main): Look for ar in /usr/local/gnubin first.
+ Rename `jak' to `junk'.
+ Move `#define vfork' to start of file. Don't declare it extern.
+
+Thu Dec 21 17:02:54 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * gprof.c (main): Combine fprintf calls in usage message.
+
+ * objdump.c (usage): Combine fprintf calls.
+
+ * robotussin.c (main): Add dashes to usage message to reduce
+ confusion of three 'f's in a row . . . .
+
+ * nm.c (main): Combine several fprintf calls to make usage
+ message easier to edit.
+
+ * ld.c (usage): New function to print error message and usage message.
+ (decode_command, decode_option): Call usage instead of fatal.
+
+ * ar.c (usage): New function to print error message and usage message.
+ (main): Call usage instead of fatal.
+
+Fri Dec 15 16:05:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * ld.c (perform_relocation) [CROSS_LINKER]: New code.
+
+Tue Dec 12 00:17:41 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * ld.c (symtab_init): Use _edata not __edata.
+
+Mon Dec 11 23:34:51 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * ld.c: Always call each_full_file with 2 args.
+
+Mon Dec 4 16:02:43 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Makefile: Define bindir.
+ (install): Add semicolon to end of 'cp' and 'mv' lines.
+ (install): Double last '$' in 'mv' line.
+
+Sat Dec 2 13:54:22 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * objdump.c (usage): Remove stray newline in message.
+
+Thu Nov 30 21:38:02 1989 David J. MacKenzie (djm at rice-chex)
+
+ * objdump.c (usage): Update to reflect Jim's change.
+
+Thu Nov 30 19:05:17 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * objdump.c (main): Rename +sym-links to +symbols.
+
+ * nm.c (do_one_rel_file): Check for validity of string table
+ offsets to avoid core dumps on bad input files.
+
+ * ld.c (process_subentry): Remove variable prev and assign
+ directly to *prev_addr.
+
+Thu Nov 30 15:33:59 1989 Jay Fenlason (hack at gnu.ai.mit.edu)
+
+ * Fixed gprof.c so it would compile and run. Jim forgot
+ a } and said FUN1 when he meant EXT1 when he added
+ the demangle stuff.
+
+Mon Nov 27 18:12:30 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * objdump.c: Add page_size.
+ (main): Set it.
+
+Mon Nov 27 16:35:50 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * Makefile (dist): Give up on weird linking schemes for making
+ the distribution archive, and simply read the list of files to
+ put in the archive from a file.
+
+ * gprof.c (main): Rename long options:
+ suppress-local to no-static, suppress-blurbs to brief,
+ suppress-arg-prof to no-prof, suppress-arg-time to no-time,
+ arg-prof-only to only-prof, arg-time-only to only-time.
+
+Sun Nov 26 00:46:10 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * gprof.c (main): Make long_options static. Mention long
+ options in usage message. Use common code for handling
+ equivalent long and short named options.
+
+Fri Nov 24 03:44:04 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * Makefile (dist): Don't distribute backup files in the hp-bin
+ and hp-include directories.
+
+ * strip.c (main): Add null terminating element to
+ long_options. Print a usage message if an invalid option is
+ given.
+
+ * ranlib.c (main): Add `val' element to long_options elements.
+ Print a usage message if an invalid option is given.
+
+ * gprof.c (main): Add null terminating element to
+ long_options. Mention long options in usage message and exit
+ if an invalid option is given.
+
+ * nm.c (main): Rename +debug-syms to +all and +reverse-sort to
+ +reverse. Add null terminating element to long_options.
+ Print a usage message if given an invalid option.
+
+ * objdump.c: Add program_name variable.
+ (main): Rename +syms to +sym-links. Add null
+ terminating element to long_options. Set program_name.
+ (usage): Mention long options and use program_name.
+ (xmalloc): New function to allocate memory with error check.
+ Global: use xmalloc instead of malloc.
+ Global: Use program_name in error messages.
+
+Mon Nov 20 16:58:25 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * objdump.c [!COFF_ENCAPSULATE]: Define N_MAGIC.
+
+ * ld.c (main) [COFF_ENCAPSULATE]: Don't write coff header
+ for output of ld -A.
+ (read_file_symbols, read_header): Seek past coff header for
+ input with just_syms_flag set.
+
+Fri Nov 17 02:45:43 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * objdump.c (dump_header) [__GNU_EXEC_MACROS]: Don't access a_info
+ field of struct exec.
+
+ * objdump.c: Include <a.out.h> not "a.out.gnu.h"
+
+ * objdump.c (main): Make long_options static.
+
+Thu Nov 16 22:55:38 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * Makefile (ranlib): Depend on getopt.
+
+Thu Nov 16 11:48:27 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * ld.c (decode_option, case 'r'): Set default_magic instead
+ of magic.
+ (decode_command): Use default_magic.
+
+ * Makefile (CPLUS_DEM): Use this for nm and gprof.
+
+ * nm.c (print_one_symbol): Use cplus_demangle.
+
+ * gprof.c (many): Use cplus_demangle when printing names.
+
+ * ld.c (copdatrel): Use N_DATADDR(outheader) for correct
+ behavior under 'ld -r -n'.
+
+ * ld.c (relocate_file_addresses): Use DATA_ADDR_DOT_O
+ instead of entry->header.a_text.
+
+Wed Nov 15 13:08:49 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * ld.c (digest_symbols): When padding data to 8 byte boundary,
+ set pad_data so that write_data() can write the padding.
+ Change old computation of pad_data to add to pad_data instead
+ of assigning into it.
+
+ * ld.c (perform_relocation): Add variable data_input_address
+ to deal with NMAGIC input files.
+
+ * ld.c (symbol_define): New function.
+ (symtab_init): Use it.
+
+ * robotussin [sun386]: Merge sun386 changes.
+
+Tue Nov 14 12:52:34 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Makefile (ld): Change ld to $(archpfx)ld.
+
+ * Makefile (objdump): Add GNU_GETOPT_LONG to dependencies.
+
+ * ld.c [pyr, hp300]: Define INITIALIZE_HEADER and N_{TXT,DATA}ADDR.
+
+Sat Nov 11 12:08:21 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * ld.c (symtab_init): Don't mess with user-defined "etext".
+ (digest_symbols): Check for e{text,data}_symbol null.
+
+ * ld.c (main): Call symtab_init after load_symbols.
+
+ * ld.c (write_output): Add call to unlink.
+
+Wed Nov 8 11:19:08 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * strip.c (relocation_info_ptr, RELOCATION_INFO_SYMBOL_NUM):
+ Added.
+ (modify_relocation): Use them.
+
+ * Makefile (strip): Use GNU_GETOPT_LONG, not GNU_GETOPT.
+
+ * ld.c [sun]. Set machtype based on machtype of object files.
+ (read_header): Call READ_HEADER_HOOK if defined.
+
+Fri Nov 3 15:18:15 EST 1989 Jay Fenlason (hack@ai.mit.edu)
+
+ * nm.c (main) make long_options static so it can be compiled with cc.
+ * strip.c (main) ditto.
+
+Thu Oct 26 12:28:33 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * Makefile (install): Supply missing `done'.
+
+Tue Oct 17 12:50:46 1989 Mike Haertel (mike at wheat-chex)
+
+ * ld.c (enter_file_symbols): ignore symbols of type
+ N_SETV | N_EXT. These shouldn't be here at all should
+ they?
+
+Mon Oct 16 16:53:03 1989 Joseph Arceneaux (jla at apple-gunkies.ai.mit.edu)
+
+ * ld.c (process_subentry): New function called from
+ linear_library.
+
+Fri Oct 6 10:46:40 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * gprof.c [!HAVE_VPRINTF]: Put in v{f,s}printf emulations.
+
+Mon Oct 2 17:20:42 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c [sequent] (N_TXTADDR, N_DATADDR): Define these macros.
+ [sequent] (INITIALIZE_HEADER): Define this same as for i386.
+ (RELOC_MEMORY_SUB_P): New customization macro.
+ Define as 0 on sun 4. Define as 0 for defaults.
+ [sequent] (RELOC_* macros): Definitions for sequent.
+ (decode_command, digest_symbols): Handle case where NMAGIC is undefined.
+ (enter_global_ref) [sequent]: Handle special N_SHUNDF code.
+ (digest_symbols, write_symbols) [sequent]: Adjust outheader.a_text.
+ (perform_relocation): Handle RELOC_MEMORY_SUB_P like ..._ADD_P.
+ (symtab_init) [sequent]: Define symbol `_387_flt' w/ value 0.
+
+Fri Sep 22 11:06:25 EDT 1989 hack@ai.mit.edu
+
+ * gprof.c (main) Installed Joy's code for using the long-option names.
+
+Thu Sep 21 03:24:36 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c (symtab_init) [sun]: Define __DYNAMIC as 0.
+ (perform_relocation) [RELOC_ADD_EXTRA]:
+ Special handling for relocatable_output case.
+ (read_file_relocation): Fix error message typos.
+
+Mon Sep 18 14:40:40 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c (digest_symbols): Pad data and bss to 8 byte boundary.
+
+Fri Sep 15 16:42:33 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU)
+
+ * a.out.gnu.h [sony]: Defined SEGMENT_SIZE as 0x2000.
+
+ * Makefile (ranlib): Include getopt in the link.
+ (objdump): New rule.
+ (install): New rule.
+
+Fri Sep 1 01:32:01 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU)
+
+ * ranlib.c: Added copyright notice and license info.
+
+Wed Aug 30 20:53:21 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU)
+
+ * Makefile (LIBS): Also get getopt1.o.
+ (dist): Include getopt1.c.
+
+ * ranlib.c (main): Move long option array into main, and fixed it so it
+ will compile.
+
+ * Makefile (dist): Link rather than copy files into the subdir.
+ Include system.h and getopt.h.
+
+Thu Aug 24 14:33:48 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * ld.c (do_file_warnings): Don't print out multiple definition
+ warnings at references.
+
+Mon Aug 21 20:19:08 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (make_new_symdefs): Abort if MAPELT->info.name is nil.
+ (update_symdefs): In the loop that calls make_new_symdefs, reject
+ deleted members (i.e., TAIL->info.name == 0).
+
+ * ar.c (make_new_symdefs): Return if we fail reading the header or the
+ magic number is bad.
+
+ * ar.c (make_new_symdefs): Check for ridiculous string table offsets.
+
+ * ranlib.c (main): If the child ar exits with a signal, print the
+ signal that killed it.
+
+ * ar.c (make_new_symdefs): Check for a ridiculous string table size.
+
+ * ar.c (write_archive): When fixing up symdefs, use each member's
+ new_offset rather than data_offset.
+
+ * ar.c (update_symdefs): When the old archive's string table is too
+ small, die, don't just bitch.
+
+ * ar.c (update_symdefs): Don't decrement num_old_symdefs when deleting
+ symdefs of deleted members. After compactifying old symdefs, decrease
+ num_old_symdefs as necessary.
+
+ * ar.c (update_symdefs): When removing symdefs of deleted members,
+ compare the symdef offsets to the mapelt's data offset, not its header
+ offset.
+
+Sat Aug 19 08:07:26 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (header_from_map): Print correct message when truncating.
+
+ * ar.c (find_mapelt_noerror, header_from_map): Truncate to 15 chars,
+ not 16.
+
+ * ranlib.c (main): Don't do the first ar run an infinite number of
+ times. One will suffice.
+
+ * ranlib.c (main): Under -v, echo the ar command before running it.
+
+ * ar.c (ignore_symdef): New variable. If nonzero, only do symdef
+ processing if the `s' option is given.
+ (main): If one of the members given on the command line is __.SYMDEF,
+ set ignore_symdef.
+ (scan): If ignore_symdef is nonzero, don't set symdef_exists.
+
+ * ar.c (find_mapelt_noerror): A mapelt matches NAME if the names are
+ the same for 14 characters and either both end in ".o", or they are the
+ same for as many more characters as they both have (i.e., the longer
+ name is truncated to the length of the shorter name for the
+ comparison).
+
+ * ar.c (update_symdefs): When correcting a bad string table size,
+ correct the size of the __.SYMDEF member as well.
+
+ * ar.c (update_symdefs): Keep track of the space in the string table
+ accounted for by deleted members. If the old archive's string table
+ size was too big, correct it; if it was too small, die.
+
+Tue Aug 15 00:54:37 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu)
+
+ * ranlib.c (main): Use getopt, and accept new `-v' option, which means
+ to pass `v' to ar. Use vfork instead of fork. Look at the status of
+ the children, and exit if it's nonzero. Also added error checking on
+ several calls.
+
+ * ar.c (write_archive): Fully initialize the new mapelt for __.SYMDEF.
+
+Sun Aug 13 00:01:27 1989 Joy Kendall (jak at hobbes.ai.mit.edu)
+
+ * strip.c, nm.c, objdump.c: Installed versions with long
+ named options available, i.e., getopt substituted with
+ getopt_long.
+
+ * Makefile: changed GNU_GETOPT to GNU_GETOPT_LONG (need to
+ make sure I did this right)
+
+Wed Aug 9 00:24:34 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (write_archive): When rewriting the symdef member, seek to its
+ header offset, not its data offset.
+
+ * ar.c (header_from_map): New function to convert a `struct mapelt' to
+ an ar header.
+
+ * ar.c: Miscellaneous cosmetic clean-ups.
+
+ * ar.c (copy_out_member): If truncating the member name, and the
+ desired name (which is too long) ends in ".o", make the written member
+ name end in ".o" as well.
+
+Tue Aug 8 16:26:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (classify_arg): Added 'V' to the list of possible
+ argument having thingys.
+
+ * ld.c (do_relocation_warnings, do_file_warnings): Changed
+ messages slightly and removed hack to allow N_WARNING name to
+ be a printf string taking stuff as arguments.
+
+Mon Aug 7 16:27:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c: Created set_element_prefixes (list of symbol name
+ prefixes to force symbols to be treated as set elements).
+ (main): Initialized to 0.
+ (decode_option): -V name recognized as defining a prefix.
+ (set_element_prefixed_p): New function.
+ (enter_file_symbols): Check every symbol to see if it has a
+ prefix; if so, change the type.
+ (subfile_wanted_p): A subfile isn't wanted if the symbol
+ definition indicated is a set element by prefix.
+
+ * ld.c [N_WARNING]: Changed commenting.
+
+ * ld.c (do_file_warnings): On the second pass for actual
+ warning symbols, warn only if it isn't a definition and it
+ isn't the reference used by the warning symbol itself.
+
+Fri Aug 4 13:04:57 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c: Remove the warning field from struct file entry.
+ (enter_file_symbols): Deal with N_WARNING symbols on a
+ per symbol basis instead of a per file basis.
+ (mark_flagged_symbols): Deleted.
+ (do_warnings): Don't call mark_flagged_symbols anymore.
+
+ * ld.c: Improved commenting on new GNU symbols.
+
+ * ld.c (subfile_wanted_p): Don't load in files for a set
+ element symbol definition.
+
+Thu Aug 3 12:54:30 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (write_output): Checked return code on last chmod and
+ output error if there is one.
+
+Wed Aug 2 13:26:16 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * ld.c (enter_global_ref): Separate out cases of undefined
+ reference and defining it versus from stuff done whenever you
+ define a symbol. Clean up assignment to sp->defined.
+
+Tue Aug 1 23:12:07 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c: Created count common_defined_global_count.
+ (main): Initialized to 0.
+ (symdef_library): Symbol is needed if it isn't defined OR it's
+ defined common. Don't stop looking till we don't have any
+ more symbols defined as common.
+ (linear_library): Don't stop looking until we have no more
+ symbols defined as common.
+ (subfile_wanted_p): If a symbol is defined common, we want to
+ check for a real definition. If it used to be undefined and
+ we've defined it by common, increment CDGC.
+ (enter_global_ref): If a symbol is defined common and it used
+ to be undefined, increment CDGC. If it is defined for real
+ and it used to be defined common, decrement CDGC and zero
+ max_common_size (so we can tell that it isn't defined common
+ any more). Rewrote logic to be cleaner.
+
+Mon Jul 31 14:52:25 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * ld.c (digest_symbols): Reverse the order of the set element
+ vector so that the elements will be in the order of the input
+ files to ld.
+
+Mon Jul 31 00:19:05 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu)
+
+ * ld.c [sun && sparc]: Don't include alloca.h if !defined(__GNUC__).
+
+Mon Jul 24 19:29:40 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (enter_global_ref): Produce a warning message and
+ rewrite not to be so dangerous if someone is clueless enough
+ to indirect a symbol to itself.
+
+Fri Jul 14 04:04:19 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (write_archive): Don't zero out the count of old symdefs if we
+ just read some.
+ (update_symdefs): Don't copy symdefs onto themselves when compacting.
+
+Wed Jul 12 16:16:36 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (write_archive): Use read_old_symdefs if the member is there.
+ (make_new_symdefs): Return if passed a deleted member.
+
+ * ar.c (write_archive): Zero out the info of the new __.SYMDEF member
+ properly.
+
+Mon Jul 10 22:16:08 1989 Randy Smith (roland at hobbes.ai.mit.edu)
+
+ * ld.c (enter_global_ref): Put the type of the nlist entry with the
+ strongest type into the "defined" field of the symbol. Used this to
+ determine the first definition of a set element.
+
+Wed Jul 5 17:29:27 1989 Randy Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (do_file_warnings): Find undefined references on second
+ passes.
+
+Fri Jun 30 03:32:50 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu)
+
+ * ar.c [__GNUC__]: Use __builtin_alloca.
+ [sparc]: Include <alloca.h>.
+
+ * ar.c (copy_out_member): After writing the header, set the entry's
+ `data_offset' field to the current file position.
+ (write_archive): After copying out members, check for any whose data
+ offsets weren't known when the symdef member was written, fix up the
+ offsets, and rewrite the symdef member.
+
+Thu Jun 29 21:29:35 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu)
+
+ * ar.c (main): Call exit (0), instead of running off the end.
+
+Tue Jun 27 02:11:22 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (make_new_symdefs): Rewritten to correctly convert the namelist
+ to symdefs.
+
+ * ar.c (replace_members): Write the archive if symdef_flag is true and
+ there is no symdef member.
+
+ * Makefile: Added $(archpfx) where appropriate.
+
+ * ld.c (symdef_library): When decode_library_subfile returns nil
+ (meaning it hit the end of the library archive), barf.
+
+Mon Jun 26 17:41:38 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * ld.c (do_warnings): Take out the blank line printed at the
+ end of the warning routine.
+
+ * ld.c (do_file_warnings): When looking for multiple
+ definitions, don't print out references (things that are just
+ N_EXT).
+
+Sun Jun 25 15:17:42 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (requestedp): Removed unused function.
+ (find_mapelt): Use find_mapelt_noerror.
+ (find_mapelt_noerror): Compare only the first 16 chars of names.
+ (error): Accept more args.
+ (copy_out_member): Write a message if the member name is truncated.
+
+ * GNUmakefile: Just include Makefile, rather than doing the silly
+ recursion bit.
+
+ * ar.c (write_archive): Split unlocking and closing into new function
+ close_archive.
+ (replace_members): If nothing changed, don't write the archive!
+
+ * ar.c: Only write old Unix style informational messages
+ (x - foo, a - bar, etc.). 1003.2 requires it (sigh).
+
+Wed Jun 21 21:45:57 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (insert_in_map): Only write one message under -v.
+ (print_descr): Use puts instead of printf where applicable.
+
+ * ar.c (copy_out_member): Don't say "copying ... to new archive" under
+ -v. This amounts to listing the entire archive with each insertion.
+
+ * Makefile (ranlib.o): Use $(bindir)/ar rather than `pwd`/ar.
+
+Tue Jun 20 18:46:42 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * ar.c (main): The `u' flag implies the `r' operation.
+
+Mon Jun 12 19:12:37 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu)
+
+ * nm.c Fixed #ifndef N_WARNING to actually compile correctly.
+
+ * ld.c (N_TXTADDR, N_DATADDR): Changed #ifdef vax to
+ #if defined(vax) || defined(sony_news)
+ so that it'll compile on the Sony's.
+
+Tue Jun 6 15:27:10 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (print_files_defining_symbol): Eliminated.
+ (main): Zero the first cmdline references after it is allocated.
+ (add_cmdline_ref): Make sure that we don't overwrite the end of the
+ array.
+
+Sun May 28 15:15:42 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * nm.c (,print_one_symbol): Added code to handle N_WARNING.
+
+Thu May 11 20:26:23 1989 Mike Haertel (mike at apple-gunkies.ai.mit.edu)
+
+ * ld.c (read_file_symbols): Use a struct exec instead of an int
+ for magic number checking.
+ * nm.c (do_one_file): Similar change.
+ * size.c (do_one_file): Similar change.
+ * strip.c (file_open): Similar change.
+
+Thu May 11 16:33:51 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ar.c (update_symdefs): Detect null pointer in info.name.
+
+Thu May 4 01:53:32 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * Makefile: Provide $(LIBS) when linking strip.
+
+Mon May 1 16:40:27 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (main): Change return from main to be exit from main
+ (supported on more systems).
+
+Mon Apr 24 14:47:53 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c (decode_option, classify_arg): Accept -Bstatic as no-op.
+
+Mon Apr 24 13:08:48 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu)
+
+ * gprof.c: Removed #ifdef __STDC__ stuff from all the
+ function headers, etc.
+
+Sun Apr 23 00:16:09 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c: Define INITIALIZE_HEADER for ALTOS.
+
+ * robotussin.c (reloc_segment): Handle R_RELLONG like R_DIR32.
+ (INPUT_MAGIC): Set it for 386 or 68k according to predef symbols.
+
+ * ranlib.c: Handle USG. Define bzero, gettimeofday.
+ New macro `seconds' defined for USG or BSD.
+ Include sys/types.h and fcntl.h.
+
+Thu Apr 20 14:47:37 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * robotussin.c: discard symbols in section -1.
+
+ * libconvert: change *.o to * in for statement.
+
+Mon Apr 10 16:54:43 1989 Pace Willisson (pace at apple-gunkies.ai.mit.edu)
+
+ * strip.c (rewrite_file_symbols): Make strip work for
+ COFF_ENCAPSULATE (it used to write the new exec header at
+ file offset 0, instead of using HEADER_SEEK_FD)
+
+Fri Mar 10 15:50:45 1989 Randall Smith (randy at sugar-bombs.ai.mit.edu)
+
+ * ranlib.c (touch): Created to simply touch an archive (update the
+ date on the symdef member). Done here since adding an option to
+ ar.c would be a hassle and using the routines in ar.c would
+ require doing almost all of the work of an "ar rs x.a" anyway.
+ Same result in both cases; differing amounts of time.
+
+Mon Mar 6 15:27:56 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu)
+
+ * gprof.c (ck_fclose) only fflush() streams opened for writing.
+
+Sun Mar 5 17:13:37 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * ar.c (write_archive): Modified test to write symdef header;
+ wasn't being done if the symdef map entry didn't need to be newly
+ created.
+
+Fri Mar 3 10:56:55 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * *.*, Makefile: Changed to use new wording as directed by the new
+ GNU General Public License.
+ * COPYING: Created as a link to /gp/rms/COPYING.
+
+Wed Feb 22 04:42:54 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * Makefile: Use GNU getopt by preference.
+
+ * gprof.c [USG]: Define bcopy as macro.
+
+Tue Feb 21 04:46:44 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c (INITIALIZE_HEADER) [HPUX]: Use N_SET_MACHTYPE.
+
+Sat Feb 18 12:47:36 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Added note for using GNU getopt for app routines.
+ Linked (symlink) it into this directory.
+
+ * ld.c: Added #ifndef sony_news around inclusion of fcntl.h. This
+ file duplicates code in sys/file.h on the sony.
+
+ * nm.c: Added include of alloca.h on a sun4 and use of
+ __builtin_alloca if compiling with GCC.
+
+Sat Feb 18 09:43:51 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ar.c (write_archive): Don't die if info.name is 0 (member deleted).
+ (scan): Reverse fread args, so value is right.
+
+Fri Feb 17 05:19:50 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ar.c (extract_members, scan): Open just a FILE *, and pass that.
+ (extract_member, print_contents): Expect a FILE *; no need to fdopen.
+
+Thu Feb 16 07:36:03 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * gprof.c: Reformatted.
+
+Fri Feb 3 14:28:24 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (do_warnings): Changed calls to each_full_file to each_file
+ (which is what we want, since we are concerned with symbol
+ definitions).
+
+ * ld.c: Added a parameter MAX_ALIGNMENT, defined in #ifdef sparc
+ and by default, to set the maximum necessary alignment for data
+ objects on this machine. This is necessary for allocation in the
+ bss area.
+ (digest_symbols): Made sure that everything allocated had the
+ minimum of it's alignment (lowest bit set in the size) or the
+ MAX_ALIGNMENT.
+
+Thu Jan 26 13:31:52 1989 Pace Willison (pace at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Delete -Dnounderscore, add gprof to USG PROG list
+
+ * ar.c (rename for USG): ignore error from first unlink
+
+ * gprof.c: COFF_ENCAPSULATE and USG changes.
+
+ * ld.c strip.c: Deal with internal labels starting with '.' on
+ nounderscore machines and 'L' on normal ones (LPREFIX).
+
+ * ld.c(next_debug_entry): Mask n_type field in switch statement
+ since it is a char, and some of its values (N_SOL) are > 128, which
+ get sign extended on some machines.
+
+ * objdump.c: Deal with symbols that have no name; mask fields
+ of nlist before printing.
+
+Mon Jan 23 14:08:43 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * ld.c (coptxtrel, copdatrel): Made sure that, when relocation is
+ being copied, that N_INDR symbols were properly followed. Also
+ made sure that the symbol indicies were correct even in the
+ presence of indirection information.
+
+ * ld.c (write_rel): When specifying symbol numbers, make sure to
+ leave room for the extra undefined ref that will be written for
+ the sake of N_INDR entries.
+
+ * ld.c (write_syms): Fixed typo; a duplicate of the N_INDR entry
+ was being written instead of the undefined ref required.
+
+Tue Jan 17 16:23:56 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * strip.c (rename): Arranged to ignore return code from "unlink";
+ file may not be there.
+
+Thu Jan 12 15:24:23 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Modified "dist" target so as to get hp-*
+ subdirectories.
+
+ * strip.c (rename): Added function to mimic BSD system call for
+ system V.
+
+Tue Jan 10 19:44:33 1989 Pace Willison (pace at prep.ai.mit.edu)
+
+ * Makefile: put -Dnounderscore back for COFF_ENCAPSULATE.
+
+Tue Jan 10 17:58:50 1989 Randall Smith (randy at cream-of-wheat.ai.mit.edu)
+
+ * ld.c (linear_library, symdef_library, list_file_locals,
+ write_file_syms): Took care to make sure that when the buffer
+ pointed to by entry->strings became invalid, entry->strings was
+ set to zero (either on a free or a function return if space had
+ been allocated through alloca).
+
+ * ld.c (getpagesize): Deleted define in hpux dependent section;
+ taken care of when compiling on hpux because of define of USG in
+ Makefile.
+
+Mon Jan 9 22:49:42 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * strip.c (strip_file): Effectively defer certain signals
+ while rewriting the file.
+
+Mon Jan 9 09:45:41 1989 Pace Willisson (pace at prep.ai.mit.edu)
+
+ * These changes improve support for COFF_ENCAPSULATE, and
+ for the future development of the GNU exec header. The
+ main change is to rename the exec header field a_magic
+ so that it can contain additional information. Now, the
+ magic number must be accessed with N_MAGIC(exec), and set
+ with N_SET_MAGIC(exec,val). Programs that only need to use
+ N_BADMAG will not have to change. Also COFF_ENCAPSULATE will
+ no longer use "nounderscore", so that it will be more like
+ normal bsd systems. This means gcc must be updated before using
+ these new tools. (It is safe to put -Dnounderscore back in
+ if you want to use an old gcc for a while.)
+
+ * README-ENCAP: new documentation for how to set up to use
+ COFF_ENCAPSULATE.
+
+ * Makefile: Add target for gnulib.
+ Don't define 'nounderscore' (must tell gcc about that too.)
+
+ * ar.c: Don't automatically define COFF_ENCAPSULATE.
+
+ * nm.c: No need to initialize the header before reading it.
+
+ * size.c: Include, sys/types.h, and sys/fcntl.h if USG
+ * strip.c: Likewise--types.h before file.h.
+
+ * ld.c, objdump.c, robotussin.c:
+ Changed to use new exec macros for a_magic.
+
+ * libconvert: now takes arguments
+
+ * robotussin.c: don't automatically define nounderscore - leave
+ that to the makefile, if desired
+
+Fri Jan 6 13:06:37 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (digest_symbols, write_text, write_data): Changed N_SETV
+ from being in the text area to being in the data area.
+ * nm.c, a.out.gnu.h: Changed comments to conform with above.
+
+ * ld.c (do_file_warnings): Added loop to go through each external
+ nlist entry and check for multiple definitions, as well as
+ catching any references which weren't caught by the relocation
+ pass.
+
+ * ld.c (address_to_line): Changed so that it will work (albeit
+ slowly) with an address less than the current address.
+ (do_file_warnings, do_relocation_warnings): Broke out scan through
+ relocation entries into a separate function. Added creation of a
+ bitvector with each bit refereing to an nlist entry so that
+ do_relocation_warnings could mark which symbol entries it had
+ output for undefined references.
+
+Thu Jan 5 20:36:44 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c: Cosmetic changes: Moved helper functions for
+ do_file_warnings to before it and modified comments to
+ next_debug_symbol and address_to_line.
+
+Wed Jan 4 15:37:52 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * ld.c: Added #define getpagesize() EXEC_PAGESIZE for hpux.
+
+ * ld.c (do_warnings): Will now print out all undefined external
+ symbols which were not referenced from the text or data sections
+ separately.
+ (do_file_warnings): Decreases undefined_global_sym_count for each
+ symbol printed.
+
+Tue Jan 3 23:43:41 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * Makefile (nm): Link with $(LIBS).
+
+ * ld.c (getpagesize): HPUX definition deleted; not needed.
+
+Mon Jan 2 23:04:35 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (digest_symbols): Modified the creation of set vectors
+ to include a zero word after the end of the vector.
+ (write_text): Made the same modification of the set vector section
+ size.
+
+Sun Jan 1 12:01:22 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c: Fixed typo in description of relocation values, and
+ changed note on RELOC_ADD_EXTRA to force is to be an lvalue if
+ it's defined.
+ (coptxtrel): If a specific relocation entry has just changed from
+ external to internal, and we aren't supposed to add in memory on
+ the new relocation value, make sure that the value of the symbol
+ get's added to the ADD_EXTRA in the relocation value. Otherwise,
+ all the work we do in a partial linking will be wasted (will be in
+ memory, but will be ignored on the next pass of the linker).
+
+Sat Dec 31 13:13:01 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c: Removed "|| TARGET == SUN2" from line 210; I believe that
+ TARGET and SUN2 were both showing up defined as 0 on the sparc,
+ which resulted in a redefine of the INITIALIZE_HEADER macro, back
+ to sun2 style.
+
+Thu Dec 29 01:48:03 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c, ar.c: Don't define COFF_ENCAPSULATE automatically.
+ The recommended Makefile change defines it.
+
+ * ld.c (alloca): If compiling with GCC, use __builtin_alloca.
+
+ * robotussin.c: New reformatted version with all variables renamed.
+
+ * ranlib.c: New file, just runs `ar rs' on each specified file.
+ * Makefile: Special hack to tell ranlib where to find GNU ar.
+ (LIBS): Recommend -lPW on USG; ld needs it for alloca (if not GCC).
+
+Sat Dec 24 13:59:09 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c (error): Start with name of program running.
+ (main): Set `progname' to that name.
+ (digest_symbols): Fix punctuation and spelling in calls to `error'.
+
+Tue Dec 20 21:49:46 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * robotussin.c (INPUT_MAGIC): New macro, has the magic number
+ to expect in input files.
+ (nounderscore): New macro; as in ld, define it to inhibit
+ adding underscore to symbols.
+
+ * Makefile: Don't compile objdump on BSD; N_DATADDR causes trouble.
+
+Tue Dec 20 14:57:38 1988 Pace Willisson (pace at prep.at.mit.edu)
+
+ * objdump.c: New program like the system 5 'dump' program.
+ Documentation will follow...
+
+ * Makefile: Set up CFLAGS for USG systems. Added target
+ libc.a to do robotussin conversion. Added objdump.
+
+ * libconvert: Wrote shell script to do robotussin conversion.
+
+ * ar.c, ld.c: Don't define COFF_ENCAPSULATE if it is already defined.
+
+ * ld.c: If i386, set a_machtype to M_386. Use a_flags instead
+ of a_encap. Don't compute coff header if it isn't going to
+ get written out.
+
+ * robotussin.c: Define COFF_ENCAPSULATE. Include a.out.encap.h
+ instead of a.out.h. Check magic number of input
+ file. Skip over optional header, if present. Don't ignore
+ symbols with aux entries (they could be function definitions),
+ instead, ignore symbols beginning with '.' (.text, etc).
+ Don't prepend underscore to externals, since gcc doesn't do
+ it now. Don't run past the end of symbols that are exactly
+ eight characters long. Always write the string table size,
+ even if it is empty. Change relocation types handled from
+ R_PCRBYTE, etc, to R_DIR32 and R_PCRLONG (these are the
+ only two emitted by the system 5 assembler.)
+
+ * size.c: Include <sys/types.h> so including sys/file.h will
+ not get an error on USG systems. Include fcntl.h on usg systems.
+
+ * strip.c: Move inclusion of file.h to after types.h. Include
+ fcntl.h. Add defintion of rename.
+
+Fri Dec 16 13:55:11 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * size.c: Delete all ROBOTUSSIN conditionals and contents.
+ Change SYSV conditionals to USG.
+ COFF_ENCAPSULATE conditionals for headers.
+ (do_one_file, read_header): Skip encapsulation headers if any.
+
+ * strip.c: Delete all ROBOTUSSIN conditionals and contents.
+ Change SYSV conditionals to USG.
+ COFF_ENCAPSULATE conditionals for headers.
+ (file_open, read_header): Skip encapsulation headers if any.
+
+ * strip.c: Change most fatal errors to nonfatal.
+ (file_open, read_header, read_{file,entry}_symbols):
+ Now return 0 for success, -1 for failure.
+ Failure means do no more for the current file.
+ (modify_relocation): Now just warn if strip a symbol needed
+ for relocation, and warn only once per file.
+ (error_with_file): New function, replaces most fatal_with_file.
+ Print filename first, as in most programs.
+ (fatal_with_file): Deleted.
+ (rewrite_file_symbols): Use perror_file when system call fails.
+
+Tue Dec 13 17:16:39 1988 Jay Fenlason (hack at apple-gunkies.ai.mit.edu)
+
+ * ar.c: Changed pad character after odd-length archive member
+ from \0 to \n so archives can be cmp'd with the output from /bin/ar
+ Added fix for when ranlib is using ar to insert an __.SYMDEF member
+
+Tue Dec 13 09:09:27 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ar.c: conditional #includes for USG.
+ * COFF_ENCAPSULATE conditionals for headers.
+ (extract_member): Don't do fchmod if USG.
+ Alternate USG code to set modtimes of extracted members.
+ (write_archive): Don't do fsync if USG.
+ (make_new_symdefs): Skip encapsulation headers if any.
+ [USG] (bcopy, bzero, bcmp): New fns.
+
+ * nm.c: Delete all ROBOTUSSIN conditionals and contents.
+ Include types.h.
+ Change SYSV conditionals to USG.
+ * COFF_ENCAPSULATE conditionals for headers.
+ (do_one_file): Skip encapsulation headers if any.
+ (read_header): Likewise.
+
+ * ld.c: Delete all ROBOTUSSIN conditionals and contents.
+ Change SYSV conditionals to USG.
+ Change HEADER_TYPE back to `struct exec'.
+ (L_SET): Define it if headers don't.
+ * COFF_ENCAPSULATE conditionals for headers.
+ (main): Update text_size differently if encapsulating.
+ (write_header): Write the encapsulation headers if nec.
+ Don't end with padding if encapsulation being done.
+ [USG] (bzero, bcopy, getpagesize): New fns.
+
+Tue Dec 6 13:26:56 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c (do_file_warnings): Ignored text relocation entries that
+ went through local symbols; any problems with lack of definitions
+ etc. with them would have been caught by the compiler.
+
+Mon Dec 5 16:13:22 1988 Jay Fenlason (hack at sugar-bombs.ai.mit.edu)
+
+ * ar.c (make_new_symdefs): On error, close the input files.
+
+Thu Nov 10 18:15:07 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * ld.c: Put declaration of alloca inside an #ifdef so that it
+ wouldn't mess up on the sparc.
+
+ * ld.c: Added #define CORE_ADDR for include of symseg.h from gdb
+ and took out TARGET == SUN2 for sun2 INITIALIZE_HEADER.
+
+Wed Nov 2 18:43:09 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * ld.c: Merged in isi68k port. This included a kludge for symbols
+ starting with _$ (#ifdef DOLLAR_KLUDGE) and addition of the
+ STANDARD_SEARCH_DIRS macro to override the default if it's
+ defined.
+
+ * ld.c: Added code for the N_WARNING symbol type. If a reference
+ is found to a symbol in an input .o file which contains an
+ N_WARNING symbol, a warning message (the name of the N_WARNING
+ symbol) is printed. This name is treated as a printf format
+ string; the name of the symbol referenced (which caused the
+ warning) is supplied as a single argument to the print which
+ interpets this string.
+
+Tue Nov 1 16:57:00 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * ld.c: Added code for Sun 2.
+
+ * ld.c: Modified access to the relocation information to be *much*
+ more general; added in sparc support. This change is a minor
+ performance hit; the perform_relocation routine uses about 0.1
+ seconds more time on linking gdb than did the original ld.
+ (perform_relocation is about 5% of the total time the loader
+ spends). The price of generality.
+
+Thu Aug 4 13:20:50 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
+
+ * Modified ld.c to print only the first 10 unresolved references
+ for each symbol, followed by a message indicating that there are
+ more unresolved references that have not been printed (if indeed
+ there are). Made default behaivior upon errors *not* writing any
+ output file at all. Also added the -noinhibit-exec flag to force
+ writing of an executable when that was desirable.
+
+Tue Aug 2 12:04:01 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
+
+ * Modified ld.c to give line numbers wherever possible on
+ unreferenced symbols. Added a new symbol (N_DSLNE) to allow for
+ the same mapping of data location to line number as is done for
+ text segments by N_SLINE. Added code to sort the relocation
+ entries when it is necessary to output these line numbers. The
+ assumption was made that both N_SLINE and N_DSLNE symbols would
+ always be in order by address.
+
+Wed Jul 27 15:13:08 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
+
+ * Modified ld.c to include a facility for equivalencing two
+ symbols (translating one to another). Modified lib/a.out.h to
+ include a definition of this new symbol. Modified nm.c to
+ recognize this symbol and all of the set element and vector
+ symbols I had added before.
+
+Thu Jul 21 17:06:10 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
+
+ * Modified ld.c to printout source file and line numbers for
+ unresolved references whenever possible (ie. whenever the input
+ file has debugger symbols and the reference is from the text area).
+
+Wed Jul 13 17:21:33 1988 Randy Smith (randy at frosted-flakes.ai.mit.edu)
+
+ * Modified ld.c and a.out.h to handle new types of symbols; the
+ loader can now create "sets" of symbols from entries in its input
+ files. See a.out.h for more info. Also fixed a bug in ld in
+ which references to common areas that we not defined in one pass
+ of the loader caused errors on the next.
+
+Sat Jul 2 00:05:44 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ld.c (symdef_library): Error check was off by one.
+
+Mon May 9 12:53:08 1988 Chris Hanson (cph at kleph)
+
+ * ar.c (replace_members): After updating map, write out
+ `change_map->next' rather than `map', since the latter may be
+ null.
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+End:
diff --git a/binutils-1.9/Makefile b/binutils-1.9/Makefile
new file mode 100644
index 0000000..8a4beda
--- /dev/null
+++ b/binutils-1.9/Makefile
@@ -0,0 +1,167 @@
+# Makefile for GNU binary-file utilities
+# Select a set of CFLAGS and PROGS, below, depending on the system type.
+# Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+#
+# This file is part of the GNU binutils.
+#
+# The GNU binutils are free software; you can redistribute them and/or modify
+# them under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# The GNU binutils are distributed in the hope that they will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with the GNU binutils; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# gprof.c contains `void *' and very long string constants which many
+# C compilers can't handle, so you might need gcc to compile it.
+GNUCC = gcc -O
+# But you might need to use your old C compiler to compile the other
+# programs (ld at least), if you can't run gcc without them
+# (particularly on COFF systems).
+#CC = cc
+
+bindir=/usr/local/gnubin
+
+# For BSD:
+# For SunOS 4.x, take out -DVPRINTF_MISSING.
+CFLAGS = -g -DVPRINTF_MISSING
+# Don't add robotussin; it won't compile on BSD or GNU systems.
+# objdump is not here because it (at least used to) not compile
+# on most systems (trouble with N_DATADDR). Some of those problems
+# have been fixed, though.
+PROGS = $(archpfx)gprof $(archpfx)ld $(archpfx)size \
+ $(archpfx)nm $(archpfx)strip $(archpfx)ar $(archpfx)ranlib
+
+# For USG systems using COFF_ENCAPSULATE:
+# Also, you will want to make the target libc.a (but it takes a long time).
+# Note that you should leave a copy of `ar' in this directory
+# after you install it, since `ranlib' will try to run it from here.
+#CFLAGS=-g -DUSG -DCOFF_ENCAPSULATE -DPORTAR -DNON_NATIVE -DSYS_SIGLIST_MISSING
+#PROGS = ld size nm strip ar robotussin objdump ranlib gprof
+#SIGNAME = $(archpfx)signame.o
+# On ALTOS systems, add -DALTOS to CFLAGS.
+
+#It's better to move a copy of alloca into your libc than to risk getting some
+#incompatible functions from -lPW (like index()), but if you
+#want to be lazy, uncomment this line.
+#ALLOCALIBS = -lPW
+
+# For HP-UX:
+# Don't add `robotussin'; use `hpxt' instead.
+# Note that you should leave a copy of `ar' in this directory
+# after you install it, since `ranlib' will try to run it from here.
+#CFLAGS = -g -Ihp-include -DUSG -DNON_NATIVE -DVPRINTF_MISSING
+#PROGS = ld size nm strip ar ranlib
+#ALLOCALIBS = alloca.o
+
+# For the NeXT:
+# Set GNUCC = cc -O.
+# Put -DMACH_O in CFLAGS, take out -DVPRINTF_MISSING.
+# Comment out MALLOC below to use the system's malloc().
+
+# For Sun386:
+# Compile with -DPORTAR -DCOFF_ENCAPSULATE.
+# Depending on how you configure gcc, you might also want -Dnounderscore,
+# though I did not wind up using it.
+
+# If you run out of stack space while running GNU ar or GNU ld (this
+# manifests itself as a segment violation), you should link in alloca.c
+# from the gcc sources, and get rid of the "#define alloca" in ar.c and
+# ld.c; or you could try to get Sun to fix this annoying "feature".
+#CFLAGS = -g -DCOFF_ENCAPSULATE -DPORTAR
+#PROGS = ld size nm strip ar robotussin objdump ranlib gprof
+
+# nm tries to malloc enough space for the string table. The old GNU malloc
+# rounds this up to a power of two (e.g. 5M becomes 8M), and so it might
+# fail unnecessarily. I've also seen some Unix malloc's fail, even when
+# there is enough memory. So use the new GNU malloc.
+MALLOC = $(archpfx)gmalloc.o
+
+GNU_GETOPT = $(archpfx)getopt.o
+GNU_GETOPT_LONG = $(archpfx)getopt.o $(archpfx)getopt1.o
+
+# C++ demangler
+CPLUS_DEM = $(archpfx)cplus-dem.o
+
+LIBS=$(ALLOCALIBS) $(SIGNAME)
+
+all: $(PROGS)
+
+$(archpfx)ld: $(archpfx)ld.o $(GNU_GETOPT_LONG) $(CPLUS_DEM) $(LIBS)
+# LIBS is used here since ld needs to use alloca.
+# Alternatively, compile it with GNU C--then the compiler handles alloca.
+ $(CC) $(CFLAGS) -o $(archpfx)ld $(archpfx)ld.o $(GNU_GETOPT_LONG) $(CPLUS_DEM) $(LIBS)
+
+$(archpfx)size: $(archpfx)size.o $(LIBS)
+ $(CC) $(CFLAGS) -o $(archpfx)size $(archpfx)size.o
+
+$(archpfx)nm: $(archpfx)nm.o $(GNU_GETOPT_LONG) $(CPLUS_DEM) $(MALLOC) $(LIBS)
+ $(CC) $(CFLAGS) -o $(archpfx)nm $(archpfx)nm.o \
+ $(GNU_GETOPT_LONG) $(CPLUS_DEM) $(LIBS) $(MALLOC)
+
+$(archpfx)strip: $(archpfx)strip.o $(archpfx)error.o $(GNU_GETOPT_LONG) $(LIBS)
+ $(CC) $(CFLAGS) -o $(archpfx)strip $(archpfx)strip.o $(archpfx)error.o $(GNU_GETOPT_LONG) $(LIBS)
+
+$(archpfx)ar: $(archpfx)ar.o $(LIBS)
+ $(CC) $(CFLAGS) -o $(archpfx)ar $(archpfx)ar.o $(LIBS)
+
+$(archpfx)gprof: $(archpfx)gprof.o $(GNU_GETOPT_LONG) $(CPLUS_DEM) $(LIBS)
+ $(GNUCC) $(CFLAGS) -o $(archpfx)gprof $(archpfx)gprof.o \
+ $(GNU_GETOPT_LONG) $(CPLUS_DEM) $(LIBS)
+$(archpfx)gprof.o: gprof.c gmon.h
+ $(GNUCC) $(CFLAGS) -c gprof.c $(OUTPUT_OPTION)
+
+$(archpfx)ranlib: $(archpfx)ranlib.o $(GNU_GETOPT_LONG) $(LIBS)
+ $(CC) $(CFLAGS) -o $(archpfx)ranlib $(archpfx)ranlib.o $(GNU_GETOPT_LONG) $(LIBS)
+$(archpfx)ranlib.o: ranlib.c
+ $(CC) -c $(CFLAGS) -DAR_PROG=\"$(bindir)/ar\" ranlib.c $(OUTPUT_OPTION)
+
+$(archpfx)objdump: $(archpfx)objdump.o $(archpfx)error.o $(GNU_GETOPT_LONG) a.out.gnu.h $(LIBS)
+ $(CC) $(CFLAGS) -o $(archpfx)objdump $(archpfx)objdump.o $(archpfx)error.o \
+ $(GNU_GETOPT_LONG) $(LIBS)
+
+# Robotussin is NOT part of `all'.
+$(archpfx)robotussin: $(archpfx)robotussin.o $(LIBS)
+ $(CC) $(CFLAGS) -o $(archpfx)robotussin $(archpfx)robotussin.o
+
+libc.a: $(archpfx)robotussin libconvert $(archpfx)ar
+ libconvert /lib/libc.a libc.a
+
+# usg-gnulib is the file gcc makes using the usg compiler
+gnulib: $(archpfx)robotussin libconvert usg-gnulib $(archpfx)ar
+ libconvert usg-gnulib gnulib
+
+clean:
+ -rm -f *.o core
+ -rm -f $(archpfx)*.o
+ -rm -f $(PROGS) objdump
+
+DISTNAME = binutils-1.9
+dist:
+ rm -rf $(DISTNAME)
+ mkdir $(DISTNAME) $(DISTNAME)/hp-bin $(DISTNAME)/hp-include
+ ln COPYING ChangeLog Makefile README README-ENCAP \
+ a.out.encap.h a.out.gnu.h ar.c cplus-dem.c \
+ error.c getopt.c getopt.h getopt1.c gmalloc.c \
+ gmon.h gprof.c gprof.texinfo ld.c libconvert nm.c objdump.c \
+ ranlib.c ranlib.h robotussin.c signame.c signame.h size.c \
+ stab.def stab.h strip.c symseg.h $(DISTNAME)
+ cd hp-bin; ln Makefile chatr.c hpxt.c ioutil.c ioutil.h \
+ mkhplib ../$(DISTNAME)/hp-bin
+ cd hp-include; ln a.out.h stab.def stab.h ../$(DISTNAME)/hp-include
+ tar chZf $(DISTNAME).tar.Z $(DISTNAME)
+ rm -rf $(DISTNAME)
+.PHONY: dist
+
+.PHONY: install
+install: $(PROGS)
+ for file in $(PROGS); do \
+ cp $$file $(bindir)/$${file}.new; \
+ mv $(bindir)/$${file}.new $(bindir)/$$file; \
+ done
diff --git a/binutils-1.9/README b/binutils-1.9/README
new file mode 100644
index 0000000..e27720c
--- /dev/null
+++ b/binutils-1.9/README
@@ -0,0 +1,38 @@
+These files are some GNU utilities for operating on binary files.
+GNU make, which used to be included here, is now distributed
+in a separate tar file.
+
+Report bugs in these programs to bug-gnu-utils@prep.ai.mit.edu.
+Please note in the bug report which version of the binutils you are
+using. Prior to version 1.7, the versions were identified by the top
+line of the ChangeLog.
+
+Define USG with `-DUSG' when compiling these programs to run on system V.
+
+COFF is not supported, but we do support a way of encapsulating GNU
+executable files with COFF headers. Use -DCOFF_ENCAPSULATE when you
+compile, to enable this feature.
+
+In order to use encapsulation, you must use entirely GNU tools,
+including these plus GAS, GCC and GDB. You will need to convert the
+system libraries to BSD object file format. Use the shell script
+libconvert (which uses robotussin) for that.
+
+The GNU version of ld has some interesting features:
+
+1. Undefined and multiply-defined global symbol errors
+are now associated with specific source files and line numbers,
+and printed in a format M-x next-error can parse.
+
+2. Normally no output is written if there are serious errors.
+Use the option `-noinhibit-exec' if you want an output file anyway.
+
+3. Global symbols can be defined by indirection to other symbols.
+See comments at definition of N_INDR in ld.c
+
+4. LD can accumulate sets of related values from all the object files
+that are being linked together, and put them into a vector that can
+be accessed at run time. Thus, you can arrange for each file to have
+initializations to be run when your `main' function sees fit, without
+having to know the names of all the files that are linked together.
+See comments at definition of N_SETA, etc., in ld.c.
diff --git a/binutils-1.9/README-ENCAP b/binutils-1.9/README-ENCAP
new file mode 100644
index 0000000..0b171c1
--- /dev/null
+++ b/binutils-1.9/README-ENCAP
@@ -0,0 +1,55 @@
+1/3/89 Pace Willisson
+
+Here is what to do to bring up gcc & tools on an 80386 running system 5.3
+(if you are adventurous and want to use the latest and greatest tools.
+If you want it to be easy, check back in a couple of months.)
+
+All of these instructions assume you are using the usg compiler. After
+you get to the end, you could start over using the gnu compiler, but
+that may not work yet ...
+
+First make gcc, cpp, and gnulib:
+
+ cd .../gcc
+ config.gcc i386-sysv-gas
+ make install
+
+(The i386gnu type was added a little after gcc-1.32)
+(the install part doesn't really work - you will have to look at
+what it tries to do, and do it by hand.)
+
+Now, make the gnu assembler:
+
+ cd .../gas
+ make a386
+ cp a386 /usr/local/lib/gcc-as
+
+Now, make the other utilities:
+
+ cd .../binutils
+
+edit Makefile to turn on the CFLAGS for USG using COFF_ENCAPSULATE
+
+ make
+ cp ld /usr/local/lib/gcc-ld
+
+Put the other programs (size nm strip ar objdump and ranlib) somewhere
+handy, but don't clobber your usg programs. I put them all in
+/usr/gnu/gnucomp, and I have this shell script in my path under the name "gnu":
+
+ exec /usr/gnu/gnucomp/$*
+
+That way, I can say "gnu nm a.out", etc.
+
+Convert the libraries to the encapsulated format:
+
+ make libc.a
+ cp libc.a /usr/local/lib/gnu/libc.a
+
+ cp .../gcc/gnulib usg-gnulib
+ make gnulib
+ cp gnulib /usr/local/lib/gcc-gnulib
+
+ robotussin /lib/crt0.o /usr/local/lib/gcc-crt0.o
+
+Now, you should be able to use 'gcc' to compile programs.
diff --git a/binutils-1.9/a.out.encap.h b/binutils-1.9/a.out.encap.h
new file mode 100644
index 0000000..1a6449c
--- /dev/null
+++ b/binutils-1.9/a.out.encap.h
@@ -0,0 +1,134 @@
+/* Another try at encapsulating bsd object files in coff.
+ Copyright (C) 1988, 1989, Free Software Foundation, Inc.
+ Written by Pace Willisson 12/9/88
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this file; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This time, we will only use the coff headers to tell the kernel
+ * how to exec the file. Therefore, the only fields that need to
+ * be filled in are the scnptr and vaddr for the text and data
+ * sections, and the vaddr for the bss. As far as coff is concerned,
+ * there is no symbol table, relocation, or line numbers.
+ *
+ * A normal bsd header (struct exec) is placed after the coff headers,
+ * and before the real text. I defined a the new fields 'a_machtype'
+ * and a_flags. If a_machtype is M_386, and a_flags & A_ENCAP is
+ * true, then the bsd header is preceeded by a coff header. Macros
+ * like N_TXTOFF and N_TXTADDR use this field to find the bsd header.
+ *
+ * The only problem is to track down the bsd exec header. The
+ * macros HEADER_OFFSET, etc do this. Look at nm.c, dis.c, etc
+ * for examples.
+ */
+
+#if !defined (A_OUT_ENCAP_H)
+#define A_OUT_ENCAP_H 1
+
+#include "a.out.gnu.h"
+
+#define N_FLAGS_COFF_ENCAPSULATE 0x20 /* coff header precedes bsd header */
+
+/* Describe the COFF header used for encapsulation. */
+
+struct coffheader
+{
+ /* filehdr */
+ unsigned short f_magic;
+ unsigned short f_nscns;
+ long f_timdat;
+ long f_symptr;
+ long f_nsyms;
+ unsigned short f_opthdr;
+ unsigned short f_flags;
+ /* aouthdr */
+ short magic;
+ short vstamp;
+ long tsize;
+ long dsize;
+ long bsize;
+ long entry;
+ long text_start;
+ long data_start;
+ struct coffscn
+ {
+ char s_name[8];
+ long s_paddr;
+ long s_vaddr;
+ long s_size;
+ long s_scnptr;
+ long s_relptr;
+ long s_lnnoptr;
+ unsigned short s_nreloc;
+ unsigned short s_nlnno;
+ long s_flags;
+ } scns[3];
+};
+
+/* Describe some of the parameters of the encapsulation,
+ including how to find the encapsulated BSD header. */
+
+#ifdef i386
+#define COFF_MAGIC 0514 /* I386MAGIC */
+#endif
+#ifdef m68k
+#define COFF_MAGIC 0520 /* MC68MAGIC */
+#endif
+
+#ifdef COFF_MAGIC
+short __header_offset_temp;
+#define HEADER_OFFSET(f) \
+ (__header_offset_temp = 0, \
+ fread ((char *)&__header_offset_temp, sizeof (short), 1, (f)), \
+ fseek ((f), -sizeof (short), 1), \
+ __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0)
+
+#define HEADER_OFFSET_FD(fd) \
+ (__header_offset_temp = 0, \
+ read ((fd), (char *)&__header_offset_temp, sizeof (short)), \
+ lseek ((fd), -sizeof (short), 1), \
+ __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0)
+
+
+#else
+#define HEADER_OFFSET(f) 0
+#define HEADER_OFFSET_FD(fd) 0
+#endif
+
+#define HEADER_SEEK(f) (fseek ((f), HEADER_OFFSET((f)), 1))
+#define HEADER_SEEK_FD(fd) (lseek ((fd), HEADER_OFFSET_FD((fd)), 1))
+
+
+/* Describe the characteristics of the BSD header
+ that appears inside the encapsulation. */
+
+#undef _N_HDROFF
+#undef N_TXTADDR
+#undef N_DATADDR
+
+#define _N_HDROFF(x) ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
+ sizeof (struct coffheader) : 0)
+
+/* Address of text segment in memory after it is loaded. */
+#define N_TXTADDR(x) \
+ ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
+ sizeof (struct coffheader) + sizeof (struct exec) : 0)
+#define SEGMENT_SIZE 0x400000
+
+#define N_DATADDR(x) \
+ ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
+ (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))) : \
+ (N_TXTADDR(x)+(x).a_text))
+#endif /* a.out.encap.h not already included. */
diff --git a/binutils-1.9/a.out.gnu.h b/binutils-1.9/a.out.gnu.h
new file mode 100644
index 0000000..2e7cd75
--- /dev/null
+++ b/binutils-1.9/a.out.gnu.h
@@ -0,0 +1,272 @@
+#ifndef __A_OUT_GNU_H__
+#define __A_OUT_GNU_H__
+
+#if defined(sequent) && defined(i386)
+#define a_magic a_info
+#include <a.out.h>
+#undef a_magic
+#define __STRUCT_EXEC_OVERRIDE__
+#define N_NLIST_DECLARED
+#define N_RELOCATION_INFO_DECLARED
+#endif
+
+#define __GNU_EXEC_MACROS__
+
+#ifndef __STRUCT_EXEC_OVERRIDE__
+
+struct exec
+{
+ unsigned long a_info; /* Use macros N_MAGIC, etc for access */
+ unsigned a_text; /* length of text, in bytes */
+ unsigned a_data; /* length of data, in bytes */
+ unsigned a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned a_syms; /* length of symbol table data in file, in bytes */
+ unsigned a_entry; /* start address */
+ unsigned a_trsize; /* length of relocation info for text, in bytes */
+ unsigned a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#endif /* __STRUCT_EXEC_OVERRIDE__ */
+
+/* these go in the N_MACHTYPE field */
+enum machine_type {
+#if defined (M_OLDSUN2)
+ M__OLDSUN2 = M_OLDSUN2,
+#else
+ M_OLDSUN2 = 0,
+#endif
+#if defined (M_68010)
+ M__68010 = M_68010,
+#else
+ M_68010 = 1,
+#endif
+#if defined (M_68020)
+ M__68020 = M_68020,
+#else
+ M_68020 = 2,
+#endif
+#if defined (M_SPARC)
+ M__SPARC = M_SPARC,
+#else
+ M_SPARC = 3,
+#endif
+ /* skip a bunch so we don't run into any of sun's numbers */
+ M_386 = 100,
+};
+
+#if !defined (N_MAGIC)
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#define N_SET_INFO(exec, magic, type, flags) \
+ ((exec).a_info = ((magic) & 0xffff) \
+ | (((int)(type) & 0xff) << 16) \
+ | (((flags) & 0xff) << 24))
+#define N_SET_MAGIC(exec, magic) \
+ ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+
+#define N_SET_MACHTYPE(exec, machtype) \
+ ((exec).a_info = \
+ ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+
+#define N_SET_FLAGS(exec, flags) \
+ ((exec).a_info = \
+ ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+
+#ifndef OMAGIC
+/* Code indicating object file or impure executable. */
+#define OMAGIC 0407
+/* Code indicating pure executable. */
+#define NMAGIC 0410
+/* Code indicating demand-paged executable. */
+#define ZMAGIC 0413
+#endif /* not OMAGIC */
+
+#if !defined (N_BADMAG)
+#define N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#endif
+
+#define _N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+
+#define _N_HDROFF(x) (SEGMENT_SIZE - sizeof (struct exec))
+
+#if !defined (N_TXTOFF)
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
+#endif
+
+#if !defined (N_DATOFF)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#endif
+
+#if !defined (N_TRELOFF)
+#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
+#endif
+
+#if !defined (N_DRELOFF)
+#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
+#endif
+
+#if !defined (N_SYMOFF)
+#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
+#endif
+
+#if !defined (N_STROFF)
+#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
+#endif
+
+/* Address of text segment in memory after it is loaded. */
+#if !defined (N_TXTADDR)
+#define N_TXTADDR(x) 0
+#endif
+
+/* Address of data segment in memory after it is loaded.
+ Note that it is up to you to define SEGMENT_SIZE
+ on machines not listed here. */
+#if defined(vax) || defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+#ifdef hp300
+#define PAGE_SIZE 4096
+#endif
+#ifdef sony
+#define SEGMENT_SIZE 0x2000
+#endif /* Sony. */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+
+#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+#endif
+
+/* Address of bss segment in memory after it is loaded. */
+#if !defined (N_BSSADDR)
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+#endif
+
+#if !defined (N_NLIST_DECLARED)
+struct nlist {
+ union {
+ char *n_name;
+ struct nlist *n_next;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ char n_other;
+ short n_desc;
+ unsigned long n_value;
+};
+#endif /* no N_NLIST_DECLARED. */
+
+#if !defined (N_UNDF)
+#define N_UNDF 0
+#endif
+#if !defined (N_ABS)
+#define N_ABS 2
+#endif
+#if !defined (N_TEXT)
+#define N_TEXT 4
+#endif
+#if !defined (N_DATA)
+#define N_DATA 6
+#endif
+#if !defined (N_BSS)
+#define N_BSS 8
+#endif
+#if !defined (N_COMM)
+#define N_COMM 18
+#endif
+#if !defined (N_FN)
+#define N_FN 15
+#endif
+
+#if !defined (N_EXT)
+#define N_EXT 1
+#endif
+#if !defined (N_TYPE)
+#define N_TYPE 036
+#endif
+#if !defined (N_STAB)
+#define N_STAB 0340
+#endif
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+#define N_INDR 0xa
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+#if !defined (N_RELOCATION_INFO_DECLARED)
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct relocation_info
+{
+ /* Address (within segment) to be relocated. */
+ int r_address;
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in file's the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* Four bits that aren't used, but when writing an object file
+ it is desirable to clear them. */
+ unsigned int r_pad:4;
+};
+#endif /* no N_RELOCATION_INFO_DECLARED. */
+
+
+#endif /* __A_OUT_GNU_H__ */
diff --git a/binutils-1.9/ar.c b/binutils-1.9/ar.c
new file mode 100644
index 0000000..82aac69
--- /dev/null
+++ b/binutils-1.9/ar.c
@@ -0,0 +1,2070 @@
+/* ar.c - Archive modify and extract.
+ Copyright (C) 1988, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <ar.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !defined(A_OUT) && !defined(MACH_O)
+#define A_OUT
+#endif
+
+#ifdef A_OUT
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+#endif
+
+#ifdef MACH_O
+#ifndef A_OUT
+#include <nlist.h>
+#endif
+#include <sys/loader.h>
+#endif
+
+#if !defined(USG) || defined(hpux)
+#define HAVE_FCHMOD
+#define HAVE_FSYNC
+#define HAVE_RENAME
+#endif /* !USG || hpux */
+
+#ifdef USG
+#include <time.h>
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#include <sys/time.h>
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+# ifdef sparc
+# include <alloca.h>
+# else
+char *alloca ();
+# endif
+#endif
+
+#ifdef USG
+#define bcopy(source, dest, size) memcpy((dest), (source), (size))
+#define bcmp(a, b, size) memcmp((a), (b), (size))
+#define bzero(s, size) memset((s), 0, (size))
+#endif
+
+/* Locking is normally disabled because fcntl hangs on the Sun
+ and it isn't supported properly across NFS anyway. */
+#ifdef LOCKS
+/* You might need to compile with -I/usr/include/sys if your fcntl.h
+ isn't in /usr/include (which is where it should be according to POSIX). */
+#ifndef USG /* already included for USG */
+#include <fcntl.h>
+#endif /* USG */
+#endif
+
+/* This structure is used internally to represent the info
+ on a member of an archive. This is to make it easier to change format. */
+
+struct member_desc
+ {
+ /* Name of member. */
+ char *name;
+
+ /* The following fields are stored in the member header as decimal or octal
+ numerals, but in this structure they are stored as machine numbers. */
+ int mode; /* Protection mode from member header. */
+ long int date; /* Last modify date as stored in member header. */
+ unsigned int size; /* Bytes of member's data, from member header. */
+ int uid, gid; /* UID and GID fields copied from member header. */
+ unsigned int offset;/* Offset in archive of the header of this member. */
+ unsigned int data_offset;/* Offset of first data byte of the member. */
+
+ /* The next field does not describe where the member was in the
+ old archive, but rather where it will be in the modified archive.
+ It is set up by write_archive. */
+ unsigned int new_offset; /* Offset of this member in new archive */
+
+ /* Symdef data for member. Used only for files being inserted. */
+ struct symdef *symdefs;
+ unsigned int nsymdefs; /* Number of entries of symdef data. */
+ unsigned int string_size; /* Size of strings needed by symdef data. */
+ };
+
+/* Each symbol is recorded by something like this. */
+
+struct symdef
+ {
+ union
+ {
+ unsigned long int stringoffset;
+ char *name;
+ } s;
+ unsigned long int offset;
+ };
+
+/* Nonzero means it's the name of an existing member;
+ position new or moved files with respect to this one. */
+
+char *posname;
+
+/* How to use `posname':
+ POS_BEFORE means position before that member.
+ POS_AFTER means position after that member.
+ POS_DEFAULT if position by default; then `posname' should also be zero. */
+
+enum { POS_DEFAULT, POS_BEFORE, POS_AFTER } postype;
+
+/* Nonzero means describe each action performed. */
+
+int verbose;
+
+/* Nonzero means don't warn about creating the archive file if necessary. */
+
+int silent_create;
+
+/* Nonzero means don't replace existing members whose
+ dates are more recent than the corresponding files. */
+
+int newer_only;
+
+/* Nonzero means preserve dates of members when extracting them. */
+
+int preserve_dates;
+
+/* Operation to be performed. */
+
+#define DELETE 1
+#define REPLACE 2
+#define PRINT_TABLE 3
+#define PRINT_FILES 4
+#define EXTRACT 5
+#define MOVE 6
+#define QUICK_APPEND 7
+
+int operation;
+
+/* Name of archive file. */
+
+char *archive;
+
+/* Descriptor on which we have locked the original archive file,
+ or -1 if this has not been done. */
+
+int lock_indesc;
+
+/* Pointer to tail of `argv', at first subfile name argument,
+ or zero if no such were specified. */
+
+char **files;
+
+/* Nonzero means write a __.SYMDEF member into the modified archive. */
+
+int symdef_flag;
+
+/* Nonzero means __.SYMDEF member exists in old archive. */
+
+int symdef_exists;
+
+/* Nonzero means don't update __.SYMDEF unless the flag was given. */
+
+int ignore_symdef;
+
+/* Total number of symdef entries we will have. */
+
+unsigned long int nsymdefs;
+
+/* Symdef data from old archive (set up only if we need it) */
+
+struct symdef *old_symdefs;
+
+/* Number of symdefs in remaining in old_symdefs. */
+
+unsigned int num_old_symdefs;
+
+/* Number of symdefs old_symdefs had when it was read in. */
+
+unsigned long int original_num_symdefs;
+
+/* String table from old __.SYMDEF member. */
+
+char *old_strings;
+
+/* Size of old_strings */
+
+unsigned long int old_strings_size;
+
+/* String table to be written into __.SYMDEF member. */
+
+char *new_strings;
+
+/* Size of new_strings */
+
+unsigned long int new_strings_size;
+
+/* An archive map is a chain of these structures.
+ Each structure describes one member of the archive.
+ The chain is in the same order as the members are. */
+
+struct mapelt
+{
+ struct member_desc info;
+ struct mapelt *next;
+};
+
+struct mapelt *maplast;
+
+/* If nonzero, this is the map-element for the __.SYMDEF member
+ and we should update the time of that member just before finishing. */
+
+struct mapelt *symdef_mapelt;
+
+/* Header that we wrote for the __.SYMDEF member. */
+
+struct ar_hdr symdef_header;
+
+/* Name this program was run with. */
+char *program_name;
+
+char *xmalloc (), *xrealloc ();
+void free ();
+
+void add_to_map (), delete_from_map ();
+int insert_in_map ();
+void print_descr ();
+char *concat ();
+void scan ();
+void extract_members ();
+void extract_member ();
+void print_contents ();
+void write_symdef_member ();
+void read_old_symdefs ();
+void two_operations ();
+void usage (), fatal (), error (), error_with_file ();
+void perror_with_name (), pfatal_with_name ();
+void write_archive ();
+void touch_symdef_member ();
+void update_symdefs ();
+void delete_members (), move_members (), replace_members ();
+void quick_append ();
+char *basename ();
+
+/* Output BYTES of data at BUF to the descriptor DESC.
+ FILE is the name of the file (for error messages). */
+
+void
+mywrite (desc, buf, bytes, file)
+ int desc;
+ char *buf;
+ int bytes;
+ char *file;
+{
+ register int val;
+
+ while (bytes > 0)
+ {
+ val = write (desc, buf, bytes);
+ if (val <= 0)
+ perror_with_name (file);
+ buf += val;
+ bytes -= val;
+ }
+}
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+
+ operation = 0;
+ verbose = 0;
+ newer_only = 0;
+ silent_create = 0;
+ posname = 0;
+ postype = POS_DEFAULT;
+ preserve_dates = 0;
+ symdef_flag = 0;
+ symdef_exists = 0;
+ ignore_symdef = 0;
+ symdef_mapelt = 0;
+ files = 0;
+ lock_indesc = -1;
+
+ program_name = argv[0];
+
+ if (argc < 2)
+ usage ("too few command arguments", 0);
+
+ {
+ char *key = argv[1];
+ char *p = key;
+ char c;
+
+ if (*p == '-')
+ p++;
+ while (c = *p++)
+ {
+ switch (c)
+ {
+ case 'a':
+ postype = POS_AFTER;
+ break;
+
+ case 'b':
+ postype = POS_BEFORE;
+ break;
+
+ case 'c':
+ silent_create = 1;
+ break;
+
+ case 'd':
+ if (operation)
+ two_operations ();
+
+ operation = DELETE;
+ break;
+
+ case 'i':
+ postype = POS_BEFORE;
+ break;
+
+ case 'l':
+ break;
+
+ case 'm':
+ if (operation)
+ two_operations ();
+ operation = MOVE;
+ break;
+
+ case 'o':
+ preserve_dates = 1;
+ break;
+
+ case 'p':
+ if (operation)
+ two_operations ();
+ operation = PRINT_FILES;
+ break;
+
+ case 'q':
+ if (operation)
+ two_operations ();
+ operation = QUICK_APPEND;
+ break;
+
+ case 'r':
+ if (operation)
+ two_operations ();
+ operation = REPLACE;
+ break;
+
+ case 's':
+ symdef_flag = 1;
+ break;
+
+ case 't':
+ if (operation)
+ two_operations ();
+ operation = PRINT_TABLE;
+ break;
+
+ case 'u':
+ operation = REPLACE;
+ newer_only = 1;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'x':
+ if (operation)
+ two_operations ();
+ operation = EXTRACT;
+ break;
+ }
+ }
+
+ }
+
+ if (operation == 0 && symdef_flag)
+ operation = REPLACE;
+
+ if (operation == 0)
+ usage ("no operation specified", 0);
+
+ i = 2;
+
+ if (postype != POS_DEFAULT)
+ if (i < argc)
+ posname = argv[i++];
+ else
+ usage ("no position operand", 0);
+
+ if (i >= argc)
+ usage ("no archive specified", 0);
+ archive = argv[i++];
+
+ if (i < argc)
+ {
+ files = &argv[i];
+ while (i < argc)
+ if (!strcmp (argv[i++], "__.SYMDEF"))
+ {
+ ignore_symdef = 1;
+ break;
+ }
+ }
+
+ switch (operation)
+ {
+ case EXTRACT:
+ extract_members (extract_member);
+ break;
+
+ case PRINT_TABLE:
+ extract_members (print_descr);
+ break;
+
+ case PRINT_FILES:
+ extract_members (print_contents);
+ break;
+
+ case DELETE:
+ if (files != 0)
+ delete_members ();
+ break;
+
+ case MOVE:
+ if (files != 0)
+ move_members ();
+ break;
+
+ case REPLACE:
+ if (files != 0 || symdef_flag)
+ replace_members ();
+ break;
+
+ case QUICK_APPEND:
+ if (files != 0)
+ quick_append ();
+ break;
+
+ default:
+ usage ("invalid operation %d", operation);
+ }
+
+ exit (0);
+}
+
+void
+two_operations ()
+{
+ usage ("two different operation switches specified", 0);
+}
+
+void
+scan (function, crflag)
+ void (*function) ();
+ int crflag;
+{
+ FILE *arcstream = fopen (archive, "r");
+
+ if (arcstream == 0 && crflag)
+ /* Creation-warning, if desired, will happen later. */
+ return;
+
+ if (arcstream == 0)
+ {
+ perror_with_name (archive);
+ exit (1);
+ }
+ {
+ char buf[SARMAG];
+ int nread = fread (buf, 1, SARMAG, arcstream);
+ if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
+ fatal ("file %s not a valid archive", archive);
+ }
+
+ /* Now find the members one by one. */
+ {
+ int member_offset = SARMAG;
+ while (1)
+ {
+ int nread;
+ struct ar_hdr member_header;
+ struct member_desc member_desc;
+ char name [1 + sizeof member_header.ar_name];
+
+ if (fseek (arcstream, member_offset, 0) < 0)
+ perror_with_name (archive);
+
+ nread = fread (&member_header, 1, sizeof (struct ar_hdr), arcstream);
+ if (nread == 0)
+ /* No data left means end of file; that is OK. */
+ break;
+
+ if (nread != sizeof (member_header)
+ || bcmp (member_header.ar_fmag, ARFMAG, 2))
+ fatal ("file %s not a valid archive", archive);
+ bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
+ {
+ char *p = name + sizeof member_header.ar_name;
+ *p = '\0';
+ while (p > name && *--p == ' ')
+ *p = '\0';
+#ifdef USG
+ if (*p == '/') /* Since V.2, names are terminated with '/' */
+ *p = '\0';
+#endif
+ }
+ member_desc.name = name;
+ sscanf (member_header.ar_mode, "%o", &member_desc.mode);
+ member_desc.date = atoi (member_header.ar_date);
+ member_desc.size = atoi (member_header.ar_size);
+ member_desc.uid = atoi (member_header.ar_uid);
+ member_desc.gid = atoi (member_header.ar_gid);
+ member_desc.offset = member_offset;
+ member_desc.data_offset = member_offset + sizeof (member_header);
+
+ member_desc.new_offset = 0;
+ member_desc.symdefs = 0;
+ member_desc.nsymdefs = 0;
+ member_desc.string_size = 0;
+
+ if (!ignore_symdef && !strcmp (name, "__.SYMDEF"))
+ symdef_exists = 1;
+
+ function (member_desc, arcstream);
+
+ member_offset += sizeof (member_header) + member_desc.size;
+ if (member_offset & 1)
+ ++member_offset;
+ }
+ }
+
+
+ fclose (arcstream);
+}
+
+void print_modes ();
+
+void
+print_descr (member)
+ struct member_desc member;
+{
+ char *timestring;
+ if (!verbose)
+ {
+ puts (member.name);
+ return;
+ }
+ print_modes (member.mode);
+ timestring = ctime (&member.date);
+ printf (" %2d/%2d %6d %12.12s %4.4s %s\n",
+ member.uid, member.gid,
+ member.size, timestring + 4, timestring + 20,
+ member.name);
+}
+
+void
+print_modes (modes)
+ int modes;
+{
+ putchar (modes & 0400 ? 'r' : '-');
+ putchar (modes & 0200 ? 'w' : '-');
+ putchar (modes & 0100 ? 'x' : '-');
+ putchar (modes & 040 ? 'r' : '-');
+ putchar (modes & 020 ? 'w' : '-');
+ putchar (modes & 010 ? 'x' : '-');
+ putchar (modes & 04 ? 'r' : '-');
+ putchar (modes & 02 ? 'w' : '-');
+ putchar (modes & 01 ? 'x' : '-');
+}
+
+#define BUFSIZE 1024
+
+void
+extract_member (member, istream)
+ struct member_desc member;
+ FILE *istream;
+{
+ int ncopied = 0;
+ FILE *ostream;
+
+ fseek (istream, member.data_offset, 0);
+ ostream = fopen (member.name, "w");
+ if (!ostream)
+ {
+ perror_with_name (member.name);
+ return;
+ }
+
+ if (verbose)
+ printf ("x - %s\n", member.name);
+
+ while (ncopied < member.size)
+ {
+ char buf [BUFSIZE];
+ int tocopy = member.size - ncopied;
+ int nread;
+ if (tocopy > BUFSIZE) tocopy = BUFSIZE;
+ nread = fread (buf, 1, tocopy, istream);
+ if (nread != tocopy)
+ fatal ("error reading archive %s", archive);
+ fwrite (buf, 1, nread, ostream);
+ ncopied += tocopy;
+ }
+
+#ifdef HAVE_FCHMOD
+ fchmod (fileno (ostream), member.mode);
+#else
+ chmod (member.name, member.mode);
+#endif
+ if (ferror (ostream) || fclose (ostream) != 0)
+ error ("%s: I/O error", member.name);
+
+ if (preserve_dates)
+ {
+#ifdef USG
+ long tv[2];
+ tv[0] = member.date;
+ tv[1] = member.date;
+ utime (member.name, tv);
+#else
+ struct timeval tv[2];
+ tv[0].tv_sec = member.date;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = member.date;
+ tv[1].tv_usec = 0;
+ utimes (member.name, tv);
+#endif
+ }
+}
+
+void
+print_contents (member, istream)
+ struct member_desc member;
+ FILE *istream;
+{
+ int ncopied = 0;
+
+ fseek (istream, member.data_offset, 0);
+
+ if (verbose)
+ printf ("\n<member %s>\n\n", member.name);
+
+ while (ncopied < member.size)
+ {
+ char buf [BUFSIZE];
+ int tocopy = member.size - ncopied;
+ int nread;
+ if (tocopy > BUFSIZE) tocopy = BUFSIZE;
+ nread = fread (buf, 1, tocopy, istream);
+ if (nread != tocopy)
+ fatal ("file %s not a valid archive", archive);
+ fwrite (buf, 1, nread, stdout);
+ ncopied += tocopy;
+ }
+}
+
+/* Make a map of the existing members of the archive: their names,
+ positions and sizes. */
+
+/* If `nonexistent_ok' is nonzero,
+ just return 0 for an archive that does not exist.
+ This will cause the ordinary supersede procedure to
+ create a new archive. */
+
+struct mapelt *
+make_map (nonexistent_ok)
+ int nonexistent_ok;
+{
+ struct mapelt mapstart;
+ mapstart.next = 0;
+ maplast = &mapstart;
+ scan (add_to_map, nonexistent_ok);
+ return mapstart.next;
+}
+
+void
+add_to_map (member)
+ struct member_desc member;
+{
+ struct mapelt *mapelt = (struct mapelt *) xmalloc (sizeof (struct mapelt));
+ mapelt->info = member;
+ mapelt->info.name = concat (mapelt->info.name, "", "");
+ maplast->next = mapelt;
+ mapelt->next = 0;
+ maplast = mapelt;
+}
+
+/* Return the last element of the specified map. */
+
+struct mapelt *
+last_mapelt (map)
+ struct mapelt *map;
+{
+ struct mapelt *tail = map;
+ while (tail->next) tail = tail->next;
+ return tail;
+}
+
+/* Return the element of the specified map which precedes elt. */
+
+struct mapelt *
+prev_mapelt (map, elt)
+ struct mapelt *map, *elt;
+{
+ struct mapelt *tail = map;
+ while (tail->next && tail->next != elt)
+ tail = tail->next;
+ if (tail->next) return tail;
+ return 0;
+}
+
+/* Return the element of the specified map which has the specified name. */
+
+struct mapelt *
+find_mapelt_noerror (map, name)
+ struct mapelt *map;
+ register char *name;
+{
+ register struct mapelt *tail;
+ unsigned int len;
+ int dot_o;
+
+ name = basename (name);
+ len = strlen (name);
+ dot_o = name[len - 2] == '.' && name[len - 1] == 'o';
+
+ for (tail = map; tail != 0; tail = tail->next)
+ {
+ if (tail->info.name == 0)
+ continue;
+ if (!strncmp (tail->info.name, name, 13))
+ {
+ unsigned int eltlen = strlen (tail->info.name);
+ if (len <= 13 || eltlen <= 13)
+ return tail;
+ else
+ {
+ char *p = tail->info.name + 13;
+ if (dot_o && p[0] == '.' && p[1] == 'o' && p[2] == '\0')
+ return tail;
+ else if (!strncmp (p, name + 13,
+ (len > eltlen ? len : eltlen) - 13))
+ return tail;
+ }
+ }
+ }
+
+ return 0;
+}
+
+struct mapelt *
+find_mapelt (map, name)
+ struct mapelt *map;
+ char *name;
+{
+ register struct mapelt *found = find_mapelt_noerror (map, name);
+ if (found == 0)
+ error ("no member named `%s'", name);
+ return found;
+}
+
+/* Before looking at the archive, if we are going to update it
+ based on looking at its current contents, make an exclusive lock on it.
+ The lock is released when `write_archive' is called. */
+
+void
+lock_for_update ()
+{
+ /* Open the existing archive file; if that fails, create an empty one. */
+
+ lock_indesc = open (archive, O_RDWR, 0);
+
+ if (lock_indesc < 0)
+ {
+ int outdesc;
+
+ if (!silent_create)
+ printf ("Creating archive file `%s'\n", archive);
+ outdesc = open (archive, O_WRONLY | O_APPEND | O_CREAT, 0666);
+ if (outdesc < 0)
+ pfatal_with_name (archive);
+ mywrite (outdesc, ARMAG, SARMAG, archive);
+ close (outdesc);
+
+ /* Now we had better be able to open for update! */
+
+ lock_indesc = open (archive, O_RDWR, 0);
+ if (lock_indesc < 0)
+ {
+ unlink (archive);
+ pfatal_with_name (archive);
+ }
+ }
+
+#ifdef LOCKS
+ /* Lock the old file so that it won't be updated by two programs at once.
+ This uses the fcntl locking facility found on Sun systems
+ which is also in POSIX. (Perhaps it comes from sysV.)
+
+ Note that merely reading an archive does not require a lock,
+ because we use `rename' to update the whole file atomically. */
+
+ {
+ struct flock lock;
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = 0;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ while (1)
+ {
+ int value = fcntl (lock_indesc, F_SETLKW, &lock);
+ if (value >= 0)
+ break;
+ else if (errno == EINTR)
+ continue;
+ else
+ pfatal_with_name ("locking archive");
+ }
+ }
+#endif
+}
+
+/* Unlock archive and close the file descriptor. */
+
+void
+close_archive ()
+{
+#ifdef LOCKS
+ {
+ struct flock lock;
+
+ /* Unlock the old archive. */
+
+ lock.l_type = F_UNLCK;
+ lock.l_whence = 0;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ fcntl (lock_indesc, F_SETLK, &lock);
+ }
+#endif
+
+ /* Close the archive. If we renamed a new one, the old one disappears. */
+ close (lock_indesc);
+}
+
+/* Write a new archive file from a given map. */
+/* When a map is used as the pattern for a new archive,
+ each element represents one member to put in it, and
+ the order of elements controls the order of writing.
+
+ Ordinarily, the element describes a member of the old
+ archive, to be copied into the new one.
+
+ If the `offset' field of the element's info is 0,
+ then the element describes a file to be copied into the
+ new archive. The `name' field is the file's name.
+
+ If the `name' field of an element is 0, the element is ignored.
+ This makes it easy to specify deletion of archive members.
+
+ Every operation that will eventually call `write_archive'
+ should call `lock_for_update' before beginning
+ to do any I/O on the archive file.
+*/
+
+char *make_tempname ();
+void copy_out_member ();
+
+void
+write_archive (map, appendflag)
+ struct mapelt *map;
+ int appendflag;
+{
+ char *tempname = make_tempname (archive);
+ int indesc = lock_indesc;
+ int outdesc;
+ char *outname;
+ struct mapelt *tail;
+
+ /* Now open the output. */
+
+ if (!appendflag)
+ {
+ /* Updating an existing archive normally.
+ Write output as TEMPNAME and rename at the end.
+ There can never be two invocations trying to do this at once,
+ because of the lock made on the old archive file. */
+
+ outdesc = open (tempname, O_WRONLY | O_CREAT, 0666);
+ if (outdesc < 0)
+ pfatal_with_name (tempname);
+ outname = tempname;
+ mywrite (outdesc, ARMAG, SARMAG, outname);
+ }
+ else
+ {
+ /* Fast-append to existing archive. */
+
+ outdesc = open (archive, O_WRONLY | O_APPEND, 0);
+ if (outdesc < 0)
+ pfatal_with_name (archive);
+ outname = archive;
+ }
+
+ /* If archive has or should have a __.SYMDEF member,
+ compute the contents for it. */
+
+ if (symdef_flag || symdef_exists)
+ {
+ if (symdef_exists)
+ read_old_symdefs (map, indesc);
+ else
+ {
+ struct mapelt *this = (struct mapelt *)
+ xmalloc (sizeof (struct mapelt));
+ this->info.name = "__.SYMDEF";
+ this->info.offset = SARMAG;
+ this->info.data_offset = SARMAG + sizeof (struct ar_hdr);
+ this->info.new_offset = 0;
+ this->info.date = 0;
+ this->info.size = 0;
+ this->info.uid = 0;
+ this->info.gid = 0;
+ this->info.mode = 0666;
+ this->info.symdefs = 0;
+ this->info.nsymdefs = 0;
+ this->info.string_size = 0;
+ this->next = map;
+ map = this;
+ original_num_symdefs = 0;
+ old_strings_size = 0;
+ }
+
+ update_symdefs (map, indesc);
+ }
+
+ /* Copy the members into the output, either from the old archive
+ or from specified files. */
+
+ for (tail = map; tail != 0; tail = tail->next)
+ {
+ if ((symdef_flag || symdef_exists) && tail->info.name
+ && !strcmp (tail->info.name, "__.SYMDEF")
+#if 0
+ && tail->info.date==0
+#endif
+ )
+ write_symdef_member (tail, map, outdesc, outname);
+ else
+ copy_out_member (tail, indesc, outdesc, outname);
+ }
+
+ if (symdef_mapelt != 0)
+ {
+ /* Check for members whose data offsets weren't
+ known when the symdef member was first written. */
+ int doneany = 0;
+ for (tail = map; tail != 0; tail = tail->next)
+ if (tail->info.offset == 0)
+ {
+ /* Fix up the symdefs. */
+ register unsigned int i;
+ for (i = 0; i < tail->info.nsymdefs; ++i)
+ tail->info.symdefs[i].offset = tail->info.new_offset;
+ doneany = 1;
+ }
+ if (doneany)
+ {
+ /* Some files had bad symdefs; rewrite the symdef member. */
+ lseek (outdesc, symdef_mapelt->info.offset, 0);
+ write_symdef_member (symdef_mapelt, map, outdesc, outname);
+ }
+ }
+
+ /* Mark the __.SYMDEF member as up to date. */
+
+ if (symdef_mapelt != 0)
+ touch_symdef_member (outdesc, outname);
+
+ /* Install the new output under the intended name. */
+
+#ifdef HAVE_FSYNC
+ fsync (outdesc);
+#endif
+ close (outdesc);
+
+ if (!appendflag)
+ if (rename (tempname, archive))
+ pfatal_with_name (tempname);
+
+ close_archive ();
+}
+
+void
+header_from_map (header, mapelt)
+ struct ar_hdr *header;
+ struct mapelt *mapelt;
+{
+ unsigned int namelen;
+ char *p;
+
+ /* Zero the header, then store in the data as text. */
+ bzero ((char *) header, sizeof (*header));
+
+ p = basename (mapelt->info.name);
+ strncpy (header->ar_name, p, sizeof (header->ar_name));
+ namelen = strlen (p);
+ if (namelen >= sizeof (header->ar_name))
+ {
+ if (mapelt->info.name[namelen - 2] == '.' &&
+ mapelt->info.name[namelen - 1] == 'o')
+ {
+ header->ar_name[sizeof (header->ar_name) - 3] = '.';
+ header->ar_name[sizeof (header->ar_name) - 2] = 'o';
+ }
+ header->ar_name[sizeof (header->ar_name) - 1] = '\0';
+ error ("member name `%s' truncated to `%s'",
+ mapelt->info.name, header->ar_name);
+ }
+#ifdef USG
+ {
+ /* System V tacks a trailing '/' onto the end of the name */
+ char *p = header->ar_name;
+ char *end = p + sizeof (header->ar_name);
+
+ while (p < end && *p)
+ p++;
+ *p = '/';
+ }
+#endif
+
+ sprintf (header->ar_date, "%ld", mapelt->info.date);
+ sprintf (header->ar_size, "%d", mapelt->info.size);
+ sprintf (header->ar_uid, "%d", mapelt->info.uid);
+ sprintf (header->ar_gid, "%d", mapelt->info.gid);
+ sprintf (header->ar_mode, "%o", mapelt->info.mode);
+ strncpy (header->ar_fmag, ARFMAG, sizeof (header->ar_fmag));
+
+ /* Change all remaining nulls in the header into spaces. */
+ {
+ char *end = (char *) &header[1];
+ register char *p;
+ for (p = (char *) header; p < end; ++p)
+ if (*p == '\0')
+ *p = ' ';
+ }
+}
+
+/* gets just the file part of name */
+
+char *
+basename (path)
+ char *path;
+{
+ char *save, *start;
+ for (start = save = path; *path; path++)
+ if (*path == '/')
+ save = path + 1;
+
+ if (save != start)
+ return save;
+ else
+ return start;
+}
+
+/* writes to file open on OUTDESC with name OUTNAME. */
+void
+copy_out_member (mapelt, archive_indesc, outdesc, outname)
+ struct mapelt *mapelt;
+ int archive_indesc;
+ int outdesc;
+ char *outname;
+{
+ struct ar_hdr header;
+ int indesc;
+
+ if (mapelt->info.name == 0)
+ /* This element was cancelled. */
+ return;
+
+ header_from_map (&header, mapelt);
+
+ if (mapelt->info.offset != 0)
+ {
+ indesc = archive_indesc;
+ lseek (indesc, mapelt->info.data_offset, 0);
+ }
+ else
+ {
+ indesc = open (mapelt->info.name, 0, 0);
+ if (indesc < 0)
+ {
+ perror_with_name (mapelt->info.name);
+ return;
+ }
+ }
+
+ mywrite (outdesc, &header, sizeof (header), outname);
+
+ if (mapelt->info.data_offset == 0)
+ mapelt->info.data_offset = lseek (outdesc, 0L, 1);
+
+ {
+ char buf[BUFSIZE];
+ int tocopy = mapelt->info.size;
+ while (tocopy > 0)
+ {
+ int thistime = tocopy;
+ if (thistime > BUFSIZE) thistime = BUFSIZE;
+ read (indesc, buf, thistime);
+ mywrite (outdesc, buf, thistime, outname);
+ tocopy -= thistime;
+ }
+ }
+
+ if (indesc != archive_indesc)
+ close (indesc);
+
+ if (mapelt->info.size & 1)
+ mywrite (outdesc, "\n", 1, outname);
+}
+
+/* Update the time of the __.SYMDEF member; done when we updated
+ that member, just before we close the new archive file.
+ It is open on OUTDESC and its name is OUTNAME. */
+
+void
+touch_symdef_member (outdesc, outname)
+ int outdesc;
+ char *outname;
+{
+ struct stat statbuf;
+ int i;
+
+ /* See what mtime the archive file has as a result of our writing it. */
+ fstat (outdesc, &statbuf);
+
+ /* Advance member's time to that time. */
+ bzero (symdef_header.ar_date, sizeof symdef_header.ar_date);
+ sprintf (symdef_header.ar_date, "%ld", statbuf.st_mtime);
+ for (i = 0; i < sizeof symdef_header.ar_date; i++)
+ if (symdef_header.ar_date[i] == 0)
+ symdef_header.ar_date[i] = ' ';
+
+ /* Write back this member's header with the new time. */
+ if (lseek (outdesc, symdef_mapelt->info.new_offset, 0) >= 0)
+ mywrite (outdesc, &symdef_header, sizeof symdef_header, outname);
+}
+
+char *
+make_tempname (name)
+ char *name;
+{
+#ifdef USG
+ /* sigh. 14 character filenames are *wonderful*, just *wonderful*. */
+ char *p = basename (name);
+ char *q, *r;
+
+ if (p != name)
+ {
+ q = concat (name, "", ""); /* get a fresh copy */
+ r = basename (q); /* r points just after last '/' */
+ *--r = '\0';
+ return concat (q, "/t_", p);
+ }
+ else if (strlen (name) >= 14)
+ return concat ("t_", name, "");
+ else
+#endif
+ return concat (name, "", "_supersede");
+}
+
+void
+delete_members ()
+{
+ struct mapelt *map = make_map (0);
+ struct mapelt mapstart;
+ char **p;
+
+ mapstart.info.name = 0;
+ mapstart.next = map;
+ map = &mapstart;
+
+ lock_for_update ();
+
+ if (files)
+ for (p = files; *p; p++)
+ {
+ /* If user says to delete the __.SYMDEF member,
+ don't make a new one to replace it. */
+ if (!strcmp (*p, "__.SYMDEF"))
+ symdef_exists = 0;
+ delete_from_map (*p, map);
+ }
+
+ write_archive (map->next, 0);
+}
+
+void
+delete_from_map (name, map)
+ char *name;
+ struct mapelt *map;
+{
+ struct mapelt *this = find_mapelt (map, name);
+
+ if (!this) return;
+ this->info.name = 0;
+ if (verbose)
+ printf ("d - %s\n", name);
+}
+
+void
+move_members ()
+{
+ struct mapelt *map = make_map (0);
+ char **p;
+ struct mapelt *after_mapelt;
+ struct mapelt mapstart;
+ struct mapelt *change_map;
+
+ mapstart.info.name = 0;
+ mapstart.next = map;
+ change_map = &mapstart;
+
+ lock_for_update ();
+
+ switch (postype)
+ {
+ case POS_DEFAULT:
+ after_mapelt = last_mapelt (change_map);
+ break;
+
+ case POS_AFTER:
+ after_mapelt = find_mapelt (map, posname);
+ break;
+
+ case POS_BEFORE:
+ after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
+ }
+
+ /* Failure to find specified "before" or "after" member
+ is a fatal error; message has already been printed. */
+
+ if (!after_mapelt) exit (1);
+
+ if (files)
+ for (p = files; *p; p++)
+ {
+ if (move_in_map (*p, change_map, after_mapelt))
+ after_mapelt = after_mapelt->next;
+ }
+
+ write_archive (map, 0);
+}
+
+int
+move_in_map (name, map, after)
+ char *name;
+ struct mapelt *map, *after;
+{
+ struct mapelt *this = find_mapelt (map, name);
+ struct mapelt *prev;
+
+ if (!this) return 0;
+ prev = prev_mapelt (map, this);
+ prev->next = this->next;
+ this->next = after->next;
+ after->next = this;
+ return 1;
+}
+
+/* Insert files into the archive. */
+
+void
+replace_members ()
+{
+ struct mapelt *map = make_map (1);
+ struct mapelt mapstart;
+ struct mapelt *after_mapelt;
+ struct mapelt *change_map;
+ char **p;
+ int changed;
+
+ mapstart.info.name = 0;
+ mapstart.next = map;
+ change_map = &mapstart;
+
+ lock_for_update ();
+
+ switch (postype)
+ {
+ case POS_DEFAULT:
+ after_mapelt = last_mapelt (change_map);
+ break;
+
+ case POS_AFTER:
+ after_mapelt = find_mapelt (map, posname);
+ break;
+
+ case POS_BEFORE:
+ after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
+ }
+
+ /* Failure to find specified "before" or "after" member
+ is a fatal error; the message has already been printed. */
+ if (after_mapelt == 0)
+ exit (1);
+
+ changed = 0;
+ if (files != 0)
+ for (p = files; *p != 0; ++p)
+ if (insert_in_map (*p, change_map, after_mapelt))
+ {
+ after_mapelt = after_mapelt->next;
+ changed = 1;
+ }
+
+ change_map = change_map->next;
+ if (!changed && (!symdef_flag || symdef_exists))
+ /* Nothing changed. */
+ close_archive (change_map);
+ else
+ write_archive (change_map, 0);
+}
+
+/* Handle the "quick insert" operation. */
+
+void
+quick_append ()
+{
+ struct mapelt *map;
+ struct mapelt *after;
+ struct mapelt mapstart;
+ char **p;
+
+ mapstart.info.name = 0;
+ mapstart.next = 0;
+ map = &mapstart;
+ after = map;
+
+ lock_for_update ();
+
+ /* Insert the specified files into the "map",
+ but is a map of the inserted files only,
+ and starts out empty. */
+ if (files)
+ for (p = files; *p; p++)
+ {
+ if (insert_in_map (*p, map, after))
+ after = after->next;
+ }
+
+ /* Append these files to the end of the existing archive file. */
+
+ write_archive (map->next, 1);
+}
+
+/* Insert an entry for name NAME into the map MAP after the map entry AFTER.
+ Delete an old entry for NAME.
+ MAP is assumed to start with a dummy entry, which facilitates
+ insertion at the beginning of the list.
+ Return 1 if successful, 0 if did nothing because file NAME doesn't
+ exist or (optionally) is older. */
+
+int
+insert_in_map (name, map, after)
+ char *name;
+ struct mapelt *map, *after;
+{
+ struct mapelt *old = find_mapelt_noerror (map, name);
+ struct mapelt *this;
+ struct stat status;
+
+ if (stat (name, &status))
+ {
+ perror_with_name (name);
+ return 0;
+ }
+ if (old && newer_only && status.st_mtime <= old->info.date)
+ return 0;
+ if (old)
+ /* Delete the old one. */
+ old->info.name = 0;
+ this = (struct mapelt *) xmalloc (sizeof (struct mapelt));
+ this->info.name = name;
+ this->info.offset = 0;
+ this->info.data_offset = 0;
+ this->info.date = status.st_mtime;
+ this->info.size = status.st_size;
+ this->info.uid = status.st_uid;
+ this->info.gid = status.st_gid;
+ this->info.mode = status.st_mode;
+ /* Always place a __.SYMDEF member first in the archive, regardless
+ of any position specifications. */
+ if (! strcmp (name, "__.SYMDEF"))
+ this->next = map->next, map->next = this;
+ else
+ this->next = after->next, after->next = this;
+
+ if (verbose)
+ printf ("%c - %s\n", old == 0 ? 'a' : 'r', this->info.name);
+
+ return 1;
+}
+
+/* Apply a function to each of the specified members.
+*/
+
+void
+extract_members (function)
+ void (*function) ();
+{
+ struct mapelt *map;
+ FILE *arcstream;
+ char **p;
+
+ if (!files)
+ {
+ /* Handle case where we want to operate on every member.
+ No need to make a map and search it for this. */
+ scan (function, 0);
+ return;
+ }
+
+ arcstream = fopen (archive, "r");
+ if (!arcstream)
+ fatal ("failure opening archive %s for the second time", archive);
+ map = make_map (0);
+
+ for (p = files; *p; p++)
+ {
+ struct mapelt *this = find_mapelt (map, *p);
+ if (!this) continue;
+ function (this->info, arcstream);
+ }
+
+ fclose (arcstream);
+}
+
+/* Write the __.SYMDEF member from data in core. OUTDESC and OUTNAME
+ are descriptor and name of file to write to. */
+
+void
+write_symdef_member (mapelt, map, outdesc, outname)
+ struct mapelt *mapelt;
+ struct mapelt *map;
+ int outdesc;
+ char *outname;
+{
+ struct ar_hdr header;
+ struct mapelt *mapptr;
+ unsigned long int symdefs_size;
+
+ if (mapelt->info.name == 0)
+ /* This element was cancelled. */
+ return;
+
+ header_from_map (&header, mapelt);
+
+ bcopy (&header, &symdef_header, sizeof header);
+
+ mywrite (outdesc, &header, sizeof (header), outname);
+
+ /* Write the number of symdefs. */
+ symdefs_size = nsymdefs * sizeof (struct symdef);
+ mywrite (outdesc, &symdefs_size, sizeof symdefs_size, outname);
+
+ /* Write symdefs surviving from old archive. */
+ mywrite (outdesc, old_symdefs, num_old_symdefs * sizeof (struct symdef),
+ outname);
+
+ /* Write symdefs for new members. */
+ for (mapptr = map; mapptr != 0; mapptr = mapptr->next)
+ if (mapptr->info.nsymdefs != 0)
+ write (outdesc, mapptr->info.symdefs,
+ mapptr->info.nsymdefs * sizeof (struct symdef));
+
+ /* Write the string table size. */
+ mywrite (outdesc, &new_strings_size, sizeof new_strings_size, outname);
+
+ /* Write the string table. */
+ mywrite (outdesc, new_strings, new_strings_size, outname);
+
+ if (mapelt->info.size & 1)
+ mywrite (outdesc, "", 1, outname);
+}
+
+void
+read_old_symdefs (map, archive_indesc)
+ struct mapelt *map;
+ int archive_indesc;
+{
+ struct mapelt *mapelt;
+ char *data;
+ int val;
+ int symdefs_size;
+
+ mapelt = find_mapelt_noerror (map, "__.SYMDEF");
+ if (!mapelt)
+ abort (); /* Only call here if an old one exists */
+
+ data = (char *) xmalloc (mapelt->info.size);
+ lseek (archive_indesc, mapelt->info.data_offset, 0);
+ val = read (archive_indesc, data, mapelt->info.size);
+
+ symdefs_size = *(unsigned long int *) data;
+ original_num_symdefs = symdefs_size / sizeof (struct symdef);
+ old_symdefs = (struct symdef *) (data + sizeof (symdefs_size));
+ old_strings = ((char *) (old_symdefs + original_num_symdefs)
+ + sizeof (symdefs_size));
+ old_strings_size
+ = *(unsigned long int *) (old_symdefs + original_num_symdefs);
+}
+
+/* Read various information from the header of an object file.
+ Return 0 for failure or 1 for success. */
+
+int
+read_header_info (mapelt, desc, offset, syms_offset, syms_size, strs_offset, strs_size)
+ struct mapelt *mapelt;
+ int desc;
+ long int offset;
+ long int *syms_offset;
+ unsigned int *syms_size;
+ long int *strs_offset;
+ unsigned int *strs_size;
+{
+#ifdef A_OUT
+ {
+ struct exec hdr;
+
+ lseek (desc, offset, 0);
+#ifdef HEADER_SEEK_FD
+ HEADER_SEEK_FD (desc);
+#endif
+
+ if (read (desc, (char *) &hdr, sizeof hdr) == sizeof hdr && !N_BADMAG(hdr))
+ {
+ *syms_offset = N_SYMOFF (hdr);
+ *syms_size = hdr.a_syms;
+ *strs_offset = N_STROFF (hdr);
+ lseek (desc, N_STROFF (hdr) + offset, 0);
+ if (read (desc, (char *) strs_size, sizeof *strs_size) != sizeof *strs_size)
+ {
+ error_with_file ("failure reading string table size in ", mapelt);
+ return 0;
+ }
+ return 1;
+ }
+ }
+#endif
+
+#ifdef MACH_O
+ {
+ struct mach_header mach_header;
+ struct load_command *load_command;
+ struct symtab_command *symtab_command;
+ char *hdrbuf;
+ int cmd, symtab_seen;
+
+ lseek (desc, offset, 0);
+ if (read (desc, (char *) &mach_header, sizeof mach_header) == sizeof mach_header
+ && mach_header.magic == MH_MAGIC)
+ {
+ hdrbuf = xmalloc (mach_header.sizeofcmds);
+ if (read (desc, hdrbuf, mach_header.sizeofcmds) != mach_header.sizeofcmds)
+ {
+ error_with_file ("failure reading load commands of ", mapelt);
+ return 0;
+ }
+ load_command = (struct load_command *) hdrbuf;
+ symtab_seen = 0;
+ for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
+ {
+ if (load_command->cmd == LC_SYMTAB)
+ {
+ symtab_seen = 1;
+ symtab_command = (struct symtab_command *) load_command;
+ *syms_offset = symtab_command->symoff;
+ *syms_size = symtab_command->nsyms * sizeof (struct nlist);
+ *strs_offset = symtab_command->stroff;
+ *strs_size = symtab_command->strsize;
+ }
+ load_command = (struct load_command *) ((char *) load_command + load_command->cmdsize);
+ }
+ free (hdrbuf);
+ if (!symtab_seen)
+ *syms_offset = *syms_size = *strs_offset = *strs_size = 0;
+ return 1;
+ }
+ }
+#endif
+
+ error_with_file ("bad format (not an object file) in ", mapelt);
+ return 0;
+}
+
+/* Create the info.symdefs for a new member
+ by reading the file it is coming from. */
+
+void
+make_new_symdefs (mapelt, archive_indesc)
+ struct mapelt *mapelt;
+ int archive_indesc;
+{
+ int indesc;
+ char *name = mapelt->info.name;
+ long int syms_offset, strs_offset;
+ unsigned int syms_size, strs_size;
+ struct nlist *symbols;
+ int symcount;
+ char *strings;
+ register unsigned int i;
+ unsigned long int offset;
+
+ if (name == 0)
+ /* Deleted member. */
+ abort ();
+
+ if (mapelt->info.offset != 0)
+ {
+ indesc = archive_indesc;
+ lseek (indesc, mapelt->info.data_offset, 0);
+ offset = mapelt->info.data_offset;
+ }
+ else
+ {
+ indesc = open (mapelt->info.name, 0, 0);
+ if (indesc < 0)
+ {
+ perror_with_name (mapelt->info.name);
+ return;
+ }
+ offset = 0;
+ }
+
+ if (!read_header_info (mapelt, indesc, offset, &syms_offset, &syms_size, &strs_offset, &strs_size))
+ {
+ if (mapelt->info.offset == 0)
+ close (indesc);
+ return;
+ }
+
+ /* Number of symbol entries in the file. */
+ symcount = syms_size / sizeof (struct nlist);
+ /* Allocate temporary space for the symbol entries. */
+ symbols = (struct nlist *) alloca (syms_size);
+ /* Read in the symbols. */
+ lseek (indesc, syms_offset + offset, 0);
+ if (read (indesc, (char *) symbols, syms_size) != syms_size)
+ {
+ error_with_file ("premature end of file in symbols of ", mapelt);
+ if (mapelt->info.offset == 0)
+ (void) close (indesc);
+ return;
+ }
+
+ /* The string table size includes the size word. */
+ if (strs_size < sizeof (strs_size))
+ {
+ error_with_file ("bad string table size in ", mapelt);
+ if (mapelt->info.offset == 0)
+ (void) close (indesc);
+ return;
+ }
+ strs_size -= sizeof (strs_size);
+
+ /* Allocate permanent space for the string table. */
+ strings = (char *) xmalloc (strs_size);
+
+ /* Read in the strings. */
+ lseek (indesc, offset + strs_offset + sizeof strs_size, 0);
+ if (read (indesc, strings, strs_size) != strs_size)
+ {
+ error_with_file ("premature end of file in strings of ", mapelt);
+ if (mapelt->info.offset == 0)
+ (void) close (indesc);
+ return;
+ }
+
+ if (indesc != archive_indesc)
+ (void) close (indesc);
+
+ /* Discard the symbols we don't want to mention; compact the rest down. */
+ symcount = filter_symbols (symbols, symcount);
+
+ mapelt->info.symdefs = (struct symdef *)
+ xmalloc (symcount * sizeof (struct symdef));
+ mapelt->info.nsymdefs = symcount;
+ mapelt->info.string_size = 0;
+
+ for (i = 0; i < symcount; ++i)
+ {
+ unsigned long int stroff = symbols[i].n_un.n_strx - sizeof (strs_size);
+ char *symname = strings + stroff;
+ if (stroff > strs_size)
+ {
+ char buf[100];
+ sprintf (buf, "ridiculous string offset %lu in symbol %u of ",
+ stroff + sizeof (strs_size), i);
+ error_with_file (buf, mapelt);
+ return;
+ }
+ mapelt->info.symdefs[i].s.name = symname;
+ mapelt->info.string_size += strlen (symname) + 1;
+ }
+}
+
+/* Choose which symbol entries to mention in __.SYMDEF;
+ compact them downward to get rid of the rest.
+ Return the number of symbols left. */
+
+int
+filter_symbols (syms, symcount)
+ struct nlist *syms;
+ unsigned int symcount;
+{
+ struct nlist *from, *to;
+ struct nlist *end = syms + symcount;
+
+ for (to = from = syms; from < end; ++from)
+ if ((from->n_type & N_EXT)
+ && (from->n_type != N_EXT || from->n_value != 0))
+ *to++ = *from;
+
+ return to - syms;
+}
+
+
+/* Update the __.SYMDEF data before writing a new archive. */
+
+void
+update_symdefs (map, archive_indesc)
+ struct mapelt *map;
+ int archive_indesc;
+{
+ struct mapelt *tail;
+ int pos;
+ register unsigned int i;
+ unsigned int len;
+ struct symdef *s;
+ unsigned long int deleted_strings_size = 0;
+
+ nsymdefs = original_num_symdefs;
+ num_old_symdefs = original_num_symdefs;
+ new_strings_size = old_strings_size;
+
+ if (nsymdefs != 0)
+ {
+ /* We already had a __.SYMDEF member, so just update it. */
+
+ /* Mark as canceled any old symdefs for members being deleted. */
+
+ for (tail = map; tail != 0; tail = tail->next)
+ {
+ if (tail->info.name == 0)
+ {
+ /* Old member being deleted. Delete its symdef entries too. */
+ for (i = 0; i < original_num_symdefs; i++)
+ if (old_symdefs[i].offset == tail->info.offset)
+ {
+ old_symdefs[i].offset = 0;
+ --nsymdefs;
+ deleted_strings_size
+ += strlen (old_strings
+ + old_symdefs[i].s.stringoffset) + 1;
+ }
+ }
+ }
+
+ /* Compactify old symdefs. */
+ {
+ register unsigned int j = 0;
+ for (i = 0; i < num_old_symdefs; ++i)
+ {
+ if (j != i)
+ old_symdefs[j] = old_symdefs[i];
+ if (old_symdefs[i].offset != 0)
+ ++j;
+ }
+ num_old_symdefs -= i - j;
+ }
+
+ /* Create symdef data for any new members. */
+ for (tail = map; tail != 0; tail = tail->next)
+ {
+ if (tail->info.offset != 0
+ || tail->info.name == 0
+ || !strcmp (tail->info.name, "__.SYMDEF"))
+ continue;
+ make_new_symdefs (tail, archive_indesc);
+ nsymdefs += tail->info.nsymdefs;
+ new_strings_size += tail->info.string_size;
+ }
+ }
+ else
+ {
+ /* Create symdef data for all existing members. */
+
+ for (tail = map; tail != 0; tail = tail->next)
+ {
+ if (tail->info.name == 0
+ || !strcmp (tail->info.name, "__.SYMDEF"))
+ continue;
+ make_new_symdefs (tail, archive_indesc);
+ nsymdefs += tail->info.nsymdefs;
+ new_strings_size += tail->info.string_size;
+ }
+ }
+
+ new_strings_size -= deleted_strings_size;
+ old_strings_size -= deleted_strings_size;
+
+ /* Now we know the size of __.SYMDEF,
+ so assign the positions of all the members. */
+
+ tail = find_mapelt_noerror (map, "__.SYMDEF");
+ tail->info.size = (sizeof (nsymdefs) + (nsymdefs * sizeof (struct symdef))
+ + sizeof (new_strings_size) + new_strings_size);
+ symdef_mapelt = tail;
+
+ pos = SARMAG;
+ for (tail = map; tail != 0; tail = tail->next)
+ {
+ if (tail->info.name == 0)
+ /* Ignore deleted members. */
+ continue;
+ tail->info.new_offset = pos;
+ pos += sizeof (struct ar_hdr) + tail->info.size;
+ if (tail->info.size & 1)
+ ++pos;
+ }
+
+ /* Now update the offsets in the symdef data
+ to be the new offsets rather than the old ones. */
+
+ for (tail = map; tail != 0; tail = tail->next)
+ {
+ if (tail->info.name == 0)
+ continue;
+ if (tail->info.symdefs == 0)
+ /* Member without new symdef data.
+ Check the old symdef data; it may be included there. */
+ for (i = 0; i < num_old_symdefs; i++)
+ {
+ if (old_symdefs[i].offset == tail->info.offset)
+ old_symdefs[i].offset = tail->info.new_offset;
+ }
+ else
+ for (i = 0; i < tail->info.nsymdefs; i++)
+ tail->info.symdefs[i].offset = tail->info.new_offset;
+ }
+
+ /* Generate new, combined string table and put each string's offset into the
+ symdef that refers to it. Note that old symdefs ref their strings by
+ offsets into old_strings but new symdefs contain addresses of strings. */
+
+ new_strings = (char *) xmalloc (new_strings_size);
+ pos = 0;
+
+ /* Write the strings of the old symdefs and update the structures
+ to contain indices into the string table instead of strings. */
+ for (i = 0; i < num_old_symdefs; i++)
+ {
+ strcpy (new_strings + pos, old_strings + old_symdefs[i].s.stringoffset);
+ old_symdefs[i].s.stringoffset = pos;
+ pos += strlen (new_strings + pos) + 1;
+ }
+ if (pos < old_strings_size)
+ {
+ unsigned int d = old_strings_size - pos;
+ /* Correct the string table size. */
+ new_strings_size -= d;
+ /* Correct the size of the `__.SYMDEF' member,
+ since it contains the string table. */
+ symdef_mapelt->info.size -= d;
+ }
+ else if (pos > old_strings_size)
+ fatal ("Old archive's string size was %u too small.",
+ pos - old_strings_size);
+
+ for (tail = map; tail != 0; tail = tail->next)
+ if (tail->info.symdefs)
+ {
+ len = tail->info.nsymdefs;
+ s = tail->info.symdefs;
+
+ for (i = 0; i < len; i++)
+ {
+ strcpy (new_strings + pos, s[i].s.name);
+ s[i].s.stringoffset = pos;
+ pos += strlen (new_strings + pos) + 1;
+ }
+ }
+ if (pos != new_strings_size)
+ fatal ("internal error: inconsistency in new_strings_size", 0);
+}
+
+/* Print error message and usage message, and exit. */
+
+void
+usage (s1, s2)
+ char *s1, *s2;
+{
+ error (s1, s2);
+ fprintf (stderr, "\
+Usage: %s [d|m|p|q|r|t|x [[abi [position-name] [cilouv]] archive file...\n",
+ program_name);
+ exit (1);
+}
+
+/* Print error message and exit. */
+
+void
+fatal (s1, s2)
+ char *s1, *s2;
+{
+ error (s1, s2);
+ exit (1);
+}
+
+/* Print error message. `s1' is printf control string, the rest are args. */
+
+void
+error (s1, s2, s3, s4, s5)
+ char *s1, *s2, *s3, *s4, *s5;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, s1, s2, s3, s4, s5);
+ fprintf (stderr, "\n");
+}
+
+void
+error_with_file (string, mapelt)
+ char *string;
+ struct mapelt *mapelt;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, string);
+ if (mapelt->info.offset != 0)
+ fprintf (stderr, "%s(%s)", archive, mapelt->info.name);
+ else
+ fprintf (stderr, "%s", mapelt->info.name);
+ fprintf (stderr, "\n");
+}
+
+void
+perror_with_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "unknown error for %s";
+ error (s, name);
+}
+
+void
+pfatal_with_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "cannot open %s";
+ fatal (s, name);
+}
+
+/* Return a newly-allocated string whose contents
+ concatenate those of S1, S2, and S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ *(result + len1 + len2 + len3) = 0;
+
+ return result;
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+char *
+xmalloc (size)
+ unsigned int size;
+{
+ extern char *malloc ();
+ char *result = malloc (size);
+ if (result == 0)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+char *
+xrealloc (ptr, size)
+ char *ptr;
+ unsigned int size;
+{
+ extern char *realloc ();
+ char *result = realloc (ptr, size);
+ if (result == 0)
+ fatal ("virtual memory exhausted");
+ return result;
+}
+
+#ifndef HAVE_RENAME
+int
+rename (from, to)
+ char *from, *to;
+{
+ (void)unlink (to);
+ if (link (from, to) < 0
+ || unlink (from) < 0)
+ return -1;
+ else
+ return 0;
+}
+#endif
diff --git a/binutils-1.9/cplus-dem.c b/binutils-1.9/cplus-dem.c
new file mode 100644
index 0000000..0ea6186
--- /dev/null
+++ b/binutils-1.9/cplus-dem.c
@@ -0,0 +1,925 @@
+/* Demangler for GNU C++
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by James Clark (jjc@jclark.uucp)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This is for g++ 1.36.1 (November 6 version). It will probably
+ require changes for any other version. */
+
+/* This file exports one function
+
+ char *cplus_demangle (const char *name)
+
+ If `name' is a mangled function name produced by g++, then
+ a pointer to a malloced string giving a C++ representation
+ of the name will be returned; otherwise NULL will be returned.
+ It is the caller's responsibility to free the string which
+ is returned.
+
+ For example,
+
+ cplus_demangle ("_foo__1Ai")
+
+ returns
+
+ "A::foo(int)"
+
+ This file imports xmalloc and xrealloc, which are like malloc and
+ realloc except that they generate a fatal error if there is no
+ available memory. */
+
+/* #define nounderscore 1 /* define this is names don't start with _ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#if !defined(sequent) && !defined(NeXT)
+#include <memory.h>
+#else
+#define memcpy(s1, s2, n) strncpy(s1, s2, n)
+#define memcmp(s1, s2, n) strncmp(s1, s2, n)
+#define strchr(s, c) index(s, c)
+#endif
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifdef __STDC__
+extern char *cplus_demangle (const char *type);
+#else
+extern char *cplus_demangle ();
+#endif
+
+#ifdef __STDC__
+extern char *xmalloc (int);
+extern char *xrealloc (char *, int);
+#else
+extern char *xmalloc ();
+extern char *xrealloc ();
+#endif
+
+static char **typevec = 0;
+static int ntypes = 0;
+static int typevec_size = 0;
+
+static struct {
+ const char *in;
+ const char *out;
+} optable[] = {
+ "new", " new",
+ "delete", " delete",
+ "ne", "!=",
+ "eq", "==",
+ "ge", ">=",
+ "gt", ">",
+ "le", "<=",
+ "lt", "<",
+ "plus", "+",
+ "minus", "-",
+ "mult", "*",
+ "negate", "-",
+ "trunc_mod", "%",
+ "trunc_div", "/",
+ "truth_andif", "&&",
+ "truth_orif", "||",
+ "postincrement", "++",
+ "postdecrement", "--",
+ "bit_ior", "|",
+ "bit_xor", "^",
+ "bit_and", "&",
+ "bit_not", "~",
+ "call", "()",
+ "cond", "?:",
+ "alshift", "<<",
+ "arshift", ">>",
+ "component", "->",
+ "nop", "", /* for operator= */
+};
+
+/* Beware: these aren't '\0' terminated. */
+
+typedef struct {
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+#ifdef __STDC__
+static void string_need (string *s, int n);
+static void string_delete (string *s);
+static void string_init (string *s);
+static void string_clear (string *s);
+static int string_empty (string *s);
+static void string_append (string *p, const char *s);
+static void string_appends (string *p, string *s);
+static void string_appendn (string *p, const char *s, int n);
+static void string_prepend (string *p, const char *s);
+#if 0
+static void string_prepends (string *p, string *s);
+#endif
+static void string_prependn (string *p, const char *s, int n);
+static int get_count (const char **type, int *count);
+static int do_args (const char **type, string *decl);
+static int do_type (const char **type, string *result);
+static int do_arg (const char **type, string *result);
+static int do_args (const char **type, string *decl);
+static void munge_function_name (string *name);
+#else
+static void string_need ();
+static void string_delete ();
+static void string_init ();
+static void string_clear ();
+static int string_empty ();
+static void string_append ();
+static void string_appends ();
+static void string_appendn ();
+static void string_prepend ();
+static void string_prepends ();
+static void string_prependn ();
+static int get_count ();
+static int do_args ();
+static int do_type ();
+static int do_arg ();
+static int do_args ();
+static void munge_function_name ();
+#endif
+
+char *
+cplus_demangle (type)
+ const char *type;
+{
+ string decl;
+ int n;
+ int success = 0;
+ int constructor = 0;
+ int const_flag = 0;
+ int i;
+ const char *p;
+
+ if (type == NULL || *type == '\0')
+ return NULL;
+#ifndef nounderscore
+ if (*type++ != '_')
+ return NULL;
+#endif
+ p = type;
+ while (*p != '\0' && !(*p == '_' && p[1] == '_'))
+ p++;
+ if (*p == '\0')
+ {
+ /* destructor */
+ if (type[0] == '_' && type[1] == '$' && type[2] == '_')
+ {
+ int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
+ char *tem = (char *) xmalloc (n);
+ strcpy (tem, type + 3);
+ strcat (tem, "::~");
+ strcat (tem, type + 3);
+ strcat (tem, "()");
+ return tem;
+ }
+ /* static data member */
+ if (*type != '_' && (p = strchr (type, '$')) != '\0')
+ {
+ int n = strlen (type) + 2;
+ char *tem = (char *) xmalloc (n);
+ memcpy (tem, type, p - type);
+ strcpy (tem + (p - type), "::");
+ strcpy (tem + (p - type) + 2, p + 1);
+ return tem;
+ }
+ return NULL;
+ }
+
+ string_init (&decl);
+
+ if (p == type)
+ {
+ if (!isdigit (p[2]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ constructor = 1;
+ }
+ else
+ {
+ string_appendn (&decl, type, p - type);
+ munge_function_name (&decl);
+ }
+ p += 2;
+
+ switch (*p)
+ {
+ case 'C':
+ /* a const member function */
+ if (!isdigit (p[1]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ p += 1;
+ const_flag = 1;
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (strlen (p) < n)
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ if (constructor)
+ {
+ string_appendn (&decl, p, n);
+ string_append (&decl, "::");
+ string_appendn (&decl, p, n);
+ }
+ else
+ {
+ string_prepend (&decl, "::");
+ string_prependn (&decl, p, n);
+ }
+ p += n;
+ success = do_args (&p, &decl);
+ if (const_flag)
+ string_append (&decl, " const");
+ break;
+ case 'F':
+ p += 1;
+ success = do_args (&p, &decl);
+ break;
+ }
+
+ for (i = 0; i < ntypes; i++)
+ if (typevec[i] != NULL)
+ free (typevec[i]);
+ ntypes = 0;
+ if (typevec != NULL)
+ {
+ free ((char *)typevec);
+ typevec = NULL;
+ typevec_size = 0;
+ }
+
+ if (success)
+ {
+ string_appendn (&decl, "", 1);
+ return decl.b;
+ }
+ else
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+}
+
+static int
+get_count (type, count)
+ const char **type;
+ int *count;
+{
+ if (!isdigit (**type))
+ return 0;
+ *count = **type - '0';
+ *type += 1;
+ /* see flush_repeats in cplus-method.c */
+ if (isdigit (**type))
+ {
+ const char *p = *type;
+ int n = *count;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (*p == '_')
+ {
+ *type = p + 1;
+ *count = n;
+ }
+ }
+ return 1;
+}
+
+/* result will be initialised here; it will be freed on failure */
+
+static int
+do_type (type, result)
+ const char **type;
+ string *result;
+{
+ int n;
+ int done;
+ int non_empty;
+ int success;
+ string decl;
+ const char *remembered_type;
+
+ string_init (&decl);
+ string_init (result);
+
+ done = 0;
+ success = 1;
+ while (success && !done)
+ {
+ int member;
+ switch (**type)
+ {
+ case 'P':
+ *type += 1;
+ string_prepend (&decl, "*");
+ break;
+
+ case 'R':
+ *type += 1;
+ string_prepend (&decl, "&");
+ break;
+
+ case 'T':
+ *type += 1;
+ if (!get_count (type, &n) || n >= ntypes)
+ success = 0;
+ else
+ {
+ remembered_type = typevec[n];
+ type = &remembered_type;
+ }
+ break;
+
+ case 'F':
+ *type += 1;
+ if (!string_empty (&decl) && decl.b[0] == '*')
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ if (!do_args (type, &decl) || **type != '_')
+ success = 0;
+ else
+ *type += 1;
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ int constp = 0;
+ int volatilep = 0;
+
+ member = **type == 'M';
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_append (&decl, ")");
+ string_prepend (&decl, "::");
+ string_prependn (&decl, *type, n);
+ string_prepend (&decl, "(");
+ *type += n;
+ if (member)
+ {
+ if (**type == 'C')
+ {
+ *type += 1;
+ constp = 1;
+ }
+ if (**type == 'V')
+ {
+ *type += 1;
+ volatilep = 1;
+ }
+ if (*(*type)++ != 'F')
+ {
+ success = 0;
+ break;
+ }
+ }
+ if ((member && !do_args (type, &decl)) || **type != '_')
+ {
+ success = 0;
+ break;
+ }
+ *type += 1;
+ if (constp)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "const");
+ }
+ if (volatilep)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "volatilep");
+ }
+ break;
+ }
+
+ case 'C':
+ if ((*type)[1] == 'P')
+ {
+ *type += 1;
+ if (!string_empty (&decl))
+ string_prepend (&decl, " ");
+ string_prepend (&decl, "const");
+ break;
+ }
+
+ /* fall through */
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ done = 0;
+ non_empty = 0;
+ while (success && !done)
+ {
+ switch (**type)
+ {
+ case 'C':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "const");
+ break;
+ case 'U':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "unsigned");
+ break;
+ case 'V':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "volatile");
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ if (success)
+ switch (**type)
+ {
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "void");
+ break;
+ case 'l':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long");
+ break;
+ case 'i':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "int");
+ break;
+ case 's':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "short");
+ break;
+ case 'c':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "char");
+ break;
+ case 'r':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long double");
+ break;
+ case 'd':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "double");
+ break;
+ case 'f':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "float");
+ break;
+ case 'G':
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ if (non_empty)
+ string_append (result, " ");
+ string_appendn (result, *type, n);
+ *type += n;
+ break;
+ default:
+ success = 0;
+ break;
+ }
+
+ if (success)
+ {
+ if (!string_empty (&decl))
+ {
+ string_append (result, " ");
+ string_appends (result, &decl);
+ }
+ string_delete (&decl);
+ return 1;
+ }
+ else
+ {
+ string_delete (&decl);
+ string_delete (result);
+ return 0;
+ }
+}
+
+/* `result' will be initialised in do_type; it will be freed on failure */
+
+static int
+do_arg (type, result)
+ const char **type;
+ string *result;
+{
+ char *tem;
+ int len;
+ const char *start;
+ const char *end;
+
+ start = *type;
+ if (!do_type (type, result))
+ return 0;
+ end = *type;
+ if (ntypes >= typevec_size)
+ {
+ if (typevec_size == 0)
+ {
+ typevec_size = 3;
+ typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
+ }
+ else
+ {
+ typevec_size *= 2;
+ typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
+ }
+ }
+ len = end - start;
+ tem = (char *) xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ typevec[ntypes++] = tem;
+ return 1;
+}
+
+/* `decl' must be already initialised, usually non-empty;
+ it won't be freed on failure */
+
+static int
+do_args (type, decl)
+ const char **type;
+ string *decl;
+{
+ string arg;
+ int need_comma = 0;
+
+ string_append (decl, "(");
+
+ while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
+ {
+ if (**type == 'N')
+ {
+ int r;
+ int t;
+ *type += 1;
+ if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
+ return 0;
+ while (--r >= 0)
+ {
+ const char *tem = typevec[t];
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (&tem, &arg))
+ return 0;
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (type, &arg))
+ return 0;
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+
+ if (**type == 'v')
+ *type += 1;
+ else if (**type == 'e')
+ {
+ *type += 1;
+ if (need_comma)
+ string_append (decl, ",");
+ string_append (decl, "...");
+ }
+
+ string_append (decl, ")");
+ return 1;
+}
+
+static void
+munge_function_name (name)
+ string *name;
+{
+ if (!string_empty (name) && name->p - name->b >= 3
+ && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
+ {
+ int i;
+ /* see if it's an assignment expression */
+ if (name->p - name->b >= 10 /* op$assign_ */
+ && memcmp (name->b + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 10;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 10, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ string_append (name, "=");
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 3;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 3, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ return;
+ }
+ }
+ }
+ return;
+ }
+ else if (!string_empty (name) && name->p - name->b >= 5
+ && memcmp (name->b, "type$", 5) == 0)
+ {
+ /* type conversion operator */
+ string type;
+ const char *tem = name->b + 5;
+ if (do_type (&tem, &type))
+ {
+ string_clear (name);
+ string_append (name, "operator ");
+ string_appends (name, &type);
+ string_delete (&type);
+ return;
+ }
+ }
+}
+
+/* a mini string-handling package */
+
+static void
+string_need (s, n)
+ string *s;
+ int n;
+{
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ n = 32;
+ s->p = s->b = (char *) xmalloc (n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ int tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = (char *) xrealloc (s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+string_delete (s)
+ string *s;
+{
+ if (s->b != NULL)
+ {
+ free (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+string_init (s)
+ string *s;
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static void
+string_clear (s)
+ string *s;
+{
+ s->p = s->b;
+}
+
+static int
+string_empty (s)
+ string *s;
+{
+ return s->b == s->p;
+}
+
+static void
+string_append (p, s)
+ string *p;
+ const char *s;
+{
+ int n;
+ if (s == NULL || *s == '\0')
+ return;
+ n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_appends (p, s)
+ string *p, *s;
+{
+ int n;
+ if (s->b == s->p)
+ return;
+ n = s->p - s->b;
+ string_need (p, n);
+ memcpy (p->p, s->b, n);
+ p->p += n;
+}
+
+static void
+string_appendn (p, s, n)
+ string *p;
+ const char *s;
+ int n;
+{
+ if (n == 0)
+ return;
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_prepend (p, s)
+ string *p;
+ const char *s;
+{
+ if (s == NULL || *s == '\0')
+ return;
+ string_prependn (p, s, strlen (s));
+}
+
+#if 0
+static void
+string_prepends (p, s)
+ string *p, *s;
+{
+ if (s->b == s->p)
+ return;
+ string_prependn (p, s->b, s->p - s->b);
+}
+#endif
+
+static void
+string_prependn (p, s, n)
+ string *p;
+ const char *s;
+ int n;
+{
+ char *q;
+
+ if (n == 0)
+ return;
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ q[n] = q[0];
+ memcpy (p->b, s, n);
+ p->p += n;
+}
diff --git a/binutils-1.9/error.c b/binutils-1.9/error.c
new file mode 100644
index 0000000..9f989e2
--- /dev/null
+++ b/binutils-1.9/error.c
@@ -0,0 +1,104 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* David MacKenzie */
+
+#include <stdio.h>
+
+#ifndef VPRINTF_MISSING
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#else
+
+#ifndef DOPRNT_MISSING
+#define va_alist args
+#define va_dcl int args;
+#else
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+void exit ();
+
+static char *
+strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum < sys_nerr)
+ return sys_errlist[errnum];
+ return "Unknown system error";
+}
+#endif
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+void
+#if !defined (VPRINTF_MISSING) && defined (__STDC__)
+error (int status, int errnum, char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+ extern char *program_name;
+#ifndef VPRINTF_MISSING
+ va_list args;
+#endif
+
+ fprintf (stderr, "%s: ", program_name);
+#ifndef VPRINTF_MISSING
+#ifdef __STDC__
+ va_start (args, message);
+#else
+ va_start (args);
+#endif
+ vfprintf (stderr, message, args);
+ va_end (args);
+#else
+#ifndef DOPRNT_MISSING
+ _doprnt (message, &args, stderr);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+#endif
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
diff --git a/binutils-1.9/getopt.c b/binutils-1.9/getopt.c
new file mode 100644
index 0000000..c3c9765
--- /dev/null
+++ b/binutils-1.9/getopt.c
@@ -0,0 +1,596 @@
+/* Getopt for GNU.
+ Copyright (C) 1987, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef __STDC__
+#define CONST const
+#else
+#define CONST
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of `argv' so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include <stdio.h>
+
+/* If compiled with GNU C, use the built-in alloca */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#ifdef sparc
+#include <alloca.h>
+#else
+char *alloca ();
+#endif /* sparc */
+#endif /* not __GNUC__ */
+
+#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
+#include <stdlib.h>
+#include <string.h>
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#define index strchr
+#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+
+#ifdef USG
+#include <string.h>
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#define index strchr
+#else /* USG */
+#ifdef VMS
+#include <string.h>
+#else
+#include <strings.h>
+#endif /* VMS */
+/* Declaring bcopy causes errors on systems whose declarations are different.
+ If the declaration is omitted, everything works fine. rms. */
+#endif /* USG */
+
+char *getenv ();
+char *malloc ();
+#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ _POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable _POSIX_OPTION_ORDER, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Describe the long-named options requested by the application.
+ _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+ The field `has_arg' is 1 if the option takes an argument,
+ 2 if it takes an optional argument. */
+
+struct option
+{
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+CONST struct option *_getopt_long_options;
+
+int _getopt_long_only = 0;
+
+/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
+ Only valid when a long-named option was found. */
+
+int option_index;
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+ char **temp = (char **) alloca (nonopts_size);
+
+ /* Interchange the two blocks of data in ARGV. */
+
+ bcopy (&argv[first_nonopt], temp, nonopts_size);
+ bcopy (&argv[last_nonopt], &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `+' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ otherwise. */
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char **argv;
+ CONST char *optstring;
+{
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = 0;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("_POSIX_OPTION_ORDER") != 0)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == 0 || *nextchar == 0)
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange (argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-'
+ || argv[optind][1] == 0)
+ && (_getopt_long_options == 0
+ || argv[optind][0] != '+'
+ || argv[optind][1] == 0))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange (argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == 0)
+ && (_getopt_long_options == 0
+ || argv[optind][0] != '+' || argv[optind][1] == 0))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = argv[optind] + 1;
+ }
+
+ if (_getopt_long_options != 0
+ && (argv[optind][0] == '+'
+ || (_getopt_long_only && argv[optind][0] == '-'))
+ )
+ {
+ CONST struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ CONST struct option *pfound = 0;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = _getopt_long_options, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == 0)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != 0)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ if (pfound->has_arg > 0)
+ optarg = s + 1;
+ else
+ {
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is getopt_long_only,
+ and the option starts with '-' and is a valid short
+ option, then interpret it as a short option. Otherwise it's
+ an error. */
+ if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
+ index (optstring, *nextchar) == 0)
+ {
+ if (opterr != 0)
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == 0)
+ optind++;
+
+ if (temp == 0 || c == ':')
+ {
+ if (opterr != 0)
+ {
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n",
+ argv[0], c);
+ }
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != 0)
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = 0;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != 0)
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr != 0)
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = 0;
+ }
+ }
+ return c;
+ }
+}
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/binutils-1.9/getopt.h b/binutils-1.9/getopt.h
new file mode 100644
index 0000000..6583ab9
--- /dev/null
+++ b/binutils-1.9/getopt.h
@@ -0,0 +1,102 @@
+/* declarations for getopt
+ Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Describe the long-named options requested by the application.
+ _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ The field `has_arg' is:
+ 0 if the option does not take an argument,
+ 1 if the option requires an argument,
+ 2 if the option takes an optional argument.
+
+ If the field `flag' is nonzero, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+#ifdef __STDC__
+extern const struct option *_getopt_long_options;
+#else
+extern struct option *_getopt_long_options;
+#endif
+
+/* If nonzero, '-' can introduce long-named options.
+ Set by getopt_long_only. */
+
+extern int _getopt_long_only;
+
+/* The index in GETOPT_LONG_OPTIONS of the long-named option found.
+ Only valid when a long-named option has been found by the most
+ recent call to `getopt'. */
+
+extern int option_index;
+
+#ifdef __STDC__
+int getopt (int argc, char **argv, const char *shortopts);
+int getopt_long (int argc, char **argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+int getopt_long_only (int argc, char **argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+void envopt(int *pargc, char ***pargv, char *optstr);
+#else
+int getopt ();
+int getopt_long ();
+int getopt_long_only ();
+void envopt();
+#endif
diff --git a/binutils-1.9/getopt1.c b/binutils-1.9/getopt1.c
new file mode 100644
index 0000000..d0d783d
--- /dev/null
+++ b/binutils-1.9/getopt1.c
@@ -0,0 +1,160 @@
+/* Getopt for GNU.
+ Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "getopt.h"
+
+#ifdef __STDC__
+#define CONST const
+#else
+#define CONST
+#endif
+
+#if !defined (NULL)
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char **argv;
+ CONST char *options;
+ CONST struct option *long_options;
+ int *opt_index;
+{
+ int val;
+
+ _getopt_long_options = long_options;
+ val = getopt (argc, argv, options);
+ if (val == 0 && opt_index != NULL)
+ *opt_index = option_index;
+ return val;
+}
+
+/* Like getopt_long, but '-' as well as '+' can indicate a long option.
+ If an option that starts with '-' doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char **argv;
+ CONST char *options;
+ CONST struct option *long_options;
+ int *opt_index;
+{
+ int val;
+
+ _getopt_long_options = long_options;
+ _getopt_long_only = 1;
+ val = getopt (argc, argv, options);
+ if (val == 0 && opt_index != NULL)
+ *opt_index = option_index;
+ return val;
+}
+
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ char *name = '\0';
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", (long_options[option_index]).name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/binutils-1.9/gmalloc.c b/binutils-1.9/gmalloc.c
new file mode 100644
index 0000000..0468551
--- /dev/null
+++ b/binutils-1.9/gmalloc.c
@@ -0,0 +1,1116 @@
+
+/* gmalloc.c - THIS FILE IS AUTOMAGICALLY GENERATED SO DON'T EDIT IT. */
+
+/* Single-file skeleton for GNU malloc.
+ Copyright 1989 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#define __ONEFILE
+
+/* DO NOT DELETE THIS LINE -- ansidecl.h INSERTED HERE. */
+/* Copyright (C) 1989 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU C Library; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ANSI and traditional C compatibility macros
+
+ ANSI C is assumed if __STDC__ is #defined.
+
+ Macros
+ PTR - Generic pointer type
+ LONG_DOUBLE - `long double' type
+ CONST - `const' keyword
+ VOLATILE - `volatile' keyword
+ SIGNED - `signed' keyword
+ PTRCONST - Generic const pointer (void *const)
+
+ EXFUN(name, prototype) - declare external function NAME
+ with prototype PROTOTYPE
+ DEFUN(name, arglist, args) - define function NAME with
+ args ARGLIST of types in ARGS
+ DEFUN_VOID(name) - define function NAME with no args
+ AND - argument separator for ARGS
+ NOARGS - null arglist
+ DOTS - `...' in args
+
+ For example:
+ extern int EXFUN(printf, (CONST char *format DOTS));
+ int DEFUN(fprintf, (stream, format),
+ FILE *stream AND CONST char *format DOTS) { ... }
+ void DEFUN_VOID(abort) { ... }
+*/
+
+#ifndef _ANSIDECL_H
+
+#define _ANSIDECL_H 1
+
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+
+#ifdef __STDC__
+
+#define PTR void *
+#define PTRCONST void *CONST
+#define LONG_DOUBLE long double
+
+#define AND ,
+#define NOARGS void
+#define CONST const
+#define VOLATILE volatile
+#define SIGNED signed
+#define DOTS , ...
+
+#define EXFUN(name, proto) name proto
+#define DEFUN(name, arglist, args) name(args)
+#define DEFUN_VOID(name) name(NOARGS)
+
+#else /* Not ANSI C. */
+
+#define PTR char *
+#define PTRCONST PTR
+#define LONG_DOUBLE double
+
+#define AND ;
+#define NOARGS
+#define CONST
+#define VOLATILE
+#define SIGNED
+#define DOTS
+
+#define EXFUN(name, proto) name()
+#define DEFUN(name, arglist, args) name arglist args;
+#define DEFUN_VOID(name) name()
+
+#endif /* ANSI C. */
+
+
+#endif /* ansidecl.h */
+
+#ifdef __STDC__
+#include <limits.h>
+#else
+/* DO NOT DELETE THIS LINE -- limits.h INSERTED HERE. */
+/* Number of bits in a `char'. */
+#define CHAR_BIT 8
+
+/* No multibyte characters supported yet. */
+#define MB_LEN_MAX 1
+
+/* Minimum and maximum values a `signed char' can hold. */
+#define SCHAR_MIN -128
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0). */
+#define UCHAR_MAX 255U
+
+/* Minimum and maximum values a `char' can hold. */
+#ifdef __CHAR_UNSIGNED__
+#define CHAR_MIN 0
+#define CHAR_MAX 255U
+#else
+#define CHAR_MIN -128
+#define CHAR_MAX 127
+#endif
+
+/* Minimum and maximum values a `signed short int' can hold. */
+#define SHRT_MIN -32768
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */
+#define USHRT_MAX 65535U
+
+/* Minimum and maximum values a `signed int' can hold. */
+#define INT_MIN -2147483648
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0). */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long int' can hold.
+ (Same as `int'). */
+#define LONG_MIN (-LONG_MAX-1)
+#define LONG_MAX 2147483647
+
+/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */
+#define ULONG_MAX 4294967295U
+#endif
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+/* DO NOT DELETE THIS LINE -- stddef.h INSERTED HERE. */
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+/* Signed type of difference of two pointers. */
+
+typedef long ptrdiff_t;
+
+/* Unsigned type of `sizeof' something. */
+
+#ifndef _SIZE_T /* in case <sys/types.h> has defined it. */
+#define _SIZE_T
+typedef unsigned long size_t;
+#endif /* _SIZE_T */
+
+/* A null pointer constant. */
+
+#undef NULL /* in case <stdio.h> has defined it. */
+#define NULL 0
+
+/* Offset of member MEMBER in a struct of type TYPE. */
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* _STDDEF_H */
+#endif
+
+/* DO NOT DELETE THIS LINE -- stdlib.h INSERTED HERE. */
+/* Fake stdlib.h supplying the stuff needed by malloc. */
+
+#ifndef __ONEFILE
+#include <stddef.h>
+#endif
+
+extern void EXFUN(abort, (void));
+extern void EXFUN(free, (PTR));
+extern PTR EXFUN(malloc, (size_t));
+extern PTR EXFUN(realloc, (PTR, size_t));
+
+/* DO NOT DELETE THIS LINE -- string.h INSERTED HERE. */
+/* Fake string.h supplying stuff used by malloc. */
+#ifndef __ONEFILE
+#include <stddef.h>
+#endif
+
+extern PTR EXFUN(memcpy, (PTR, PTR, size_t));
+extern PTR EXFUN(memset, (PTR, int, size_t));
+#define memmove memcpy
+
+#define _MALLOC_INTERNAL
+/* DO NOT DELETE THIS LINE -- malloc.h INSERTED HERE. */
+/* Declarations for `malloc' and friends.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H 1
+
+#ifndef __ONEFILE
+#define __need_NULL
+#define __need_size_t
+#define __need_ptrdiff_t
+#include <stddef.h>
+#endif
+
+#ifdef _MALLOC_INTERNAL
+
+#ifndef __ONEFILE
+#include <limits.h>
+#endif
+
+/* The allocator divides the heap into blocks of fixed size; large
+ requests receive one or more whole blocks, and small requests
+ receive a fragment of a block. Fragment sizes are powers of two,
+ and all fragments of a block are the same size. When all the
+ fragments in a block have been freed, the block itself is freed. */
+#define INT_BIT (CHAR_BIT * sizeof(int))
+#define BLOCKLOG (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE (1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+ (not an absolute limit). */
+#define HEAP (INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+ memory before they will be returned to the system. */
+#define FINAL_FREE_BLOCKS 8
+
+/* Where to start searching the free list when looking for new memory.
+ The two possible values are 0 and _heapindex. Starting at 0 seems
+ to reduce total memory usage, while starting at _heapindex seems to
+ run faster. */
+#define MALLOC_SEARCH_START _heapindex
+
+/* Data structure giving per-block information. */
+typedef union
+ {
+ /* Heap information for a busy block. */
+ struct
+ {
+ /* Zero for a large block, or positive giving the
+ logarithm to the base two of the fragment size. */
+ int type;
+ union
+ {
+ struct
+ {
+ size_t nfree; /* Free fragments in a fragmented block. */
+ size_t first; /* First free fragment of the block. */
+ } frag;
+ /* Size (in blocks) of a large cluster. */
+ size_t size;
+ } info;
+ } busy;
+ /* Heap information for a free block (that may be the first of
+ a free cluster). */
+ struct
+ {
+ size_t size; /* Size (in blocks) of a free cluster. */
+ size_t next; /* Index of next free cluster. */
+ size_t prev; /* Index of previous free cluster. */
+ } free;
+ } malloc_info;
+
+/* Pointer to first block of the heap. */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information. */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa. */
+#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table. */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices. */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments. */
+struct list
+ {
+ struct list *next;
+ struct list *prev;
+ };
+
+/* Free list headers for each fragment size. */
+extern struct list _fraghead[];
+
+/* Instrumentation. */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of free() used in morecore(). */
+extern void EXFUN(__free, (PTR __ptr));
+
+#endif /* _MALLOC_INTERNAL. */
+
+/* Underlying allocation function; successive calls should
+ return contiguous pieces of memory. */
+extern PTR EXFUN((*__morecore), (ptrdiff_t __size));
+
+/* Default value of previous. */
+extern PTR EXFUN(__default_morecore, (ptrdiff_t __size));
+
+/* Flag whether malloc has been called. */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions. */
+extern void EXFUN((*__free_hook), (PTR __ptr));
+extern PTR EXFUN((*__malloc_hook), (size_t __size));
+extern PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size));
+
+/* Activate a standard collection of debugging hooks. */
+extern void EXFUN(mcheck, (void EXFUN((*func), (void))));
+
+/* Statistics available to the user. */
+struct mstats
+ {
+ size_t bytes_total; /* Total size of the heap. */
+ size_t chunks_used; /* Chunks allocated by the user. */
+ size_t bytes_used; /* Byte total of user-allocated chunks. */
+ size_t chunks_free; /* Chunks in the free list. */
+ size_t bytes_free; /* Byte total of chunks in the free list. */
+ };
+
+/* Pick up the current statistics. */
+extern struct mstats EXFUN(mstats, (NOARGS));
+
+#endif /* malloc.h */
+
+/* DO NOT DELETE THIS LINE -- free.c INSERTED HERE. */
+/* Free a block of memory allocated by `malloc'.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+/* Debugging hook for free. */
+void EXFUN((*__free_hook), (PTR __ptr));
+
+/* Return memory to the heap. Like free() but don't call a __free_hook
+ if there is one. */
+void
+DEFUN(__free, (ptr), PTR ptr)
+{
+ int type;
+ size_t block, blocks;
+ register size_t i;
+ struct list *prev, *next;
+
+ block = BLOCK(ptr);
+
+ type = _heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Get as many statistics as early as we can. */
+ --_chunks_used;
+ _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+ _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+ /* Find the free cluster previous to this one in the free list.
+ Start searching at the last block referenced; this may benefit
+ programs with locality of allocation. */
+ i = _heapindex;
+ if (i > block)
+ while (i > block)
+ i = _heapinfo[i].free.prev;
+ else
+ {
+ do
+ i = _heapinfo[i].free.next;
+ while (i > 0 && i < block);
+ i = _heapinfo[i].free.prev;
+ }
+
+ /* Determine how to link this block into the free list. */
+ if (block == i + _heapinfo[i].free.size)
+ {
+ /* Coalesce this block with its predecessor. */
+ _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+ block = i;
+ }
+ else
+ {
+ /* Really link this block back into the free list. */
+ _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+ _heapinfo[block].free.next = _heapinfo[i].free.next;
+ _heapinfo[block].free.prev = i;
+ _heapinfo[i].free.next = block;
+ _heapinfo[_heapinfo[block].free.next].free.prev = block;
+ ++_chunks_free;
+ }
+
+ /* Now that the block is linked in, see if we can coalesce it
+ with its successor (by deleting its successor from the list
+ and adding in its size). */
+ if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+ {
+ _heapinfo[block].free.size
+ += _heapinfo[_heapinfo[block].free.next].free.size;
+ _heapinfo[block].free.next
+ = _heapinfo[_heapinfo[block].free.next].free.next;
+ _heapinfo[_heapinfo[block].free.next].free.prev = block;
+ --_chunks_free;
+ }
+
+ /* Now see if we can return stuff to the system. */
+ blocks = _heapinfo[block].free.size;
+ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+ && (*__morecore)(0) == ADDRESS(block + blocks))
+ {
+ register size_t bytes = blocks * BLOCKSIZE;
+ _heaplimit -= blocks;
+ (*__morecore)(- bytes);
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapinfo[block].free.next;
+ _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapinfo[block].free.prev;
+ block = _heapinfo[block].free.prev;
+ --_chunks_free;
+ _bytes_free -= bytes;
+ }
+
+ /* Set the next search to begin at this block. */
+ _heapindex = block;
+ break;
+
+ default:
+ /* Do some of the statistics. */
+ --_chunks_used;
+ _bytes_used -= 1 << type;
+ ++_chunks_free;
+ _bytes_free += 1 << type;
+
+ /* Get the address of the first free fragment in this block. */
+ prev = (struct list *) ((char *) ADDRESS(block) +
+ (_heapinfo[block].busy.info.frag.first << type));
+
+ if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+ {
+ /* If all fragments of this block are free, remove them
+ from the fragment list and free the whole block. */
+ next = prev;
+ for (i = 1; i < BLOCKSIZE >> type; ++i)
+ next = next->next;
+ prev->prev->next = next;
+ if (next != NULL)
+ next->prev = prev->prev;
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = 1;
+
+ /* Keep the statistics accurate. */
+ ++_chunks_used;
+ _bytes_used += BLOCKSIZE;
+ _chunks_free -= BLOCKSIZE >> type;
+ _bytes_free -= BLOCKSIZE;
+
+ free(ADDRESS(block));
+ }
+ else if (_heapinfo[block].busy.info.frag.nfree != 0)
+ {
+ /* If some fragments of this block are free, link this
+ fragment into the fragment list after the first free
+ fragment of this block. */
+ next = (struct list *) ptr;
+ next->next = prev->next;
+ next->prev = prev;
+ prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ ++_heapinfo[block].busy.info.frag.nfree;
+ }
+ else
+ {
+ /* No fragments of this block are free, so link this
+ fragment into the fragment list and announce that
+ it is the first free fragment of this block. */
+ prev = (struct list *) ptr;
+ _heapinfo[block].busy.info.frag.nfree = 1;
+ _heapinfo[block].busy.info.frag.first = (unsigned int)
+ (((char *) ptr - (char *) NULL) % BLOCKSIZE >> type);
+ prev->next = _fraghead[type].next;
+ prev->prev = &_fraghead[type];
+ prev->prev->next = prev;
+ if (prev->next != NULL)
+ prev->next->prev = prev;
+ }
+ break;
+ }
+}
+
+/* Return memory to the heap. */
+void
+DEFUN(free, (ptr), PTR ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (__free_hook != NULL)
+ (*__free_hook)(ptr);
+ else
+ __free (ptr);
+}
+
+/* DO NOT DELETE THIS LINE -- malloc.c INSERTED HERE. */
+/* Memory allocator `malloc'.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+/* How to really get more memory. */
+PTR EXFUN((*__morecore), (ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'. */
+PTR EXFUN((*__malloc_hook), (size_t __size));
+
+/* Pointer to the base of the first block. */
+char *_heapbase;
+
+/* Block information table. Allocated with align/__free (not malloc/free). */
+malloc_info *_heapinfo;
+
+/* Number of info entries. */
+static size_t heapsize;
+
+/* Search index in the info table. */
+size_t _heapindex;
+
+/* Limit of valid info table indices. */
+size_t _heaplimit;
+
+/* Free lists for each fragment size. */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation. */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced? */
+int __malloc_initialized;
+
+/* Aligned allocation. */
+static PTR
+DEFUN(align, (size), size_t size)
+{
+ PTR result;
+ unsigned int adj;
+
+ result = (*__morecore)(size);
+ adj = (unsigned int) ((char *) result - (char *) NULL) % BLOCKSIZE;
+ if (adj != 0)
+ {
+ adj = BLOCKSIZE - adj;
+ (void) (*__morecore)(adj);
+ result = (char *) result + adj;
+ }
+ return result;
+}
+
+/* Set everything up and remember that we have. */
+static int
+DEFUN_VOID(initialize)
+{
+ heapsize = HEAP / BLOCKSIZE;
+ _heapinfo = (malloc_info *) align(heapsize * sizeof(malloc_info));
+ if (_heapinfo == NULL)
+ return 0;
+ memset(_heapinfo, 0, heapsize * sizeof(malloc_info));
+ _heapinfo[0].free.size = 0;
+ _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+ _heapindex = 0;
+ _heapbase = (char *) _heapinfo;
+ __malloc_initialized = 1;
+ return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+ growing the heap info table as necessary. */
+static PTR
+DEFUN(morecore, (size), size_t size)
+{
+ PTR result;
+ malloc_info *newinfo, *oldinfo;
+ size_t newsize;
+
+ result = align(size);
+ if (result == NULL)
+ return NULL;
+
+ /* Check if we need to grow the info table. */
+ if (BLOCK((char *) result + size) > heapsize)
+ {
+ newsize = heapsize;
+ while (BLOCK((char *) result + size) > newsize)
+ newsize *= 2;
+ newinfo = (malloc_info *) align(newsize * sizeof(malloc_info));
+ if (newinfo == NULL)
+ {
+ (*__morecore)(- size);
+ return NULL;
+ }
+ memset(newinfo, 0, newsize * sizeof(malloc_info));
+ memcpy(newinfo, _heapinfo, heapsize * sizeof(malloc_info));
+ oldinfo = _heapinfo;
+ newinfo[BLOCK(oldinfo)].busy.type = 0;
+ newinfo[BLOCK(oldinfo)].busy.info.size
+ = BLOCKIFY(heapsize * sizeof(malloc_info));
+ _heapinfo = newinfo;
+ __free(oldinfo);
+ heapsize = newsize;
+ }
+
+ _heaplimit = BLOCK((char *) result + size);
+ return result;
+}
+
+/* Allocate memory from the heap. */
+PTR
+DEFUN(malloc, (size), size_t size)
+{
+ PTR result;
+ size_t block, blocks, lastblocks, start;
+ register size_t i;
+ struct list *next;
+
+ if (size == 0)
+ return NULL;
+
+ if (__malloc_hook != NULL)
+ return (*__malloc_hook)(size);
+
+ if (!__malloc_initialized)
+ if (!initialize())
+ return NULL;
+
+ if (size < sizeof(struct list))
+ size = sizeof(struct list);
+
+ /* Determine the allocation policy based on the request size. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ /* Small allocation to receive a fragment of a block.
+ Determine the logarithm to base two of the fragment size. */
+ register size_t log = 1;
+ --size;
+ while ((size /= 2) != 0)
+ ++log;
+
+ /* Look in the fragment lists for a
+ free fragment of the desired size. */
+ next = _fraghead[log].next;
+ if (next != NULL)
+ {
+ /* There are free fragments of this size.
+ Pop a fragment out of the fragment list and return it.
+ Update the block's nfree and first counters. */
+ result = (PTR) next;
+ next->prev->next = next->next;
+ if (next->next != NULL)
+ next->next->prev = next->prev;
+ block = BLOCK(result);
+ if (--_heapinfo[block].busy.info.frag.nfree != 0)
+ _heapinfo[block].busy.info.frag.first = (unsigned int)
+ (((char *) next->next - (char *) NULL) % BLOCKSIZE) >> log;
+
+ /* Update the statistics. */
+ ++_chunks_used;
+ _bytes_used += 1 << log;
+ --_chunks_free;
+ _bytes_free -= 1 << log;
+ }
+ else
+ {
+ /* No free fragments of the desired size, so get a new block
+ and break it into fragments, returning the first. */
+ result = malloc(BLOCKSIZE);
+ if (result == NULL)
+ return NULL;
+
+ /* Link all fragments but the first into the free list. */
+ for (i = 1; i < BLOCKSIZE >> log; ++i)
+ {
+ next = (struct list *) ((char *) result + (i << log));
+ next->next = _fraghead[log].next;
+ next->prev = &_fraghead[log];
+ next->prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ }
+
+ /* Initialize the nfree and first counters for this block. */
+ block = BLOCK(result);
+ _heapinfo[block].busy.type = log;
+ _heapinfo[block].busy.info.frag.nfree = i - 1;
+ _heapinfo[block].busy.info.frag.first = i - 1;
+
+ _chunks_free += (BLOCKSIZE >> log) - 1;
+ _bytes_free += BLOCKSIZE - (1 << log);
+ }
+ }
+ else
+ {
+ /* Large allocation to receive one or more blocks.
+ Search the free list in a circle starting at the last place visited.
+ If we loop completely around without finding a large enough
+ space we will have to get more memory from the system. */
+ blocks = BLOCKIFY(size);
+ start = block = MALLOC_SEARCH_START;
+ while (_heapinfo[block].free.size < blocks)
+ {
+ block = _heapinfo[block].free.next;
+ if (block == start)
+ {
+ /* Need to get more from the system. Check to see if
+ the new core will be contiguous with the final free
+ block; if so we don't need to get as much. */
+ block = _heapinfo[0].free.prev;
+ lastblocks = _heapinfo[block].free.size;
+ if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+ (*__morecore)(0) == ADDRESS(block + lastblocks) &&
+ (morecore((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+ {
+ _heapinfo[block].free.size = blocks;
+ _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+ continue;
+ }
+ result = morecore(blocks * BLOCKSIZE);
+ if (result == NULL)
+ return NULL;
+ block = BLOCK(result);
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = blocks;
+ ++_chunks_used;
+ _bytes_used += blocks * BLOCKSIZE;
+ return result;
+ }
+ }
+
+ /* At this point we have found a suitable free list entry.
+ Figure out how to remove what we need from the list. */
+ result = ADDRESS(block);
+ if (_heapinfo[block].free.size > blocks)
+ {
+ /* The block we found has a bit left over,
+ so relink the tail end back into the free list. */
+ _heapinfo[block + blocks].free.size
+ = _heapinfo[block].free.size - blocks;
+ _heapinfo[block + blocks].free.next
+ = _heapinfo[block].free.next;
+ _heapinfo[block + blocks].free.prev
+ = _heapinfo[block].free.prev;
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapindex = block + blocks;
+ }
+ else
+ {
+ /* The block exactly matches our requirements,
+ so just remove it from the list. */
+ _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapinfo[block].free.prev;
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapindex = _heapinfo[block].free.next;
+ --_chunks_free;
+ }
+
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = blocks;
+ ++_chunks_used;
+ _bytes_used += blocks * BLOCKSIZE;
+ _bytes_free -= blocks * BLOCKSIZE;
+ }
+
+ return result;
+}
+
+/* DO NOT DELETE THIS LINE -- realloc.c INSERTED HERE. */
+/* Change the size of a block allocated by `malloc'.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc. */
+PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+ to the (possibly moved) region. This is optimized for speed;
+ some benchmarks seem to indicate that greater compactness is
+ achieved by unconditionally allocating and copying to a
+ new region. This module has incestuous knowledge of the
+ internals of both free and malloc. */
+PTR
+DEFUN(realloc, (ptr, size), PTR ptr AND size_t size)
+{
+ PTR result;
+ int type;
+ size_t block, blocks, oldlimit;
+
+ if (size == 0)
+ {
+ free(ptr);
+ return NULL;
+ }
+ else if (ptr == NULL)
+ return malloc(size);
+
+ if (__realloc_hook != NULL)
+ return (*__realloc_hook)(ptr, size);
+
+ block = BLOCK(ptr);
+
+ type = _heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Maybe reallocate a large block to a small fragment. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ result = malloc(size);
+ if (result != NULL)
+ {
+ memcpy(result, ptr, size);
+ free(ptr);
+ return result;
+ }
+ }
+
+ /* The new size is a large allocation as well;
+ see if we can hold it in place. */
+ blocks = BLOCKIFY(size);
+ if (blocks < _heapinfo[block].busy.info.size)
+ {
+ /* The new size is smaller; return
+ excess memory to the free list. */
+ _heapinfo[block + blocks].busy.type = 0;
+ _heapinfo[block + blocks].busy.info.size
+ = _heapinfo[block].busy.info.size - blocks;
+ _heapinfo[block].busy.info.size = blocks;
+ free(ADDRESS(block + blocks));
+ result = ptr;
+ }
+ else if (blocks == _heapinfo[block].busy.info.size)
+ /* No size change necessary. */
+ result = ptr;
+ else
+ {
+ /* Won't fit, so allocate a new region that will.
+ Free the old region first in case there is sufficient
+ adjacent free space to grow without moving. */
+ blocks = _heapinfo[block].busy.info.size;
+ /* Prevent free from actually returning memory to the system. */
+ oldlimit = _heaplimit;
+ _heaplimit = 0;
+ free(ptr);
+ _heaplimit = oldlimit;
+ result = malloc(size);
+ if (result == NULL)
+ {
+ (void) malloc(blocks * BLOCKSIZE);
+ return NULL;
+ }
+ if (ptr != result)
+ memmove(result, ptr, blocks * BLOCKSIZE);
+ }
+ break;
+
+ default:
+ /* Old size is a fragment; type is logarithm
+ to base two of the fragment size. */
+ if (size > 1 << (type - 1) && size <= 1 << type)
+ /* The new size is the same kind of fragment. */
+ result = ptr;
+ else
+ {
+ /* The new size is different; allocate a new space,
+ and copy the lesser of the new size and the old. */
+ result = malloc(size);
+ if (result == NULL)
+ return NULL;
+ memcpy(result, ptr, MIN(size, 1 << type));
+ free(ptr);
+ }
+ break;
+ }
+
+ return result;
+}
+
+/* DO NOT DELETE THIS LINE -- unix.c INSERTED HERE. */
+/* unix.c - get more memory with a UNIX system call.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+extern PTR EXFUN(sbrk, (ptrdiff_t size));
+
+PTR
+DEFUN(__default_morecore, (size), ptrdiff_t size)
+{
+ PTR result;
+
+ result = sbrk(size);
+ if (result == (PTR) -1)
+ return NULL;
+ return result;
+}
+
+#define __getpagesize getpagesize
+/* DO NOT DELETE THIS LINE -- valloc.c INSERTED HERE. */
+/* Allocate memory on a page boundary.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stdlib.h>
+#endif /* __ONEFILE */
+
+extern size_t EXFUN(__getpagesize, (NOARGS));
+
+static size_t pagesize;
+
+PTR
+DEFUN(valloc, (size), size_t size)
+{
+ PTR result;
+ unsigned int adj;
+
+ if (pagesize == 0)
+ pagesize = __getpagesize();
+
+ result = malloc(size + pagesize);
+ if (result == NULL)
+ return NULL;
+ adj = (unsigned int) ((char *) result - (char *) NULL) % pagesize;
+ if (adj != 0)
+ result = (char *) result + pagesize - adj;
+ return result;
+}
diff --git a/binutils-1.9/gmon.h b/binutils-1.9/gmon.h
new file mode 100644
index 0000000..02f12fb
--- /dev/null
+++ b/binutils-1.9/gmon.h
@@ -0,0 +1,48 @@
+/* Format of gmon.out file. */
+
+/* This header appears at the beginning of the gmon.out file.
+ LOW and HIGH are low and high water marks for the program counter
+ during the creation of the gmon.out file.
+ LOW is also the offset where the histogram table starts in the
+ text (code) segment.
+ NBYTES is the number of bytes in this header plus the histogram itself,
+ which immediately follows the header in the file.
+
+ Therefore, the number of histogram entries is
+ (NBYTES - sizeof (struct gm_header)) / (sizeof (CHUNK)).
+
+ Each entry applies to a range of PC values.
+ The first entry applies to PC values starting at LOW.
+ The last entry applies to PC values ending at HIGH.
+ Therefore, the span of each entry's range is
+ (HIGH - LOW) / number-of-entries
+ Usually this value is 4.
+*/
+
+struct gm_header {
+ unsigned long low;
+ unsigned long high;
+ long nbytes;
+};
+
+/* Data type of an entry in the PC histogram. */
+#define CHUNK short
+
+/* After the histogram cone the function call count entries.
+ They fill all the rest of the file.
+ Each count entry records the number of calls to one function
+ from one pc value.
+
+ FROM describes the caller pc, as an offset into the text segment.
+ TO is the address of the called function.
+ NCALLS is the number of calls counted from FROM to TO.
+
+ Note that if a function A is called from several places in B,
+ there are separate call count entries for each call, with different FROM.
+ All of them together count the number of calls from B to A. */
+
+struct gm_call {
+ unsigned long from;
+ unsigned long to;
+ unsigned long ncalls;
+};
diff --git a/binutils-1.9/gprof.c b/binutils-1.9/gprof.c
new file mode 100644
index 0000000..e3a7a73
--- /dev/null
+++ b/binutils-1.9/gprof.c
@@ -0,0 +1,2737 @@
+/* `gprof', analyze gmon.out and print a profile.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* GNU gprof was written mainly by Jay Fenlason. */
+
+#include <assert.h>
+#include "getopt.h"
+#ifdef __STDC__
+#include "stddef.h"
+#include "stdarg.h"
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#endif
+#else /* no __STDC__ */
+#ifdef sparc
+#include "alloca.h"
+#endif /* sparc */
+#include "varargs.h"
+#define const
+typedef unsigned int size_t;
+#endif /* no __STDC__ */
+
+#undef NULL
+#include <stdio.h>
+#undef NULL
+#define NULL 0
+
+#if !defined(A_OUT) && !defined(MACH_O)
+#define A_OUT
+#endif
+
+#ifdef A_OUT
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+#endif
+
+#ifdef MACH_O
+#ifndef A_OUT
+#include <nlist.h>
+#ifndef N_TEXT
+#define N_TEXT 0x04
+#endif
+#endif
+#include <sys/loader.h>
+#endif
+
+#include "gmon.h"
+/* #include <nlist.h> */
+
+#ifdef USG
+#define index strchr
+#define bzero(s, n) (memset((s), 0, (n)))
+#define bcopy(from, to, n) (memcpy ((to), (from), (n)))
+#endif
+
+/* Special macros designed to remove some __STDC__ ugliness from my source
+ files. Instead, I use these (which may be just as ugly). Instead of using
+extern foo();
+ or
+extern foo(int,double);
+ I use
+extern foo FUN2(int, double);
+ which is expanded to the right thing depending on whether you're using an
+ ANSI cc or not.
+
+ Also, instead of saying
+type
+foo(x,y)
+int x;
+double y;
+ or
+type
+foo(int x, double y)
+ I use
+type
+foo FUN2(int, x, double, y)
+Which is also expanded into the right thing. . .
+ */
+
+#ifdef __STDC__
+#define var_start(x,y) va_start(x,y)
+
+/* These macros expand into ANSI prototypes */
+#define FUN0() (void)
+#define EXT0() (void)
+
+#define FUN1(t1,a1) (t1 a1)
+#define EXT1(t1) (t1)
+#define FUN1N(t1,a1) (t1 a1, ...)
+#define EXT1N(t1) (t1, ...)
+
+#define FUN2(t1,a1,t2,a2) (t1 a1,t2 a2)
+#define EXT2(t1, t2) (t1, t2)
+#define FUN2N(t1,a1,t2,a2) (t1 a1,t2 a2, ...)
+#define EXT2N(t1, t2) (t1, t2, ...)
+
+#define FUN3(t1,a1,t2,a2,t3,a3) (t1 a1, t2 a2, t3 a3)
+#define EXT3(t1, t2, t3) (t1, t2, t3)
+#define FUN3N(t1,a1,t2,a2,t3,a3)(t1 a1, t2 a2, t3 a3, ...)
+#define EXT3N(t1, t2, t3) (t1, t2, t3, ...)
+
+#define FUN4(t1,a1,t2,a2,t3,a3,t4,a4) (t1 a1, t2 a2, t3 a3, t4 a4)
+#define EXT4(t1, t2, t3, t4) (t1, t2, t3, t4)
+
+#define FUN5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5)
+#define EXT5(t1, t2, t3, t4, t5) (t1, t2, t3, t4, t5)
+
+#define FUN6(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6)
+#define EXT6(t1, t2, t3, t4, t5, t6) (t1, t2, t3, t4, t5, t6)
+
+#define FUN7(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7)
+#define EXT7(t1, t2, t3, t4, t5, t6, t7) (t1, t2, t3, t4, t5, t6, t7)
+
+#define FUN8(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8)
+#define EXT8(t1, t2, t3, t4, t5, t6, t7, t8) (t1, t2, t3, t4, t5, t6, t7, t8)
+
+#define FUN9(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9)
+#define EXT9(t1, t2, t3, t4, t5, t6, t7, t8, t9) (t1, t2, t3, t4, t5, t6, t7, t8, t9)
+
+#define FUN10(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9, t10 a10)
+#define EXT10(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
+
+#define FUN11(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10,t11,a11) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9, t10 a10, t11 a11)
+#define EXT11(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)
+
+#define FUN12(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10,t11,a11,t12,a12) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9, t10 a10, t11 a11, t12 a12)
+#define EXT12(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)
+
+#define FUN13(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10,t11,a11,t12,a12,t13,a13) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9, t10 a10, t11 a11, t12 a12, t13 a13)
+#define EXT13(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)
+
+
+#else
+/* Non-ANSI */
+#define var_start(x,y) va_start(x)
+
+/* These macros expand into old-style function definitions */
+
+#define FUN0() ()
+#define EXT0() ()
+
+#define FUN1(t1,a1) (a1) t1 a1;
+#define EXT1(t1) ()
+#define FUN1N(t1,a1) (a1,va_alist) t1 a1; va_dcl
+#define EXT1N(t1) ()
+
+#define FUN2(t1,a1,t2,a2) (a1, a2) t1 a1; t2 a2;
+#define EXT2(t1, t2) ()
+#define FUN2N(t1,a1,t2,a2,va_alist) (a1, a2) t1 a1; t2 a2; va_dcl
+#define EXT2N(t1, t2) ()
+
+#define FUN3(t1,a1,t2,a2,t3,a3) (a1, a2, a3) t1 a1; t2 a2; t3 a3;
+#define EXT3(t1, t2, t3) ()
+#define FUN3N(t1,a1,t2,a2,t3,a3) (a1, a2, a3, va_alist) t1 a1; t2 a2; t3 a3; va_dcl
+#define EXT3N(t1, t2, t3) ()
+
+#define FUN4(t1,a1,t2,a2,t3,a3,t4,a4) (a1, a2, a3, a4) t1 a1; t2 a2; t3 a3; t4 a4;
+#define EXT4(t1, t2, t3, t4) ()
+
+#define FUN5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (a1, a2, a3, a4, a5) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5;
+#define EXT5(t1, t2, t3, t4, t5) ()
+
+#define FUN6(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6) (a1, a2, a3, a4, a5, a6) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6;
+#define EXT6(t1, t2, t3, t4, t5, t6) ()
+
+#define FUN7(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7) (a1, a2, a3, a4, a5, a6, a7) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7;
+#define EXT7(t1, t2, t3, t4, t5, t6, t7) ()
+
+#define FUN8(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8) (a1, a2, a3, a4, a5, a6, a7, a8) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7; t8 a8;
+#define EXT8(t1, t2, t3, t4, t5, t6, t7, t8) ()
+
+#define FUN9(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9) (a1, a2, a3, a4, a5, a6, a7, a8, a9) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7; t8 a8; t9 a9;
+#define EXT9(t1, t2, t3, t4, t5, t6, t7, t8, t9) ()
+
+#define FUN10(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10) (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7; t8 a8; t9 a9; t10 a10;
+#define EXT10(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) ()
+
+#define FUN11(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10,t11,a11) (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7; t8 a8; t9 a9; t10 a10; t11 a11;
+#define EXT11(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) ()
+
+#define FUN12(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10,t11,a11,t12,a12) (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7; t8 a8; t9 a9; t10 a10; t11 a11; t12 a12;
+#define EXT12(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) ()
+
+#define FUN13(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7,t8,a8,t9,a9,t10,a10,t11,a11,t12,a12,t13,a13) (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7; t8 a8; t9 a9; t10 a10; t11 a11; t12 a12; t13 a13;
+#define EXT13(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) ()
+
+
+#endif
+
+#ifdef VPRINTF_MISSING
+/* The following will work for some systems. */
+#define vfprintf(stream, format, ap) _doprnt (format, ap, stream)
+int
+vsprintf FUN3(char *, into, char *, s, va_list, ap)
+{
+ int ret;
+ FILE f;
+
+ f._cnt = 32767;
+ /* taking address and dereferencing deals with the fact that
+ f._ptr can be either a char * or an unsigned char *. */
+ *(char **)&f._ptr = into;
+ f._flag = _IOWRT+_IOSTRG;
+ ret = _doprnt(s, ap, &f);
+ *f._ptr = 0;
+ return (ret);
+}
+#endif
+
+/* Names or default names for various files. */
+#define OBJ_NAM "a.out"
+#define MON_NAM "gmon.out"
+#define SUM_NAM "gmon.sum"
+
+/* Debugging stuff */
+
+#define DEBUG
+
+/* A mask of flags defined below. */
+long debug=0;
+
+/* Print obnoxious msgs about the a.out file, and the amusing values therein */
+#define DB_AFILE (1<<0) /* a.out file */
+
+/* Describe in detail the rending and tearing of the gmon.out file */
+#define DB_GFILE (1<<1) /* gmon.out file */
+
+/* Describe in detail the writing out of the gmon.sum file */
+#define DB_SUM (1<<2) /* gmon.sum file */
+
+/* Print neeto messages as we deal with -e -E -f and -F options */
+#define DB_OPT (1<<3) /* Options */
+
+/* Print msgs whenever the ring buffer is used */
+/* This probably doesn't work since the ring buffer code was
+ moved into the utilities file */
+#define DB_RB (1<<4) /* Ring buffer */
+
+/* Print msgs about cycles */
+#define DB_CYC (1<<5)
+
+/* Print msgs about assigning the histogram entries to functions */
+#define DB_HISTO (1<<6)
+
+/* Print obnoxious msgs here and there as we do our stuff */
+#define DB_MISC (1<<31) /* misc stuff */
+
+#ifdef DEBUG
+#define PRINT_OBNOXIOUS_DEBUG_MESSAGE(x, msg) if (debug&x) dbgprintf msg
+#else
+#define PRINT_OBNOXIOUS_DEBUG_MESSAGE(x, msg)
+#endif
+
+/* LessThan EQual GreaterThan */
+/* These get returned by the various comparison functions */
+#define LT (-1)
+#define EQ (0)
+#define GT (1)
+
+/* Note since *ALL* non-zero values are true, do *NOT* say
+ if (x==TRUE)
+ These values are here only for saying
+ return TRUE;
+ and things like that. */
+
+#define TRUE (1)
+#define FALSE (0)
+
+/* The floating point datatype to use for storing
+ propagated info. Float should be big enough */
+#define FLOAT double
+
+/* Used when creating a gmon.sum file */
+/* #define FUDGE_FACTOR (sizeof (CHUNK)) */
+#define FUDGE_FACTOR 0
+
+/* Description of one symbol in gprof's internal symbol table.
+ There is one of these for each function and one for each cycle.
+
+ NAME is the name of the function or cycle.
+ VALUE is the address of the start of the function.
+
+ CALLS and CALLED are chains of edges for calls into and out of
+ this function. These constitute the call graph.
+
+ NCALLS is the total number
+ of times this function called other functions,
+ NCALLED is the total number of times this function was called.
+ Note that if NCALLED is zero, but NCALLS is nozero, this function
+ must have been started magically. It happens. (Signals, etc.)
+
+ RECURSIVE is the total number of times this function was called
+ recursively.
+
+ HISTO is the total number of histogram counts for this function.
+
+ SUB_HISTO is the total number of histogram counts for this function
+ plus time propagated from the children.
+
+ CYCNUM is the number of the cycle this function is in,
+ or the number of this cycle is this entry is for a cycle.
+ -1 means the function isn't in any cycles. 0 means the
+ cycle-ness of the function hasn't been determined yet.
+
+ NUMINDEX is the index number assigned to this function
+ for the call graph.
+
+ If FLAG is non-zero, this function is in the process of being
+ saved from the oblivion caused by the -f or -F options. */
+
+struct mesym {
+ char *name;
+ unsigned long value;
+
+ struct symlist *calls;
+ unsigned ncalls;
+ struct symlist *called;
+ unsigned ncalled;
+
+ unsigned recursive;
+
+ unsigned histo;
+ FLOAT sub_histo;
+ int cycnum;
+ int numindex;
+ int flag;
+};
+
+/* Vector of `struct mesym' for all functions,
+ sorted in ascending order by VALUE field for binary search. */
+struct mesym *syms;
+int nsym=0; /* Length of vector */
+
+/* Vector of `struct mesym' for all cycles so far identified. */
+struct mesym **cycles;
+int number_of_cycles = 0; /* Length of vector */
+
+/* Structure for an edges of the call graph.
+
+ Each edge--each pair of functions A and B such that A called B--
+ is represented by one of these structures. It appears in
+ A's `calls' chain and in B's `called' chain.
+
+ Meanwhile, the structure describes its meaning with the
+ SYM_FROM and SYM_TO fields, which point to the symbol entries
+ for A and B.
+
+ Basically, if you got here from a mesym's calls
+ pointer, SYM_FROM points back to that symbol, NEXT_FROM is irrevelant,
+ SYM_TO points to the symbol it called, and NEXT_TO points to the
+ next one in the list.
+
+ If you got here from a mesym's called pointer, SYM_FROM points to
+ the symbol that called it, NEXT_FROM points to the next one in the
+ list, SYM_TO points back to the symbol, and NEXT_TO is irrelevant.
+
+ NCALLS is the number of times SYM_FROM called SYM_TO,
+ PROP_TIME is the amount of time in SYM_TO itself propagated to SYM_FROM,
+ CHILD_TIME is the amount of time
+ propagated from SYM_TO's children to SYM_FROM. */
+
+struct symlist {
+ struct mesym *sym_from;
+ struct symlist *next_from;
+ struct mesym *sym_to;
+ struct symlist *next_to;
+
+ unsigned ncalls;
+ FLOAT prop_time;
+ FLOAT child_time;
+};
+
+/* argv[0], here for the sake of error messages. */
+char *myname = 0;
+
+/* Name of the executable file. */
+char *exec_file_name;
+
+/* The string table of the executable file.
+ Each symbol entry in the file contains an index in the string table.
+ When the symbols are in core, we relocate them to point to their names,
+ which remain inside the string table. */
+char *strs;
+
+/* Header of the first gmon.out file we read. This is used to (try to)
+ make sure all the rest of the gmon.out files agree with the first one
+ (and the executable.) */
+struct gm_header hdr;
+
+/* Number of clock ticks per second. Read from the kernel's memory,
+ this number tells us how long an interval a single stab in the
+ histogram represents. */
+long ticks;
+
+/* This is an array of pointers to symbols. These are the functions that
+ we'll have to print out in the flat graph. */
+struct mesym **flat_profile_functions;
+int number_of_flat_profile_functions = 0; /* Size of vector */
+
+/* This is an array of pointers to symbols. These are the functions that
+ we should mention in the call tree. */
+struct mesym **functions_in_call_tree;
+int number_of_functions_in_call_tree= 0;
+struct mesym **f_end;
+
+/* Number of slots in the histogram. */
+int nhist;
+
+/* Total number of counts in the histogram. */
+unsigned long tothist = 0;
+
+/* Pointer to the histogram itself. */
+unsigned CHUNK *histo; /* Stabs */
+
+/* Now that I've re-written the ring_buffer code, we need this */
+void *ring_buffer;
+
+/* Record the specified options. */
+
+/* If the -a option is given, static (private) functions are not read into
+ the symbol table. This means that time spent in them, calls to them, etc,
+ are instead added to whatever function was loaded next to it in the a.out
+ file. This is compatable with UN*X gprof. (Bleh.) The right thing to do
+ is keep track of time spent in static functions, and forget about it,
+ instead of adding it to another hapless function. Rms disagrees with me.
+ I think its evil to add histogram time to a function simply because it
+ happend to be loaded in memory just before a function we don't want to print. */
+int no_locals = 0; /* -a flag */
+
+/* The -b option tells gprof to not print out the obnoxious blurbs telling
+ what all the fields of the output mean. This is useful if you've seen
+ the blurbs a gzillion times and you only want to look at your numbers. */
+int no_blurbs = 0; /* -b flag */
+
+/* If the -s option is given, gprof will write out a 'sum file' gmon.sum
+ which is a gmon.out file that contains the profile info from all the
+ gmon.out files that gprof read in. */
+int write_sum_file = 0; /* -s option */
+
+/* The -z option tells gprof to include functions with zero usage (never called,
+ and used no time) in the output. Usually, such functions are considered
+ boring, and aren't printed. */
+int print_zeros = 0; /* -z option */
+
+/* The -e option takes a function name, and suppress the printing of that
+ function and its descendents from the call graph profile. (If its
+ descendents are called from elswhere, well. . .) (Currently, they're
+ printed, and the -e'd function is shown under the list of parents so
+ you can see where the child's time is disappearing to. . .)
+
+ The -E option takes a function name, and not only -e's it, but
+ removes the time spent in the function from the total time. (Its as if
+ that function never existed (unless it calls something that is also
+ called from somewhere else, in which case. . . (Currently it works
+ as described for -e above.))
+
+ -f prints only the call tree for its argument.
+
+ -F is like -f, but it uses only the time in the function and its
+ descendents for computing total time.
+ */
+
+enum option_type { SMALL_E, BIG_E, SMALL_F, BIG_F,
+ /* Like BIG_E except don't print a warning if the
+ function doesn't exist. */
+ REMOVE_TIME_IF_THERE };
+
+struct filter {
+ char *name;
+ enum option_type type;
+};
+
+/* Vector with an element for each -e, -E, -f or -F option specified. */
+struct filter *filters;
+/* Length of the vector. */
+int nfilters;
+
+/* These values are stored in the flag field of a struct mesym so we can know
+ what we're doing to that function */
+
+/* This one is being saved by a -f or -F flag */
+#define SAVE_ME 01
+/* This one is being killed by a -e or -E flag */
+#define KILL_ME 02
+
+/* Blurbs that are copied verbatim into the output file
+ to explain the data in the tables.
+
+ If your compiler can't stand this, split this up into a vector
+ of strings, and print them one after another. */
+
+char *first_blurb = "\n\
+ The above table shows how much time was spent directly in each\n\
+ function. The table was sorted by the amount of time the computer\n\
+ spent in each function.\n\n\
+ % time This is the percentage of the total execution time\n\
+ the program spent in this function. These should all add\n\
+ up to 100%.\n\n\
+ seconds This is the total number of seconds the computer spent\n\
+ executing this function.\n\n\
+ cumsec This is the cumulative total number of seconds the\n\
+ computer spent executing this functions, plus the time spent\n\
+ in all the functions above this one in this table.\n\n\
+ calls This is the total number of times the function was called.\n\
+ If there isn't a number here, the function wasn't compiled with\n\
+ the profiler enabled, and further information about this function\n\
+ is limited. In particular, all information about where this \n\
+ function was called from has been lost.\n\n\
+ function This is the name of the function.\n\
+\f";
+
+char *second_blurb = "\n\
+ This table describes the call tree of the program, and was sorted by\n\
+ the total amount of time spent in each function and its children.\n\n\
+ Each entry in this table consists of several lines. The line with the\n\
+ index number at the left hand margin lists the current function.\n\
+ The lines above it list the functions that called this function,\n\
+ and the lines below it list the functions this one called.\n\
+ This line lists:\n\
+ index A unique number given to each element of the table.\n\
+ Index numbers are sorted numerically.\n\
+ The index number is printed next to every function name so\n\
+ it is easier to look up where the function in the table.\n\n\
+ % time This is the percentage of the `total' time that was spent\n\
+ in this function and its children. Note that due to\n\
+ different viewpoints, functions excluded by options, etc,\n\
+ these numbers will NOT add up to 100%.\n\n\
+ self This is the total amount of time spent in this function.\n\n\
+ children This is the total amount of time propagated into this\n\
+ function by its children.\n\n\
+ called This is the number of times the function was called.\n\
+ If the function called itself recursively, the number\n\
+ only includes non-recursive calls, and is followed by\n\
+ a `+' and the number of recursive calls.\n\n\
+ name The name of the current function. The index number is\n\
+ printed after it. If the function is a member of a\n\
+ cycle, the cycle number is printed between the\n\
+ function's name and the index number.\n\n\n\
+ For the function's parents, the fields have the following meanings:\n\n\
+ self This is the amount of time that was propagated directly\n\
+ from the function into this parent.\n\n\
+ children This is the amount of time that was propagated from\n\
+ the function's children into this parent.\n\n\
+ called This is the number of times this parent called the\n\
+ function `/' the total number of times the function\n\
+ was called. Recursive calls to the function are not\n\
+ included in the number after the `/'.\n\n\
+ name This is the name of the parent. The parent's index\n\
+ number is printed after it. If the parent is a\n\
+ member of a cycle, the cycle number is printed between\n\
+ the name and the index number.\n\n\
+ If the parents of the function cannot be determined, the word\n\
+ `<spontaneous>' is printed in the `name' field, and all the other\n\
+ fields are blank.\n\n\
+ For the function's children, the fields have the following meanings:\n\n\
+ self This is the amount of time that was propagated directly\n\
+ from the child into the function.\n\n\
+ children This is the amount of time that was propagated from the\n\
+ child's children to the function.\n\n\
+ called This is the number of times the function called\n\
+ this child `/' the total number of times the child\n\
+ was called. Recursive calls by the child are not\n\
+ listed in the number after the `/'.\n\n\
+ name This is the name of the child. The child's index\n\
+ number is printed after it. If the child is a\n\
+ member of a cycle, the cycle number is printed\n\
+ between the name and the index number.\n\n\
+ If there are any cycles (circles) in the call graph, there is an\n\
+ entry for the cycle-as-a-whole. This entry shows who called the\n\
+ cycle (as parents) and the members of the cycle (as children.)\n\
+ The `+' recursive calls entry shows the number of function calls that\n\
+ were internal to the cycle, and the calls entry for each member shows,\n\
+ for that member, how many times it was called from other members of\n\
+ the cycle.\n\n";
+
+
+/* Prototypes for all the functions. */
+
+int main EXT2(int, char **);
+int read_header_info EXT6 (char *, FILE *, long int *, unsigned int *,
+ long int *, unsigned int *);
+void print_flat_profile EXT0();
+void print_call_graph EXT0();
+void write_summary EXT0();
+void filter_graph EXT0();
+FLOAT convert_and_round EXT1(FLOAT);
+void add_to_lists EXT3(struct mesym *, struct mesym *, unsigned);
+void delete_from_lists EXT2(struct mesym*, struct mesym *);
+void flushfuns EXT0();
+void findcycles EXT0();
+void kill_children EXT2(struct mesym *, int);
+void save_the_children EXT2(struct mesym *, int);
+void remove_from_call_tree EXT1(struct mesym **);
+struct mesym **find_funp_from_name EXT1(char *);
+struct mesym **find_funp_from_pointer EXT1(struct mesym *);
+void read_syms EXT2(FILE *, int);
+struct mesym *val_to_sym EXT1(unsigned long);
+int badsym EXT1(struct nlist *);
+int symcmp EXT2(const void *, const void *);
+int timecmp EXT2(const void *, const void *);
+int callcmp EXT2(const void *, const void *);
+int treetimecmp EXT2(const void *, const void *);
+int listcmp EXT2(const void *, const void *);
+void readgm EXT1(char *);
+void print_blurb EXT1(char *blurb);
+long get_ticks EXT0();
+void add_filter EXT2(char *name, int flag);
+void print_sorted_list EXT3(int, int, struct symlist *);
+
+void fatal EXT1N(char *);
+void fatal_io EXT2(char *, char *);
+
+FILE *ck_fopen EXT2(char *, char *);
+void ck_fseek EXT3(FILE *, long, int);
+void ck_fread EXT4(void *, size_t, size_t, FILE *);
+void ck_fwrite EXT4(void *, size_t, size_t, FILE *);
+void ck_fclose EXT1(FILE *);
+
+void *ck_malloc EXT1(size_t);
+void *ck_calloc EXT2(size_t, size_t);
+void *ck_realloc EXT2(void *, size_t);
+
+char *mk_sprintf EXT1N(char *);
+
+void *init_ring_buffer EXT0();
+void push_ring_buffer EXT2(void *, void *);
+void *pop_ring_buffer EXT1(void *);
+int ring_buffer_isnt_empty EXT1(void *);
+void flush_ring_buffer EXT1(void *);
+
+/* C++ demangler stuff. */
+char *cplus_demangle EXT1(char *);
+void fprint_name EXT2(FILE *, char *);
+
+void fatal EXT1N(char *);
+
+void *malloc EXT1(size_t);
+void *realloc EXT2(void *,size_t);
+void free EXT1(void *);
+
+
+/* Since we don't have prototypes for the system funs, we add them
+ ourselves. . . */
+int atoi EXT1(const char *);
+long atol EXT1(const char *);
+double atof EXT1(const char *);
+
+#ifndef NeXT /* NeXT has a bug in their include files. */
+void qsort EXT4(void *, size_t, size_t, int (*)(const void *, const void *));
+#endif
+
+void exit EXT1(int);
+
+int strcmp EXT2(const char *, const char *);
+char *index EXT2(const char *, int);
+int printf EXT1N(const char *);
+int fprintf EXT2N(FILE *, const char *);
+/* char *sprintf EXT2N(const char *, const char *); */
+
+int puts EXT1(const char *);
+int fputs EXT2(const char *, FILE *);
+
+int fputc EXT2(int, FILE *);
+size_t fread EXT4(void *, size_t, size_t, FILE *);
+
+int nlist EXT2(const char *, struct nlist *);
+
+#ifndef VPRINTF_MISSING
+int vfprintf EXT3(FILE *, const char *, va_list);
+#endif
+
+void dbgprintf EXT1N(char *);
+void dumpsyms EXT0();
+void dumpfuns EXT0();
+
+
+/* And now, the program. */
+
+int
+main FUN2(int, ac, char **,av)
+{
+ FILE *fp;
+ int argc;
+ char **argv;
+ int c;
+ long int syms_offset, strs_offset;
+ unsigned int syms_size, strs_size;
+
+ extern char *optarg;
+ extern int optind, opterr;
+
+ static struct option long_options[] =
+ {
+ {"no-static", 0, &no_locals, 1},
+ {"brief", 0, &no_blurbs, 1},
+ {"no-prof", 1, 0, 'e'},
+ {"no-time", 1, 0, 'E'},
+ {"only-prof", 1, 0, 'f'},
+ {"only-time", 1, 0, 'F'},
+ {"sum", 0, &write_sum_file, 1},
+ {"zeros", 0, &print_zeros, 1},
+ {NULL, 0, NULL, 0}
+ };
+
+ char *name = '\0';
+ int ind;
+
+ argc=ac;
+ argv=av;
+
+ myname= argv[0];
+
+ /* Omit profiling internal functions from call graph. */
+#ifdef sparc
+
+#else
+ add_filter ("mcount", BIG_E);
+#endif
+ /* add_filter ("mcleanup", BIG_E); Seems to have dissappeared? */
+
+ /* GCC output doesn't have this function. */
+ add_filter ("moncontrol", REMOVE_TIME_IF_THERE);
+
+ ring_buffer=init_ring_buffer ();
+
+ while ((c = getopt_long (argc, argv, "abcdD:e:E:f:F:svz", long_options,
+ &ind)) !=EOF) {
+ if (c == 0 && long_options[ind].flag == 0)
+ c = long_options[ind].val;
+ switch (c) {
+ case 0 :
+ break;
+ case 'a':
+ no_locals= TRUE;
+ break;
+ case 'b':
+ no_blurbs = TRUE;
+ break;
+ case 'c':
+ fatal ("The -c option is not supported");
+ case 'd':
+ debug= -1;
+ break;
+ case 'D':
+ debug=atoi (optarg);
+ break;
+ case 's':
+ write_sum_file= TRUE;
+ break;
+ case 'z':
+ print_zeros = TRUE;
+ break;
+ case 'e':
+ add_filter (optarg, SMALL_E);
+ break;
+ case 'E':
+ add_filter (optarg, BIG_E);
+ break;
+ case 'f':
+ add_filter (optarg, SMALL_F);
+ break;
+ case 'F':
+ add_filter (optarg, BIG_F);
+ break;
+ default:
+ fprintf (stderr, "\
+Usage: %s [-absz] [-e func] [-E func] [-f func] [-F func]\n\
+ [+no-static] [+brief] [+no-prof func]\n\
+ [+no-time func] [+only-prof func]\n\
+ [+only-time func] [+sum] [+zeros] executable gmon.out...\n",
+ myname);
+ exit (1);
+ }
+ }
+ if (optind<argc) {
+ exec_file_name=argv[optind];
+ optind++;
+ }
+ if (!exec_file_name)
+ exec_file_name=OBJ_NAM;
+
+ /* Open the a.out file, and read in selected portions */
+ fp=ck_fopen (exec_file_name, "r");
+
+ /* Make sure its really an a.out file. If it isn't yell and scream
+ and stamp our feet. */
+ if (!read_header_info(exec_file_name, fp, &syms_offset, &syms_size, &strs_offset, &strs_size))
+ fatal ("`%s' is not an executable file", exec_file_name);
+
+ /* Read in the string table. */
+ ck_fseek (fp, strs_offset + sizeof strs_size, 0);
+ strs=(char *)ck_malloc (strs_size);
+ ck_fread ((void *)(strs+sizeof (long)), sizeof (char), strs_size-sizeof (long), fp);
+
+ /* Read the symbols, and put the interesting ones (sorted) in SYMS. */
+ ck_fseek (fp, syms_offset, 0);
+ read_syms (fp, syms_size / sizeof (struct nlist));
+
+ ck_fclose (fp);
+ /* We are done with the a.out file */
+
+ /* Read in the gmon.out files; accumulate all histogram data in HISTO
+ and put all number-of-calls figures into the call graph. */
+ if (optind>=argc) readgm (MON_NAM);
+ else {
+ while (optind<argc) {
+ readgm (argv[optind]);
+ optind++;
+ }
+ }
+
+ /* If a summary output file is wanted,
+ we can do it straightaway since we have merged the data. */
+
+ if (write_sum_file) {
+ write_summary ();
+ exit (0);
+ }
+
+ /* Find out how many clock ticks/second our machine puts out */
+ ticks=get_ticks ();
+
+ /* Assign the ticks in the histogram to the functions they represent */
+ {
+ int n;
+ unsigned long pos;
+ struct mesym *sym;
+ int incr = (hdr.high - hdr.low) / (nhist - 1);
+
+ if ((hdr.high - hdr.low) != 4 * (nhist - 1))
+ abort ();
+
+ for (n=0, pos=hdr.low, sym= &syms[0]; n<nhist; n++, pos+=incr) {
+ if (histo[n]) {
+
+ /* We've found the right symbol when *sym<=pos && *(sym+1)>pos */
+ /* This means POS lies between sym and the one after it */
+
+ while ((sym+1)->value<=pos)
+ sym++;
+ if ((sym+1)->value<(pos+incr))
+ {
+ /* Wow! On the edge. Split the time between the symbols */
+ sym->histo+=(histo[n]+1)/2;
+ (sym+1)->histo+=(histo[n])/2;
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_HISTO, ("%05lx %02d-> %s (%d) %s (%d)\n", pos, histo[n], sym->name, sym->histo, (sym+1)->name, (sym+1)->histo));
+ } else {
+ sym->histo+=histo[n];
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_HISTO, ("%05lx %02d-> %s (%d)\n", pos, histo[n], sym->name, sym->histo));
+ }
+ }
+ }
+ }
+
+ /* Avoid division by zero if there wasn't any time collected! */
+ if (tothist==0)
+ tothist=1;
+
+ print_flat_profile ();
+
+ print_call_graph ();
+
+ if (debug&DB_AFILE)
+ dumpsyms ();
+
+ if (debug&DB_AFILE)
+ dumpfuns ();
+ exit (0);
+}
+
+/* Read various information from the header of an object file.
+ Return 0 for failure or 1 for success. */
+
+int
+read_header_info (name, fp, syms_offset, syms_size, strs_offset, strs_size)
+ char *name;
+ FILE *fp;
+ long int *syms_offset;
+ unsigned int *syms_size;
+ long int *strs_offset;
+ unsigned int *strs_size;
+{
+#ifdef A_OUT
+ {
+ struct exec hdr;
+
+ ck_fseek (fp, 0L, 0);
+#ifdef HEADER_SEEK
+ HEADER_SEEK (fp);
+#endif
+
+ if (fread ((char *) &hdr, sizeof hdr, 1, fp) == 1 && !N_BADMAG(hdr))
+ {
+ *syms_offset = N_SYMOFF (hdr);
+ *syms_size = hdr.a_syms;
+ *strs_offset = N_STROFF (hdr);
+ ck_fseek (fp, N_STROFF (hdr), 0);
+ if (fread ((char *) strs_size, sizeof *strs_size, 1, fp) != 1)
+ fatal ("error reading string table of `%s'", name);
+ return 1;
+ }
+ }
+#endif
+
+#ifdef MACH_O
+ {
+ struct mach_header mach_header;
+ struct load_command *load_command;
+ struct symtab_command *symtab_command;
+ char *hdrbuf;
+ int cmd, symtab_seen;
+
+ ck_fseek (fp, 0L, 0);
+ if (fread ((char *) &mach_header, sizeof mach_header, 1, fp) == 1
+ && mach_header.magic == MH_MAGIC)
+ {
+ hdrbuf = ck_malloc (mach_header.sizeofcmds);
+ if (fread (hdrbuf, mach_header.sizeofcmds, 1, fp) != 1)
+ fatal ("failure reading load commands of file `%s'", name);
+ load_command = (struct load_command *) hdrbuf;
+ symtab_seen = 0;
+ for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
+ {
+ if (load_command->cmd == LC_SYMTAB)
+ {
+ symtab_seen = 1;
+ symtab_command = (struct symtab_command *) load_command;
+ *syms_offset = symtab_command->symoff;
+ *syms_size = symtab_command->nsyms * sizeof (struct nlist);
+ *strs_offset = symtab_command->stroff;
+ *strs_size = symtab_command->strsize;
+ }
+ load_command = (struct load_command *) ((char *) load_command + load_command->cmdsize);
+ }
+ free (hdrbuf);
+ if (!symtab_seen)
+ *syms_offset = *syms_size = *strs_offset = *strs_size = 0;
+ return 1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+/* Output a summary gmon file containing all our accumulated
+ histogram and call-graph data. */
+
+void
+write_summary FUN0()
+{
+ struct mesym *p;
+ struct symlist *t;
+ struct gm_call call_tmp;
+ FILE *fp;
+
+ fp=ck_fopen (SUM_NAM, "w");
+ hdr.nbytes=sizeof (struct gm_header)+nhist*sizeof (CHUNK);
+ ck_fwrite ((void *)&hdr, sizeof (hdr), 1, fp);
+ ck_fwrite ((void *)histo, sizeof (unsigned CHUNK), nhist, fp);
+ /* for (p= &syms[nsym]; --p>=&syms[0];) { */
+ if (nsym) {
+ p= &syms[nsym-1];
+ do {
+ for (t=p->calls; t; t=t->next_to) {
+ /* Since we've forgotten exactly where in FROM we
+ were called from, we fake it. Since this is only
+ gonna be fed back into gprof, it doesn't matter */
+ call_tmp.from=(p->value+FUDGE_FACTOR)-hdr.low;
+ call_tmp.to=(t->sym_to->value+FUDGE_FACTOR)-hdr.low;
+ call_tmp.ncalls=t->ncalls;
+ ck_fwrite ((void *)&call_tmp, sizeof (call_tmp), 1, fp);
+ }
+ } while (p-->&syms[0]);
+ }
+ ck_fclose (fp);
+}
+
+/* Print the flat profile from the symbol table information. */
+
+void
+print_flat_profile FUN0()
+{
+ int n;
+ struct mesym **funp;
+
+ /* Scan the symbol table and discover how many functions either had time
+ spent in them, or had a non-zero call count */
+ for (n=0; n<nsym; n++) {
+ if (syms[n].histo || syms[n].ncalled || print_zeros)
+ number_of_flat_profile_functions++;
+ }
+ /* Collect all the interesting functions */
+ flat_profile_functions
+ =(struct mesym **)ck_calloc (number_of_flat_profile_functions, sizeof (struct mesym *));
+ for (n=0, funp=flat_profile_functions; n<nsym; n++) {
+ if (syms[n].histo || syms[n].ncalled || print_zeros) {
+ *funp= &syms[n];
+ funp++;
+ }
+ }
+
+ /* Sort them */
+ qsort (flat_profile_functions, number_of_flat_profile_functions,
+ sizeof (struct mesym *), timecmp);
+
+ /* And print them out */
+
+ if (no_blurbs)
+ printf ("\t\tFlat profile\n\n");
+ else
+ printf ("\tFlat profile (explanation follows)\n\n");
+
+ if (no_blurbs)
+ printf ("\t\tCall graph is on the following page.\n\n");
+ else
+ printf ("\tCall graph is on the following page.\n\n");
+
+ printf ("Each sample counts as %g seconds.\n\n", 1.0/ticks);
+
+ puts ("% time seconds cumsec calls function");
+
+ for (n=0; n<number_of_flat_profile_functions; n++) {
+ unsigned histo;
+ static cumhist = 0;
+
+ histo=flat_profile_functions[n]->histo;
+ cumhist+=histo;
+ printf ("%6.2f ", (FLOAT)(100.0*histo)/(FLOAT)tothist);
+ printf ("%8.2f ", ((FLOAT)histo)/(FLOAT)ticks);
+ printf ("%8.2f ", ((FLOAT)cumhist)/(FLOAT)ticks);
+ if (flat_profile_functions[n]->ncalled)
+ printf (" %5d ", flat_profile_functions[n]->ncalled);
+ else fputs (" ", stdout);
+ fprint_name (stdout, flat_profile_functions[n]->name);
+ fputs ("\n", stdout);
+ }
+
+ /* RMS says we should print the blurb last, which makes sense to me */
+ print_blurb (first_blurb);
+}
+
+/* Compute the call graph and print it. */
+
+void
+print_call_graph FUN0()
+{
+ int n;
+ int index;
+ struct mesym **funp;
+ struct mesym **f;
+
+ /* Count the functions that appear in the call tree. */
+ for (n=0; n<nsym; n++) {
+ /* If a function calls something else, or is called by
+ something else, its in the call tree. . . */
+ if (syms[n].ncalls || syms[n].ncalled)
+ number_of_functions_in_call_tree++;
+ }
+
+ if (number_of_functions_in_call_tree == 0) {
+ printf ("\t\tNo call graph information available.\n");
+ return;
+ }
+
+ /* Allocate a vector of these functions. */
+ functions_in_call_tree
+ =(struct mesym **)ck_calloc (number_of_functions_in_call_tree, sizeof (struct mesym *));
+ for (n=0, funp=functions_in_call_tree; n<nsym; n++) {
+ if (syms[n].ncalls || syms[n].ncalled) {
+ *funp= &syms[n];
+ funp++;
+ }
+ }
+
+ /* Put all the leaf nodes at the end of the call tree */
+ qsort (functions_in_call_tree, number_of_functions_in_call_tree, sizeof (struct mesym *), callcmp);
+
+ /* Root nodes are now all at the head, and can be easily found
+ 'cuz they have call-counts of zero (Never been called, but
+ calls something else; that's spontaneous in my book.) */
+ /* Ordinary nodes are in the middle, (were called, and
+ called others. Leaf nodes are at the end. */
+
+ /* Our mission, should we choose to accept it, is to detect
+ circles in the call graph. */
+ /* We do this by keeping a pointer into the call tree called f_end. This
+ points to the end of the functions that we don't know if they are leaf
+ nodes or not. When we know something is a leaf node, we move it down
+ past f_end */
+
+ f= &functions_in_call_tree[number_of_functions_in_call_tree-1];
+ do {
+ if ((*f)->ncalls!=0)
+ break;
+ (*f)->cycnum= -1;
+
+ /* Note the neeto side effect here! Is there a better way to do this? */
+ } while (f-- > &functions_in_call_tree[0]);
+
+ /* Note that functions that only call themselves (and nobody else) don't
+ get marked above. Doesn't matter; they get marked soon. */
+ if (f== &functions_in_call_tree[0]) {
+ (*f)->cycnum= -1;
+ } else {
+ int found;
+
+ f_end=f;
+
+ /* Eliminate recursive calls */
+ do {
+ struct symlist *t, *u;
+
+ for (t= (*f)->calls; t; t=t->next_to) {
+ if (t->sym_to!= (*f))
+ continue;
+ (*f)->recursive+=t->ncalls;
+
+ (*f)->ncalls-=t->ncalls;
+ (*f)->ncalled-=t->ncalls;
+
+ /* Delete from linked list */
+ if (t==(*f)->calls)
+ (*f)->calls=t->next_to;
+ else {
+ for (u=(*f)->calls; u->next_to!=t; u=u->next_to)
+ ;
+ u->next_to=t->next_to;
+ }
+
+ /* Find and delete from called list too */
+ if (t==(*f)->called)
+ (*f)->called=t->next_from;
+ else {
+ for (u=(*f)->called; u->next_from!=t; u=u->next_from)
+ ;
+ u->next_from=t->next_from;
+ }
+ free (t);
+ break;
+ }
+ } while (f--!=&functions_in_call_tree[0]);
+
+ number_of_cycles = 0;
+
+ /* Either there weren't any cycles, or all the cycles live
+ between f_end and functions_in_call_tree */
+
+ /* Mark all functions that are not in any cycle. */
+ flushfuns ();
+
+
+ /* If we haven't got them all, find the cycle (s). */
+ if (f_end != &functions_in_call_tree[0])
+ findcycles ();
+ }
+
+ /* Add entries for the cycles to the vector of all call-graph nodes. */
+
+ functions_in_call_tree
+ =ck_realloc (functions_in_call_tree,
+ (number_of_cycles+number_of_functions_in_call_tree)*sizeof (struct mesym *));
+ for (n=0; n<number_of_cycles; n++)
+ functions_in_call_tree[number_of_functions_in_call_tree++]= cycles[n];
+
+ /* Now discard the functions that the filters say should not appear. */
+
+ filter_graph ();
+
+ /* So by now, the only functions left are the ones we want to print */
+ qsort (functions_in_call_tree, number_of_functions_in_call_tree, sizeof (struct mesym *), treetimecmp);
+
+ /* Assign each function its index number. */
+ for (n=0; n<number_of_functions_in_call_tree; n++)
+ functions_in_call_tree[n]->numindex=n+1;
+
+ if (no_blurbs)
+ printf ("\t\t\tCall graph\n\n");
+ else
+ printf ("\t\t Call graph (explanation follows)\n\n");
+
+ puts ("index % time self children called name");
+
+ /* Loop over entries. */
+
+ for (index = 0; index <number_of_functions_in_call_tree; index++) {
+ struct mesym *current = functions_in_call_tree[index];
+ char tmpstr[40]; /* Can an int have more than 40 digits? I hope not */
+
+ /* Print out all the things that called this */
+ if (current->ncalled==0 && current->called==0)
+ printf (" <spontaneous>\n");
+ else {
+ print_sorted_list (current->ncalled, current->cycnum, current->called);
+ }
+
+
+ sprintf (tmpstr, "[%d]", current->numindex);
+ printf ("%-6s %6.2f %7.2f %7.2f ",
+ tmpstr,
+ (FLOAT)(100.0*(current->sub_histo+current->histo))/(FLOAT)tothist,
+ convert_and_round ((FLOAT)current->histo),
+ convert_and_round ((FLOAT)current->sub_histo));
+
+ if (current->recursive) {
+ printf ("%4d+%-4d ",
+ current->ncalled,
+ current->recursive);
+ fprint_name (stdout, current->name);
+ } else {
+ printf ("%4d ", current->ncalled);
+ fprint_name (stdout, current->name);
+ }
+
+ if (current->cycnum>0 && current->name[0]!='<')
+ printf (" <cycle %d>", current->cycnum);
+
+ printf (" [%d]\n", current->numindex);
+
+
+ /* Now print out the children */
+
+ if (current->name[0]=='<')
+ print_sorted_list (-2, current->cycnum, current->calls);
+ else
+ print_sorted_list (-1, current->cycnum, current->calls);
+
+
+ printf ("----------------------------------------\n");
+ }
+
+ print_blurb (second_blurb);
+}
+
+/* Scan the call tree for virtual leaf nodes */
+/* If we find any, propagate time into them from their children,
+ mark them as being leaf nodes. Then repeat the process. When
+ we drop out of here, either we've flushed the entire tree, or
+ we've found a cycle. */
+
+void
+flushfuns FUN0()
+{
+ int found;
+ struct mesym **f;
+
+ do {
+ found=0;
+ f=f_end;
+ do {
+ struct symlist *t;
+
+ assert (f>=functions_in_call_tree);
+
+ for (t=(*f)->calls; t; t=t->next_to)
+ if (t->sym_to->cycnum==0)
+ break;
+
+ /* We've found an virtual leaf node. We shold
+ propagate time into the node, and move it
+ past f_end, since we aren't interested in
+ it anymore */
+ if (!t) {
+ found++;
+
+ /* If its a member of a cycle, cycnum is positive, and
+ time propagation has already been dealt with. */
+ if ((*f)->cycnum==0) {
+ for (t=(*f)->calls; t; t=t->next_to) {
+ struct mesym *symP;
+
+ if (t->sym_to->name[0]=='<')
+ continue;
+ if (t->sym_to->cycnum==-1)
+ symP= t->sym_to;
+ else
+ symP= cycles[t->sym_to->cycnum-1];
+
+ t->prop_time= (FLOAT)t->ncalls*(FLOAT)symP->histo/(FLOAT)symP->ncalled;
+ t->child_time=(FLOAT)t->ncalls* symP->sub_histo /(FLOAT)symP->ncalled;
+ (*f)->sub_histo+=t->prop_time+t->child_time;
+ }
+ (*f)->cycnum= -1;
+ }
+
+ /* move this node past f_end, since we don't care
+ about it anymore */
+ if (f_end!=functions_in_call_tree) {
+ /* move this function to the end */
+ if (f!=f_end) {
+ struct mesym *tmp;
+
+ tmp= *f;
+ *f= *f_end;
+ *f_end=tmp;
+ }
+ --f_end;
+ }
+ assert (f_end>=functions_in_call_tree);
+ }
+ } while (f-->&functions_in_call_tree[0]);
+ } while (found && f_end>&functions_in_call_tree[0]);
+}
+
+void
+findcycles FUN0()
+{
+ struct mesym **f;
+ struct mesym *ptr;
+ struct symlist *tmp;
+ struct cy {
+ struct mesym *memb1;
+ struct mesym *memb2;
+ struct mesym **others;
+ int width;
+ int deepest;
+ int shallowest;
+ };
+ struct cy *cy;
+ int ncy = 0;
+ int n;
+
+ int bigdepth = 0;
+ int curdepth;
+ struct mesym *current_cycle_pointer;
+ struct mesym *cursym;
+
+ int tree_depth;
+
+ for (f= &functions_in_call_tree[0]; f<=f_end; f++) {
+ if ((*f)->ncalled==0) {
+ push_ring_buffer (ring_buffer, *f);
+ (*f)->flag=0;
+ }
+ }
+ push_ring_buffer (ring_buffer, (void *)0);
+
+ tree_depth = 1;
+ for (;;) {
+ ptr=pop_ring_buffer (ring_buffer);
+ if (!ptr) {
+ if (ring_buffer_isnt_empty (ring_buffer)) {
+ push_ring_buffer (ring_buffer, (void *)0);
+ tree_depth ++;
+ continue;
+ } else {
+ break;
+ }
+ } else if (ptr->flag==1) {
+ fprintf (stderr, "Ignoring call to spont function ");
+ fprint_name (stderr, ptr->name);
+ fprintf (stderr, "\n");
+ } else if (ptr->flag!=0) {
+ /* Save upward edge */
+ /* printf ("Upward edge detected in function %s\n", ptr->name); */
+ if (!ncy) {
+ cy=ck_malloc (sizeof (struct cy));
+ ncy=1;
+ } else {
+ ncy++;
+ cy=ck_realloc (cy, ncy*sizeof (struct cy));
+ }
+ cy[ncy-1].memb1=ptr;
+ cy[ncy-1].memb2=0;
+ } else {
+ ptr->flag=tree_depth;
+ for (tmp=ptr->calls; tmp; tmp=tmp->next_to)
+ if (tmp->sym_to->cycnum!=-1)
+ push_ring_buffer (ring_buffer, tmp->sym_to);
+ }
+ }
+ if (!ncy)
+ return;
+
+ for (n=0; n<ncy; n++) {
+ struct symlist *s;
+ struct symlist *u;
+
+
+ cursym=cy[n].memb1;
+ if (cursym->cycnum)
+ continue;
+
+ number_of_cycles++;
+ /* for (s=cursym->called; s; s=s->next_from) {
+ if (s->sym_from->flag>=cursym->flag)
+ break;
+ }
+ if (!s)
+ abort (); */
+
+ if (!cycles)
+ cycles=(struct mesym **)ck_malloc (sizeof (struct mesym *));
+ else
+ cycles=(struct mesym **)ck_realloc ((void *)cycles,
+ number_of_cycles*sizeof (struct mesym *));
+
+ current_cycle_pointer = (struct mesym *)ck_malloc (sizeof (struct mesym));
+ cycles[number_of_cycles-1] = current_cycle_pointer;
+ bzero (current_cycle_pointer, sizeof *current_cycle_pointer);
+ current_cycle_pointer->name=mk_sprintf ("<cycle %d as a whole>", number_of_cycles);
+ current_cycle_pointer->value= (unsigned long)-1;
+ current_cycle_pointer->cycnum=number_of_cycles;
+
+ cursym=cy[n].memb1;
+
+ push_ring_buffer (ring_buffer, cursym);
+
+ while (ring_buffer_isnt_empty (ring_buffer)) {
+ cursym=pop_ring_buffer (ring_buffer);
+ if (cursym->cycnum==number_of_cycles)
+ continue;
+ if (cursym->cycnum!=0)
+ abort ();
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_CYC, ("adding %s (%d) to cycle", cursym->name, cursym->histo));
+ current_cycle_pointer->histo+=cursym->histo;
+ cursym->cycnum=number_of_cycles;
+ add_to_lists (current_cycle_pointer, cursym, 0);
+
+ /* Now queue the subroutines of this function to be scanned
+ eventually. */
+
+ for (u=cursym->calls; u; u=u->next_to)
+ if (u->sym_to->cycnum==0) {
+ push_ring_buffer (ring_buffer, (void *)(u->sym_to));
+ } else if (u->sym_to->name[0] == '<') {
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_CYC, ("Cycle calls %s (%d)", u->sym_to->name, u->ncalls));
+ add_to_lists (current_cycle_pointer, u->sym_to, u->ncalls);
+ }
+ }
+
+ /* The cycle's list of children now contains all the members of the cycle.
+ Occasionally a function creeps in that doesn't belong in the cycle.
+ Find and remove them. */
+
+ {
+ struct symlist *v;
+ int found;
+
+ do {
+ found = 0;
+ for (u=current_cycle_pointer->calls; u; u=u->next_to) {
+ for (v=u->sym_to->called; v; v=v->next_from)
+ if (v->sym_from->name[0]!='<' && v->sym_from->cycnum==number_of_cycles)
+ break;
+ if (!v) {
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_CYC, ("%s not really in cycle", u->sym_to->name));
+ /* This 'cycle member' wasn't called by any member of the cycle.
+ thus, it isn't a cycle member. */
+ u->sym_to->cycnum=0;
+ delete_from_lists (current_cycle_pointer, u->sym_to);
+ found++;
+ }
+ }
+ } while (found);
+ }
+ /* The cycle's lists of callers and children are now correct.
+ Propagate the time through the cycle. */
+
+
+ /* Now we propagate time INTO the
+ cycle from its children. We could do this in flushfuns,
+ but its easier to do here, since doing it here guarentees
+ it only happens once per cycle */
+
+ for (u=current_cycle_pointer->calls; u; u=u->next_to) {
+ struct mesym *symP;
+ struct symlist *v;
+
+ /* We have to remember to not propagate time that's already here. . . */
+ if (u->sym_to->cycnum!=number_of_cycles) {
+ current_cycle_pointer->ncalls+=u->ncalls;
+
+ if (u->sym_to->cycnum==-1)
+ symP= u->sym_to;
+ else /* Propagate time FROM another cycle here */
+ symP= cycles[u->sym_to->cycnum-1];
+ u->prop_time= (FLOAT)u->ncalls*(FLOAT)symP->histo/(FLOAT)symP->ncalled;
+ u->child_time=(FLOAT)u->ncalls* symP->sub_histo /(FLOAT)symP->ncalled;
+ current_cycle_pointer->sub_histo+=u->prop_time+u->child_time;
+ for (v=u->sym_to->called; v; v=v->next_from) {
+ if (v->sym_from->cycnum==number_of_cycles) {
+ v->prop_time= (FLOAT)v->ncalls*(FLOAT)symP->histo/(FLOAT)symP->ncalled;
+ v->child_time=(FLOAT)v->ncalls* symP->sub_histo /(FLOAT)symP->ncalled;
+ }
+ }
+ } else {
+ u->prop_time= u->sym_to->histo;
+ u->child_time=u->sym_to->sub_histo;
+
+ for (v=u->sym_to->calls; v; v=v->next_to) {
+ if (v->sym_to->cycnum==number_of_cycles) {
+ add_to_lists (current_cycle_pointer, v->sym_to, v->ncalls);
+ current_cycle_pointer->recursive+=v->ncalls;
+ } else {
+ symP = v->sym_to;
+ v->prop_time= (FLOAT)v->ncalls*(FLOAT)symP->histo/(FLOAT)symP->ncalled;
+ v->child_time=(FLOAT)v->ncalls* symP->sub_histo /(FLOAT)symP->ncalled;
+ }
+ }
+
+ for (v=u->sym_to->called; v; v=v->next_from) {
+ assert (v->sym_from->cycnum==0 || v->sym_from->cycnum==number_of_cycles);
+ if (v->sym_from->cycnum==0) {
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_CYC, ("Cycle called by %s (%d)", v->sym_from->name, v->ncalls));
+ add_to_lists (v->sym_from, current_cycle_pointer, v->ncalls);
+ }
+ }
+ }
+ }
+
+
+ /* Sum all calls into the cycle, from each caller not in the cycle,
+ to get the number of calls into the cycle. */
+ for (u=current_cycle_pointer->called; u; u=u->next_from) {
+ if (u->sym_from->cycnum!=number_of_cycles)
+ current_cycle_pointer->ncalled+=u->ncalls;
+ }
+
+ /* Loop over functions in this cycle. */
+ for (u=current_cycle_pointer->calls; u; u=u->next_to) {
+ struct symlist *v;
+
+ if (u->sym_to->cycnum!=number_of_cycles)
+ continue;
+
+ /* U->sym_to is a function in this cycle. */
+
+ /* Find all calls to this function from functions outside the cycle
+ and add remove them from the count of calls "from the cycle" to this function. */
+
+ for (v=u->sym_to->called; v; v=v->next_from) {
+ if (v->sym_from != current_cycle_pointer
+ && v->sym_from->cycnum==number_of_cycles)
+ u->sym_to->ncalled-=v->ncalls;
+ }
+ }
+
+ /* Compute amounts of time to propagate out of the cycle
+ to the callers-in. */
+
+ for (u=current_cycle_pointer->called; u; u=u->next_from)
+ if (u->sym_from->cycnum != number_of_cycles) {
+ struct symlist *v;
+
+ u->prop_time= ((FLOAT)u->ncalls*(FLOAT)current_cycle_pointer->histo /(FLOAT)current_cycle_pointer->ncalled);
+ u->child_time=((FLOAT)u->ncalls* current_cycle_pointer->sub_histo /(FLOAT)current_cycle_pointer->ncalled);
+ for (v=u->sym_from->calls; v; v=v->next_to) {
+ if (v->sym_to->cycnum==number_of_cycles) {
+ v->prop_time= ((FLOAT)v->ncalls*(FLOAT)current_cycle_pointer->histo /(FLOAT)current_cycle_pointer->ncalled);
+ v->child_time=((FLOAT)v->ncalls* current_cycle_pointer->sub_histo /(FLOAT)current_cycle_pointer->ncalled);
+ }
+ }
+ }
+
+ flushfuns ();
+ }
+}
+
+
+/* Remove from the call tree all nodes that are rejected by
+ the -e, -E, -f and -F filters that were specified.
+ Their nodes are removed from functions_in_call_tree
+ and their edges are deleted from the lists they are in. */
+
+void
+filter_graph FUN0()
+{
+ int n;
+ int the_bomb_is_falling = 0;
+
+ for (n=0; n<nfilters; n++) {
+ struct mesym **call_tree_pointer;
+
+ call_tree_pointer=find_funp_from_name (filters[n].name);
+ /* Couldn't find it? Skip it! */
+ if (!call_tree_pointer) {
+ /* It may have taken time, although it
+ isn't in the call tree. Seek and
+ destroy! */
+ if (filters[n].type==BIG_E
+ || filters[n].type == REMOVE_TIME_IF_THERE) {
+ struct mesym *p;
+
+ for (p=syms; p< &syms[nsym]; p++) {
+ if (!strcmp (p->name, filters[n].name)) {
+ tothist-=p->histo;
+ break;
+ }
+ }
+ if (p==&syms[nsym] && filters[n].type != REMOVE_TIME_IF_THERE) {
+ fprintf (stderr, "Warning: couldn't find function ");
+ fprint_name (stderr, filters[n].name);
+ fprintf (stderr, "\n");
+ }
+ } else {
+ fprintf (stderr, "Warning: ");
+ fprint_name (stderr, filters[n].name);
+ fprintf (stderr, " is not in the call tree.\n");
+ }
+ continue;
+ }
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_OPT, ("Option %d on %s", filters[n].type, (*call_tree_pointer)->name));
+
+ switch (filters[n].type) {
+ case SMALL_E:
+ kill_children (*call_tree_pointer, FALSE);
+ break;
+ case BIG_E:
+ case REMOVE_TIME_IF_THERE:
+ kill_children (*call_tree_pointer, TRUE);
+ break;
+ case SMALL_F:
+ if (!the_bomb_is_falling)
+ the_bomb_is_falling = 1;
+ save_the_children (*call_tree_pointer, FALSE);
+ break;
+ case BIG_F:
+ if (!the_bomb_is_falling) {
+ the_bomb_is_falling = 1;
+ tothist=0;
+ }
+ save_the_children (*call_tree_pointer, TRUE);
+ break;
+ default:
+ abort ();
+ }
+ }
+
+ /* If we had -e or -E filters, now delete everything that
+ was not marked to be saved. */
+
+ if (the_bomb_is_falling) {
+ struct mesym **call_tree_pointer;
+
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_OPT, ("And now we drop the bomb."));
+ call_tree_pointer =
+ &functions_in_call_tree[number_of_functions_in_call_tree-1];
+ do {
+ if (((*call_tree_pointer)->flag&SAVE_ME)==0)
+ remove_from_call_tree (call_tree_pointer);
+ } while (call_tree_pointer-->&functions_in_call_tree[0]);
+ }
+}
+
+/* Collect a list of parents/children, sort them, and print them */
+/* If CALLED > 0, we print parents,
+ and the value of CALLED is the total number of times this fn was called.
+ If CALLED == -2 we print children.
+ This is used for printing the children of an entire cycle.
+ If CALLED == -1, we print children and if their cycle number is the
+ same as CYCLE, we print abbreviated information.
+ This is used for printing the children of an ordinary function. */
+/* LIST is the list of parents/children we want to print */
+
+void
+print_sorted_list FUN3(int, called, int, cycle, struct symlist *, list)
+{
+ static struct symlist **sbuf;
+ static nsbuf, sizsbuf;
+ struct symlist **sbp, *t;
+ struct mesym *symP;
+
+ if (!sizsbuf) {
+ sbuf=(struct symlist **)ck_calloc (30, sizeof (struct symlist *));
+ nsbuf=0;
+ sizsbuf=30;
+ }
+
+ /* Extract all the symbols in LIST as a vector,
+ but ignore any which represent entire cycles. */
+
+ t=list;
+ for (sbp= &sbuf[0]; t;) {
+ symP = (called>=0) ? t->sym_from : t->sym_to;
+ if (symP && symP->name[0] != '<') {
+ *sbp=t;
+ sbp++;
+ nsbuf++;
+ if (nsbuf==sizsbuf) {
+ sizsbuf*=2;
+ sbuf=(struct symlist **)ck_realloc ((void *)sbuf, sizsbuf*sizeof (struct symlist *));
+ sbp= &sbuf[nsbuf];
+ }
+ } else {
+ symP++;
+
+ }
+
+ if (called>=0) t=t->next_from;
+ else t=t->next_to;
+ }
+
+ /* Sort the vector. */
+ qsort (sbuf, nsbuf, sizeof (struct symlist *), listcmp);
+
+ /* Print the elements of the vector. */
+ for (sbp= &sbuf[0]; nsbuf>0; nsbuf--, sbp++) {
+ t= *sbp;
+ if (called>=0) symP=t->sym_from;
+ else symP=t->sym_to;
+
+ if (cycle>0 && cycle==symP->cycnum) {
+ if (called==-2) {
+ printf (" %7.2f %7.2f %4d ",
+ convert_and_round ((FLOAT)(symP->histo)),
+ convert_and_round ((FLOAT)(symP->sub_histo)),
+ t->ncalls);
+ fprint_name (stdout, symP->name);
+ } else {
+ /* For things in the same cycle, we only want to print
+ the number of calls */
+ printf ("%30s %4d ", "", t->ncalls);
+ fprint_name (stdout, symP->name);
+ }
+ } else {
+ printf (" %7.2f %7.2f %4d/%-4d ",
+ convert_and_round (t->prop_time),
+ convert_and_round (t->child_time),
+ t->ncalls,
+ (called>=0) ? called : symP->ncalled);
+ fprint_name (stdout, symP->name);
+ }
+
+ if (symP->cycnum>0 && symP->name[0]!='<')
+ printf (" <cycle %d>", symP->cycnum);
+
+ if (symP->numindex)
+ printf (" [%d]\n", symP->numindex);
+ else
+ printf (" [not printed]\n");
+ }
+}
+
+/* Compare two symbols for which should come first among
+ the callers or subroutines in a single call-graph entry. */
+
+int
+listcmp FUN2(const void *, a, const void *, b)
+{
+ struct symlist *aa, *bb;
+ FLOAT n;
+
+ aa= *(struct symlist **)a;
+ bb= *(struct symlist **)b;
+
+ n=(bb->prop_time + bb->child_time - aa->prop_time - aa->child_time);
+
+ if (n<0) return -1;
+ if (n>0) return 1;
+ return 0;
+}
+
+/* Convert a number (IN) from the histogram into seconds, rounding to the
+ nearest 100th of a second. */
+FLOAT
+convert_and_round FUN1(FLOAT, in)
+{
+ long int inter;
+
+ inter=((in/(FLOAT)(ticks))+.005)*100.0;
+ return ((FLOAT)(inter)/100.0);
+}
+
+/* Given ncalls from fromP to toP, add a symlist element telling about it */
+void
+add_to_lists FUN3(struct mesym *, fromP, struct mesym *, toP, unsigned, ncalls)
+{
+ struct symlist *tmp;
+
+ for (tmp=fromP->calls; tmp; tmp=tmp->next_to)
+ if (tmp->sym_to==toP) {
+ tmp->ncalls+=ncalls;
+ break;
+ }
+ if (!tmp) {
+ tmp=(struct symlist *)ck_malloc (sizeof (struct symlist));
+ tmp->sym_from=fromP;
+ tmp->next_from=toP->called;
+ tmp->sym_to=toP;
+ tmp->next_to=fromP->calls;
+ tmp->ncalls=ncalls;
+ tmp->prop_time = -1;
+ tmp->child_time = -1;
+
+ fromP->calls=tmp;
+ toP->called=tmp;
+ }
+}
+
+
+/* The reverse of add_to_lists. Forget that fromP ever called toP */
+void
+delete_from_lists FUN2(struct mesym *, fromP, struct mesym *, toP)
+{
+ struct symlist *die, *tmp, *old;
+
+ if (fromP->calls->sym_to==toP) {
+ die=fromP->calls;
+ fromP->calls=fromP->calls->next_to;
+ } else {
+ old=0;
+ for (tmp=fromP->calls; tmp; tmp=tmp->next_to) {
+ if (tmp->sym_to==toP) {
+ die=tmp;
+ old->next_to=tmp->next_to;
+ }
+ old=tmp;
+ }
+ }
+
+ if (toP->called->sym_from==fromP) {
+ die=toP->called;
+ toP->called=toP->called->next_from;
+ } else {
+ for (tmp=toP->called; tmp; tmp=tmp->next_from) {
+ old=0;
+ if (tmp->sym_from==fromP) {
+ die=tmp;
+ old->next_from=tmp->next_from;
+ }
+ old=tmp;
+ }
+ }
+ free (die);
+}
+
+
+/* Implement the -e or -E option by deleting a certain function
+ and all its descendents from the call graph.
+ If FLUSHFLAG is set, remove its histogram time from the total, too. */
+
+void
+kill_children FUN2(struct mesym *, p, int, flushflag)
+{
+ struct symlist *t;
+
+ push_ring_buffer (ring_buffer, p);
+ while (ring_buffer_isnt_empty (ring_buffer)) {
+ p=pop_ring_buffer (ring_buffer);
+ if (flushflag)
+ tothist-=p->histo;
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_OPT, ("Flushing %s (%d)", p->name, flushflag ? p->histo : 0));
+ p->flag|=KILL_ME;
+ remove_from_call_tree (find_funp_from_pointer (p));
+ for (t=p->calls; t; t=t->next_to) {
+ if (t->sym_to->ncalled==t->ncalls
+ || (p->cycnum>0 && t->sym_to->cycnum==p->cycnum)) {
+ push_ring_buffer (ring_buffer, t->sym_to);
+ } else if (t->sym_to->cycnum>0 && t->sym_to->cycnum!=p->cycnum) {
+ if (cycles[t->sym_to->cycnum-1]->ncalled==t->ncalls) {
+ push_ring_buffer (ring_buffer, cycles[t->sym_to->cycnum-1]);
+ }
+ } else {
+ struct symlist *ztmp;
+
+ for (ztmp=t->sym_to->called; ztmp; ztmp=ztmp->next_from) {
+ if ((ztmp->sym_from->flag&KILL_ME)==0)
+ break;
+ }
+ if (!ztmp)
+ push_ring_buffer (ring_buffer, t->sym_to);
+ else {
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_OPT, ("Not flushing %s. . . More parents", t->sym_to->name));
+ /* Do we want to deal with removing FRACTIONS of time from
+ functions who were called from different places? If so,
+ code goes here. (F'rinstance, if half of the calls to
+ function X were made from here, cut its stored time in half */
+ }
+ }
+ }
+ }
+}
+
+/* This is the opposite of kill_children ().
+ -f or -F has been specified, so all call-graph nodes EXCEPT
+ the descendents of specified functions will be killed.
+ Find all these descendents and mark them to be saved
+ by setting the `flag' fields nonzero.
+
+ If TIMEFLAG is set, the histogram-total has
+ already been nuked, and we should add our histogram time to
+ it in an attempt at reconstruction. . . */
+
+void
+save_the_children FUN2(struct mesym *, p, int, timeflag)
+{
+ struct symlist *t;
+
+ push_ring_buffer (ring_buffer, p);
+ while (ring_buffer_isnt_empty (ring_buffer)) {
+ p=pop_ring_buffer (ring_buffer);
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_OPT, ("Saving %s (%d)", p->name, p->histo));
+ p->flag|=SAVE_ME;
+ if (p->cycnum>0)
+ cycles[p->cycnum-1]->flag|=SAVE_ME;
+ if (timeflag)
+ tothist+=p->histo;
+ for (t=p->calls; t; t=t->next_to) {
+ if ((t->sym_to->flag&SAVE_ME)==0)
+ push_ring_buffer (ring_buffer, t->sym_to);
+ }
+ }
+}
+
+/* The bomb is falling, and PT has just been hit by severe doses of
+ radiation. Remove it from the call-tree vector */
+void
+remove_from_call_tree FUN1(struct mesym **, pt)
+{
+ if (!pt) {
+ /* Just quietly returning allows us to remove cycles from
+ the call tree easily. */
+ /* panic ("Internal Error: trying to remove null from call tree"); */
+ return;
+ }
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_OPT, ("Removing %ss from the tree", (*pt)->name));
+ *pt=functions_in_call_tree[number_of_functions_in_call_tree-1];
+ number_of_functions_in_call_tree--;
+}
+
+/* We want to play with a member of the call tree, but we
+ only know its name. Try to find the funp. This is slow,
+ natch, since it uses linear search, but it doesn't get called much */
+
+/* Should be some way to scan rest of symbols so we could delete
+ mcount/mcleanup histogram ticks. Should be way to disable warning? */
+struct mesym **
+find_funp_from_name FUN1(char *, name)
+{
+ struct mesym **ret;
+
+ ret= &functions_in_call_tree[number_of_functions_in_call_tree-1];
+ do {
+ if (strcmp ((*ret)->name, name)==0)
+ return ret;
+ } while (ret-->&functions_in_call_tree[0]);
+ return 0;
+}
+
+/* We have the mesym, but we need to know where it lives in the call-tree
+ This is almost as slow as find_funp_from_name (). */
+struct mesym **
+find_funp_from_pointer FUN1(struct mesym *, p)
+{
+ struct mesym **ret;
+
+ ret= &functions_in_call_tree[number_of_functions_in_call_tree-1];
+ do {
+ if (*ret==p)
+ return ret;
+ } while (ret-->&functions_in_call_tree[0]);
+ /* fprintf (stderr, "Warning: Can't find %s in the call tree.\n", p->name); */
+ return 0;
+}
+
+/* Read symbols from a.out file open on FP. There are N of them. Allocate a
+ vector to store the interesting ones in, and sort it numerically. */
+
+void
+read_syms FUN2(FILE *, fp, int, n)
+{
+ struct nlist *tmpsyms;
+ struct nlist *sym;
+ int i;
+#ifdef __STDC__
+ char buf[n];
+#else
+ char *buf;
+ char *alloca ();
+
+ buf=alloca (n);
+#endif
+ /* Read the entire symbol table. */
+ tmpsyms=(struct nlist *)ck_malloc (n*sizeof (struct nlist));
+ ck_fread (tmpsyms, sizeof (struct nlist), n, fp);
+
+ bzero (buf, n);
+
+ /* Count the useful symbols.
+ Also relocate their name-fields to be C string pointers. */
+ for (sym= &tmpsyms[0], i=0; sym<&tmpsyms[n]; sym++) {
+ sym->n_un.n_name= strs+sym->n_un.n_strx;
+ if (!badsym (sym))
+ buf[sym-tmpsyms] = 1, i++;
+ }
+
+ /* Allocate permanent space and copy useful symbols into it. */
+ nsym=i;
+ syms=(struct mesym *)ck_calloc (nsym, sizeof (struct mesym));
+
+ for (sym= &tmpsyms[0], i=0; sym<&tmpsyms[n]; sym++) {
+ if (!badsym (sym)) {
+ syms[i].name=sym->n_un.n_name;
+
+#ifndef nounderscore
+ /* Remove the initial _ from the symbol name */
+ if (*(syms[i].name)=='_')
+ syms[i].name++;
+#endif
+ syms[i].value=sym->n_value;
+ i++;
+ }
+ else if (buf[sym-tmpsyms])
+ abort ();
+ }
+
+ if (i != nsym)
+ abort ();
+
+ /* Put symbols in numeric order. */
+ qsort (syms, nsym, sizeof (struct mesym), symcmp);
+ free ((void *)tmpsyms);
+}
+
+/* Return the symbol which has the largest value less than VAL.
+ Since the symbol vector is sorted by value, this is done
+ with a binary search. */
+
+struct mesym *
+val_to_sym FUN1(unsigned long, val)
+{
+ struct mesym *m;
+ int gap=nsym/4;
+
+ m= &syms[nsym/2];
+ for (;;) {
+ if (m->value>val) {
+ m-=gap;
+ gap/=2;
+ } else if ((m+1)->value<val) {
+ m+=gap;
+ gap/=2;
+ } else
+ break;
+ if (m<&syms[0] || m>=&syms[nsym])
+ abort ();
+ if (gap<1)
+ gap=1;
+ }
+ return m;
+}
+
+/* Return TRUE if the nlist-entry SYM describes a symbol
+ that gprof should pay attention to. */
+
+int
+badsym FUN1(struct nlist *, sym)
+{
+#ifndef N_SECT
+ if ((sym->n_type & ~N_EXT) != N_TEXT)
+ return TRUE;
+#else
+ if ((sym->n_type & ~N_EXT) != N_TEXT && (sym->n_type & ~N_EXT) != N_SECT)
+ return TRUE;
+#endif
+ if (no_locals && !(sym->n_type&N_EXT))
+ return TRUE;
+ /* Filenames or pascal labels should be ignored */
+ if (index (sym->n_un.n_name, '.') || index (sym->n_un.n_name, '$'))
+ return TRUE;
+ return FALSE;
+}
+
+/* This is used to qsort () the symbol table into numerical order. */
+
+int
+symcmp FUN2(const void *, a, const void *, b)
+{
+ struct mesym *aa, *bb;
+
+ aa=(struct mesym *)a;
+ bb=(struct mesym *)b;
+ return aa->value - bb->value;
+}
+
+/* This is used to sort the vector for the flat profile.
+ if they used different amounts of time, the one with
+ the most time goes first. If they used the same amount,
+ the one that was called most goes first. If they were
+ called the same #, they are sorted alphabetically */
+
+int
+timecmp FUN2(const void *, a, const void *, b)
+{
+ struct mesym *aa, *bb;
+ int n;
+
+ aa= *(struct mesym **)a;
+ bb= *(struct mesym **)b;
+ n = bb->histo - aa->histo;
+ if (n==0) n=bb->ncalled - aa->ncalled;
+ if (n==0) n=strcmp (aa->name, bb->name);
+ return n;
+}
+
+/* This is used to sort the functions_in_call_tree[] vector
+ so the leaf nodes are at the end, and the root nodes
+ are at the beginning. This bit about useless nodes could
+ probably be taken out now, since they shouldn't make it
+ into the vector in the first place */
+
+int
+callcmp FUN2(const void *, a, const void *, b)
+{
+ struct mesym *aa, *bb;
+
+ aa= *(struct mesym **)a;
+ bb= *(struct mesym **)b;
+
+ /* Send useless symbols to the end */
+ if (aa->ncalls==0 && aa->ncalled==0) {
+ if (bb->ncalls==0 && bb->ncalled==0)
+ return EQ;
+ return GT;
+ }
+ if (bb->ncalled==0 && bb->ncalls==0)
+ return LT;
+
+ /* send root nodes to the front; */
+ /* Functions that were called 0 times
+ are spontaneous */
+
+ if (aa->ncalled==0) {
+ if (bb->ncalled==0)
+ return EQ;
+ return LT;
+ }
+ if (bb->ncalled==0)
+ return GT;
+
+ /* Send leaf nodes to the end */
+ if (aa->ncalls==0) {
+ if (bb->ncalls==0)
+ return EQ;
+ return GT;
+ }
+ if (bb->ncalls==0)
+ return LT;
+
+ /* And keep the rest the same */
+ return EQ;
+}
+
+/* This is used to sort functions_in_call_tree[] before printing.
+ To print, we want
+ A: the ones with the most time first
+ a: (If one was never called, put it first, 'cuz it
+ was invoked by GOD, else the one called the most
+ # of times first)
+ 1: the one with the lower name (strcmp ()) first
+ */
+
+int
+treetimecmp FUN2(const void *, a, const void *, b)
+{
+ struct mesym *aa, *bb;
+ int n;
+
+ aa= *(struct mesym **)a;
+ bb= *(struct mesym **)b;
+ n = (bb->histo+bb->sub_histo) - (aa->histo+aa->sub_histo);
+ if (n==0) {
+
+ /* Just to be bizarre: If one was never called,
+ put it first, else put the one who was called
+ the most first. Confused yet? */
+ if (aa->ncalled==0)
+ return LT;
+ if (bb->ncalled==0)
+ return GT;
+ n=bb->ncalled - aa->ncalled;
+ if (n==0)
+ n=strcmp (aa->name, bb->name);
+ }
+ return n;
+}
+
+/* Read in a gmon.out file named NAME and deal with the stuff inside it. */
+
+void
+readgm FUN1(char *, name)
+{
+ FILE *fp;
+ struct gm_header tmp;
+ unsigned CHUNK *p;
+ int n;
+ struct gm_call calltmp;
+
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_GFILE, ("gmon from `%s'", name));
+
+ fp=ck_fopen (name, "r");
+
+ /* Read in the gmon file header and check that histogram is
+ compatible with the other gmon files already read. */
+
+ ck_fread ((void *)&tmp, sizeof (tmp), 1, fp);
+ if (hdr.low) {
+ if (hdr.low!=tmp.low || hdr.high!=tmp.high)
+ fatal ("file `%s' is incompatable with previous gmon.out file", name);
+ } else
+ hdr=tmp;
+
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_GFILE, ("lowpc=%ld hipc=%ld nbytes= %ld", hdr.low, hdr.high, hdr.nbytes));
+
+ /* Allocate the total histogram if we haven't yet done so. */
+
+ if (!histo) {
+ nhist=(hdr.nbytes-sizeof (struct gm_header))/sizeof (CHUNK);
+ histo=(unsigned CHUNK *)ck_calloc (nhist, sizeof (unsigned CHUNK));
+ }
+
+ /* Read this file's histogram and merge it into the total one. */
+
+ p=(unsigned CHUNK *)ck_malloc (nhist*sizeof (unsigned CHUNK));
+ ck_fread ((void *)p, sizeof (unsigned CHUNK), nhist, fp);
+ for (n=0; n<nhist; n++) {
+ tothist+=p[n];
+ histo[n]+=p[n];
+ if (debug&DB_GFILE) {
+ static ncol;
+
+ if (n==0) ncol=0;
+ if (histo[n]) {
+ fprintf (stderr, "s[%05d]=%-3d", n, histo[n]);
+ if (ncol++%10==9) fputc ('\n', stderr);
+ }
+ }
+ }
+ free ((void *)p);
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_GFILE, (""));
+
+ /* We've read in the histogram, now read in the function call data.
+ Loop, reading one call-graph edge from the file
+ and recording the edge in the graph. */
+
+ while (fread ((void *)&calltmp, sizeof (calltmp), 1, fp)==1) {
+ struct symlist *tmp;
+ struct mesym *s_fm, *s_to;
+
+ /* Find the calling and called functions's symbol entries. */
+
+ s_fm=val_to_sym (calltmp.from);
+ s_to=val_to_sym (calltmp.to);
+
+ if (!s_fm || !s_to) {
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_GFILE, ("unknown call %#lx to %#lx %d times.", calltmp.from, calltmp.to, calltmp.ncalls));
+ continue;
+ }
+
+ /* Updated total numbers of calls from this caller and to this callee. */
+
+ s_to->ncalled+=calltmp.ncalls;
+ s_fm->ncalls+=calltmp.ncalls;
+
+ /* Add these calls to the edge between them. */
+
+ add_to_lists (s_fm, s_to, calltmp.ncalls);
+
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE
+ (DB_GFILE, ("call %s (%#lx) to %s (%#lx) %ld times", s_fm->name,
+ calltmp.from, s_to->name, calltmp.to, calltmp.ncalls));
+ }
+
+ ck_fclose (fp);
+}
+
+/* Print one of those obnoxious and vaguely informative blurbs that we know
+ and love so well. Used to be, we'd print them out of a file, but nowaday
+ the blurb is encoded direcly into the program. Makes printing them
+ much faster. Also means bozo syswiz can't accidentally delete/move/etc the
+ blurb file on us. */
+
+void
+print_blurb FUN1(char *, blurb)
+{
+ if (! no_blurbs)
+ fputs (blurb, stdout);
+}
+
+
+/* Find the number of clock ticks/second by reading the kernel's memory.
+ This means that if /dev/kmem isn't readable, this program will have to run
+ set[ug]id to someone who can read the kernel. setgid is probably best. */
+
+long
+get_ticks FUN0()
+{
+ static struct nlist nl[2];
+ long ret;
+ FILE *fp;
+
+#ifdef USG
+#include <sys/types.h>
+#include <sys/param.h>
+ ret = HZ;
+#else
+ nl[0].n_un.n_name="_hz";
+ nlist ("/vmunix", &nl[0]);
+ if (nl[0].n_type==0)
+ fatal ("Can't find `%s' in namelist of /vmunix", nl[0].n_un.n_name);
+ fp=ck_fopen ("/dev/kmem", "r");
+ ck_fseek (fp, (long)nl[0].n_value, 0);
+ ck_fread ((void *)&ret, sizeof (ret), 1, fp);
+ fclose (fp); /* This really should be ck_fclose, but on some systems,
+ closing devices returns -1, errno=NOT_OWNER, which
+ really screws things up. . . */
+#endif
+ PRINT_OBNOXIOUS_DEBUG_MESSAGE (DB_MISC, ("get_ticks ()=%ld", ret));
+ return ret;
+}
+
+
+/* Record one -e, -E, -f or -F option in `filters', and check for conflicts.
+ All these options are recorded there for processing later
+ once the call-graph has been constructed. */
+
+void
+add_filter FUN2(char *, name, int, type)
+{
+ if (!filters) {
+ filters=(struct filter *)ck_malloc (sizeof (struct filter));
+ nfilters=1;
+ } else {
+ int n;
+
+ for (n=0; n<nfilters; n++) {
+ if (filters[n].name==name || !strcmp (filters[n].name, name))
+ fatal ("Conflicting options for function `%s'", name);
+ }
+ nfilters++;
+ filters=(struct filter *)ck_realloc ((void *)filters, sizeof (struct filter)*nfilters);
+ }
+ filters[nfilters-1].name=name;
+ filters[nfilters-1].type=type;
+}
+
+/* Data base associating stdio streams with the file names that are open. */
+
+struct file_to_name {
+ FILE *stream; /* A stdio stream */
+ char *name; /* The file name (malloc'd specially for this list) */
+ struct file_to_name *next;
+};
+
+struct file_to_name *files_to_names;
+
+/* Given a stdio stream, look it up in the data base and return
+ the file name. */
+
+char *
+stream_name FUN1(FILE *, stream)
+{
+ struct file_to_name *tail;
+
+ for (tail = files_to_names; tail; tail = tail->next)
+ if (tail->stream == stream)
+ return tail->name;
+
+ return "unknown file";
+}
+
+/* Open a file like `fopen', but report a fatal error if it fails;
+ if it succeeds, record the stream and filename in the data base of such. */
+
+FILE *
+ck_fopen FUN2(char *, name, char *, mode)
+{
+ FILE *stream;
+ int n;
+ struct file_to_name *new;
+
+ stream=fopen (name, mode);
+ if (stream==(FILE *)0)
+ fatal_io ("Couldn't open", name);
+
+ new = ck_malloc (sizeof (struct file_to_name));
+ new->name = ck_malloc (strlen (name) + 1);
+ strcpy (new->name, name);
+ new->stream = stream;
+ new->next = files_to_names;
+ files_to_names = new;
+ return stream;
+}
+
+/* Interfaces to various functions of stdio
+ which use the stream/filename database to print an error message
+ if the function gets an error. */
+
+void
+ck_fseek FUN3(FILE *, stream, long, i, int, w)
+{
+ if (fseek (stream, i, w)==-1)
+ fatal_io ("Couldn't lseek", stream_name (stream));
+}
+
+void
+ck_fread FUN4(void *, ptr, size_t, size, size_t, nmemb, FILE *, stream)
+{
+ if (fread (ptr, size, nmemb, stream)!=nmemb)
+ fatal_io ("Couldn't read", stream_name (stream));
+}
+
+void
+ck_fwrite FUN4(void *, ptr, size_t, size, size_t, nmemb, FILE *, stream)
+{
+ if (fwrite (ptr, size, nmemb, stream)!=nmemb)
+ fatal_io ("Couldn't write", stream_name (stream));
+}
+
+void
+ck_fclose FUN1(FILE *, stream)
+{
+ struct file_to_name *tail;
+
+ if(stream->_flag & _IOWRT)
+ fflush (stream);
+ if (ferror (stream))
+ fatal ("I/O error on `%s'", stream_name (stream));
+ if (fclose (stream)==EOF)
+ fatal_io ("Couldn't close", stream_name (stream));
+
+ if (files_to_names && files_to_names->stream == stream)
+ files_to_names = files_to_names->next;
+ else
+ for (tail = files_to_names; tail->next; tail = tail->next)
+ if (tail->next->stream == stream)
+ {
+ struct file_to_name *loser = tail->next;
+ tail->next = tail->next->next;
+ free (loser->name);
+ free (loser);
+ return;
+ }
+}
+
+/* Report a fatal error doing I/O, and exit.
+ PROBLEM is "Couldn't whatever" and NAME is the file name. */
+
+void
+fatal_io FUN2(char *, problem, char *, name)
+{
+ fprintf (stderr, "%s: %s %s:", myname, problem, name);
+ perror (0);
+ exit (1);
+}
+
+/* Report a fatal error and exit. Arguments like `printf'. */
+
+void
+fatal FUN1N(char *, s)
+{
+ va_list iggy;
+
+ var_start (iggy, s);
+ fprintf (stderr, "%s: ", myname);
+ vfprintf (stderr, s, iggy);
+ /* _doprnt (s, iggy, stderr); */
+ putc ('\n', stderr);
+ va_end (iggy);
+
+ exit (1);
+}
+
+/* Memory allocation functions. */
+
+/* This function is called just like `printf'
+ except that the output is put into a new string
+ allocated with `malloc'.
+ Returns the address of the string. The caller must free the string. */
+
+char *
+mk_sprintf FUN1N(char *, str)
+{
+ char tmpbuf[2048];
+ char *ret;
+ va_list iggy;
+
+ var_start (iggy, str);
+ vsprintf (tmpbuf, str, iggy);
+ va_end (iggy);
+
+ ret=ck_malloc (strlen (tmpbuf)+1);
+ strcpy (ret, tmpbuf);
+ return ret;
+}
+
+/* Encapsulations of `malloc', `calloc' and `realloc'
+ that cause fatal errors if there is not enough memory. */
+
+void *
+ck_malloc FUN1(size_t, size)
+{
+ void *ret;
+ void *malloc ();
+
+ ret=malloc (size);
+ if (ret==(void *)0)
+ fatal ("Virtual memory exhausted");
+ return ret;
+}
+
+void *
+ck_calloc FUN2(size_t, nmemb, size_t, size)
+{
+ void *ret;
+ void *calloc ();
+
+ ret=calloc (nmemb, size);
+ if (ret==(void *)0)
+ fatal ("Virtual memory exhausted");
+ return ret;
+}
+
+void *
+ck_realloc FUN2(void *, ptr, size_t, size)
+{
+ void *ret;
+ void *realloc ();
+
+ ret=realloc (ptr, size);
+ if (ret==(void *)0)
+ fatal ("Virtual memory exhausted");
+ return ret;
+}
+
+/* Implement an expandable fifo buffer of pointers
+ (we don't care what they point to)
+ which is used for conducting breadth-first tree walks in the call graph.
+
+ The fifo is implemented as a ring buffer. */
+
+struct ring_buf
+{
+ void **buf;
+ int size;
+ void **push_to_here;
+ void **pop_frm_here;
+};
+
+void *
+init_ring_buffer FUN0()
+{
+ struct ring_buf *ret;
+
+ ret=ck_malloc (sizeof (struct ring_buf));
+ ret->size=40;
+ ret->buf=(void **)ck_calloc (ret->size, sizeof (void **));
+ ret->push_to_here=ret->buf;
+ ret->pop_frm_here=ret->buf;
+ return ret;
+}
+
+void
+push_ring_buffer FUN2(void *, b, void *, n)
+{
+ struct ring_buf *buf;
+
+ buf=(struct ring_buf *)b;
+ if (buf->push_to_here+1==buf->pop_frm_here
+ || (buf->pop_frm_here==buf->buf
+ && buf->push_to_here==buf->buf+(buf->size-1))) {
+ int f, t, from_num;
+
+ f=buf->pop_frm_here-buf->buf;
+ t=buf->push_to_here-buf->buf;
+ from_num=buf->size-f;
+
+ buf->size*=2;
+ buf->buf=ck_realloc ((void *)buf->buf, buf->size*sizeof (void **));
+ if (t==0) {
+ buf->push_to_here=buf->buf+f+from_num;
+ buf->pop_frm_here=buf->buf+f;
+ } else if (t>f) {
+ buf->push_to_here=buf->buf+t;
+ buf->pop_frm_here=buf->buf+f;
+ } else {
+ buf->push_to_here=buf->buf+t;
+ buf->pop_frm_here=buf->buf+(buf->size-from_num);
+ if (from_num)
+ bcopy (buf->buf+f,
+ buf->pop_frm_here,
+ from_num*sizeof (void **));
+ }
+ }
+ *(buf->push_to_here)=n;
+ buf->push_to_here++;
+ if (buf->push_to_here==buf->buf+buf->size)
+ buf->push_to_here=buf->buf;
+}
+
+void *
+pop_ring_buffer FUN1(void *, b)
+{
+ struct ring_buf *buf;
+ void *ret;
+
+ buf=(struct ring_buf *)b;
+ ret= *(buf->pop_frm_here);
+ buf->pop_frm_here++;
+ if (buf->pop_frm_here==buf->buf+buf->size)
+ buf->pop_frm_here=buf->buf;
+ return ret;
+}
+
+int
+ring_buffer_isnt_empty FUN1(void *, b)
+{
+ struct ring_buf *buf;
+
+ buf=(struct ring_buf *)b;
+ return buf->pop_frm_here!=buf->push_to_here;
+}
+
+void
+flush_ring_buffer FUN1(void *, b)
+{
+ struct ring_buf *buf;
+
+ buf=(struct ring_buf *)b;
+ free (buf->buf);
+ free (buf);
+}
+
+
+/* Functions to print debugging messages. */
+
+/* Like vprintf but print an extra newline at the end. */
+
+void
+dbgprintf FUN1N(char *, s)
+{
+ va_list iggy;
+
+ var_start (iggy, s);
+ vfprintf (stderr, s, iggy);
+ putc ('\n', stderr);
+ va_end (iggy);
+}
+
+/* Print out the entire symbol table */
+
+void
+dumpsyms FUN0()
+{
+ struct mesym *np, *endp;
+ struct symlist *sy;
+ int n;
+ char buf[80];
+
+ n=0;
+ for (np=syms, endp= &syms[nsym]; np<endp; np++) {
+ char *demangled = cplus_demangle (np->name);
+ char *name = demangled == NULL ? np->name : demangled;
+
+ sprintf (buf, "%-15s %#6lx %d %2d.%2d[%d]",
+ name, np->value, np->histo, np->ncalled, np->ncalls, np->cycnum);
+ if (demangled != NULL)
+ free (demangled);
+
+ if (n==0) {
+ printf ("%-35s", buf);
+ n++;
+ } else {
+ printf ("%s\n", buf);
+ n=0;
+ }
+ }
+ putchar ('\n');
+ if (n==0) putchar ('\n');
+}
+
+/* Print out the call tree vector */
+void
+dumpfuns FUN0()
+{
+ struct mesym *np;
+ struct symlist *sy;
+ int n;
+
+ for (n=0; n<number_of_functions_in_call_tree; n++) {
+ np=functions_in_call_tree[n];
+ fprint_name (stdout, np->name);
+ printf ("{%d}[%d] ", np->cycnum, np->ncalls);
+ /* for (sy=np->called; sy; sy=sy->next)
+ printf ("%s{%d}(%d) ", sy->sym->name, sy->sym->cycnum, sy->ncalls);
+ putchar ('\n'); */
+ }
+}
+
+/* JF someone put this stuff in the file before all the prototyes et all.
+ I moved them here where they belong */
+
+/* Like malloc but abort if out of memory. */
+void *
+xmalloc FUN1(size_t, size)
+{
+ return ck_malloc(size);
+}
+
+/* Like realloc but abort if out of memory. */
+void *
+xrealloc FUN2(void *, p, size_t, size)
+{
+ return ck_realloc(p,size);
+}
+
+/* Print NAME on STREAM, demangling if necessary. */
+void
+fprint_name FUN2(FILE *, stream, char *, name)
+{
+ char *demangled = cplus_demangle (name);
+ if (demangled == NULL)
+ fputs (name, stream);
+ else
+ {
+ fputs (demangled, stream);
+ free (demangled);
+ }
+}
diff --git a/binutils-1.9/gprof.texinfo b/binutils-1.9/gprof.texinfo
new file mode 100644
index 0000000..a4161ed
--- /dev/null
+++ b/binutils-1.9/gprof.texinfo
@@ -0,0 +1,943 @@
+\input texinfo @c -*-texinfo-*-
+
+@setfilename gprof.info
+@settitle gprof
+@setchapternewpage odd
+@ifinfo
+This file documents the gprof profiler of the GNU system.
+
+Copyright (C) 1988 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@iftex
+@finalout
+@end iftex
+
+@titlepage
+@sp 11
+@center @titlefont{gprof}
+@sp 1
+@center The GNU Profiler
+@sp 2
+@center Jay Fenlason and Richard Stallman
+@sp 1
+@center @today
+@sp 3
+This manual describes the GNU profiler, @code{gprof}, and how you can use
+it to determine which parts of a program are taking most of the execution
+time. We assume that you know how to write, compile, and execute programs.
+GNU @code{gprof} was written by Jay Fenlason.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1988 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the same conditions as for modified versions.
+
+@end titlepage
+
+@ifinfo
+@node Top, Why, Top, (dir)
+@ichapter Profiling a Program: Where Does It Spend Its Time?
+
+This manual describes the GNU profiler @code{gprof}, and how you can use it
+to determine which parts of a program are taking most of the execution
+time. We assume that you know how to write, compile, and execute programs.
+GNU @code{gprof} was written by Jay Fenlason.
+
+@menu
+* Why:: What profiling means, and why it is useful.
+* Compiling:: How to compile your program for profiling.
+* Executing:: How to execute your program to generate the
+ profile data file @file{gmon.out}.
+* Analyzing:: How to run @code{gprof}, and how to specify
+ options for it.
+
+* Flat Profile:: The flat profile shows how much time was spent
+ executing directly in each function.
+* Call Graph:: The call graph shows which functions called which
+ others, and how much time each function used
+ when its subroutine calls are included.
+
+* Implementation:: How the profile data is recorded and written.
+* Sampling Error:: Statistical margins of error.
+ How to accumulate data from several runs
+ to make it more accurate.
+
+* Assumptions:: Some of @code{gprof}'s measurements are based
+ on assumptions about your program
+ that could be very wrong.
+
+* Incompatibilities:: (between GNU @code{gprof} and Unix @code{gprof}.)
+@end menu
+@end ifinfo
+
+@node Why, Compiling, Top, Top
+@chapter Why Profile
+
+Profiling allows you to learn where your program spent its time and which
+functions called which other functions while it was executing. This
+information can show you which pieces of your program are slower than you
+expected, and might be candidates for rewriting to make your program
+execute faster. It can also tell you which functions are being called more
+or less often than you expected. This may help you spot bugs that had
+otherwise been unnoticed.
+
+Since the profiler uses information collected during the actual execution
+of your program, it can be used on programs that are too large or too
+complex to analyze by reading the source. However, how your program is run
+will affect the information that shows up in the profile data. If you
+don't use some feature of your program while it is being profiled, no
+profile information will be generated for that feature.
+
+Profiling has several steps:
+
+@itemize @bullet
+@item
+You must compile and link your program with profiling enabled.
+@xref{Compiling}.
+
+@item
+You must execute your program to generate a profile data file.
+@xref{Executing}.
+
+@item
+You must run @code{gprof} to analyze the profile data.
+@xref{Analyzing}.
+@end itemize
+
+The next three chapters explain these steps in greater detail.
+
+The result of the analysis is a file containing two tables, the
+@dfn{flat profile} and the @dfn{call graph} (plus blurbs which briefly
+explain the contents of these tables).
+
+The flat profile shows how much time your program spent in each function,
+and how many times that function was called. If you simply want to know
+which functions burn most of the cycles, it is stated concisely here.
+@xref{Flat Profile}.
+
+The call graph shows, for each function, which functions called it, which
+other functions it called, and how many times. There is also an estimate
+of how much time was spent in the subroutines of each function. This can
+suggest places where you might try to eliminate function calls that use a
+lot of time. @xref{Call Graph}.
+
+@node Compiling, Executing, Why, Top
+@chapter Compiling a Program for Profiling
+
+The first step in generating profile information for your program is
+to compile and link it with profiling enabled.
+
+To compile a source file for profiling, specify the @samp{-pg} option when
+you run the compiler. (This is in addition to the options you normally
+use.)
+
+To link the program for profiling, if you use a compiler such as @code{cc}
+to do the linking, simply specify @samp{-pg} in addition to your usual
+options. The same option, @samp{-pg}, alters either compilation or linking
+to do what is necessary for profiling. Here are examples:
+
+@example
+cc -g -c myprog.c utils.c -pg
+cc -o myprog myprog.o utils.o -pg
+@end example
+
+The @samp{-pg} option also works with a command that both compiles and links:
+
+@example
+cc -o myprog myprog.c utils.c -g -pg
+@end example
+
+If you run the linker @code{ld} directly instead of through a compiler such
+as @code{cc}, you must specify the profiling startup file
+@file{/lib/gcrt0.o} as the first input file instead of the usual startup
+file @file{/lib/crt0.o}. In addition, you would probably want to specify
+the profiling C library, @file{/usr/lib/libc_p.a}, by writing @samp{-lc_p}
+instead of the usual @samp{-lc}. This is not absolutely necessary, but doing
+this gives you number-of-calls information for standard library functions such
+as @code{read} and @code{open}. For example:
+
+@example
+ld -o myprog /lib/gcrt0.o myprog.o utils.o -lc_p
+@end example
+
+If you compile only some of the modules of the program with @samp{-pg}, you
+can still profile the program, but you won't get complete information about
+the modules that were compiled without @samp{-pg}. The only information
+you get for the functions in those modules is the total time spent in them;
+there is no record of how many times they were called, or from where. This
+will not affect the flat profile (except that the @code{calls} field for
+the functions will be blank), but will greatly reduce the usefulness of the
+call graph.
+
+So far GNU @code{gprof} has been tested only with C programs, but it ought
+to work with any language in which programs are compiled and linked to form
+executable files. If it does not, please let us know.
+
+@node Executing, Analyzing, Compiling, Top
+@chapter Executing the Program to Generate Profile Data
+
+Once the program is compiled for profiling, you must run it in order to
+generate the information that @code{gprof} needs. Simply run the program
+as usual, using the normal arguments, file names, etc. The program should
+run normally, producing the same output as usual. It will, however, run
+somewhat slower than normal because of the time spent collecting and the
+writing the profile data.
+
+The way you run the program---the arguments and input that you give
+it---may have a dramatic effect on what the profile information shows. The
+profile data will describe the parts of the program that were activated for
+the particular input you use. For example, if the first command you give
+to your program is to quit, the profile data will show the time used in
+initialization and in cleanup, but not much else.
+
+You program will write the profile data into a file called @file{gmon.out}
+just before exiting. If there is already a file called @file{gmon.out},
+its contents are overwritten. There is currently no way to tell the
+program to write the profile data under a different name, but you can rename
+the file afterward if you are concerned that it may be overwritten.
+
+In order to write the @file{gmon.out} file properly, your program must exit
+normally: by returning from @code{main} or by calling @code{exit}. Calling
+the low-level function @code{_exit} does not write the profile data, and
+neither does abnormal termination due to an unhandled signal.
+
+The @file{gmon.out} file is written in the program's @emph{current working
+directory} at the time it exits. This means that if your program calls
+@code{chdir}, the @file{gmon.out} file will be left in the last directory
+your program @code{chdir}'d to. If you don't have permission to write in
+this directory, the file is not written. You may get a confusing error
+message if this happens. (We have not yet replaced the part of Unix
+responsible for this; when we do, we will make the error message
+comprehensible.)
+
+@node Analyzing, Flat Profile, Executing, Top
+@chapter Analyzing the Profile Data: @code{gprof} Command Summary
+
+After you have a profile data file @file{gmon.out}, you can run @code{gprof}
+to interpret the information in it. The @code{gprof} program prints a
+flat profile and a call graph on standard output. Typically you would
+redirect the output of @code{gprof} into a file with @samp{>}.
+
+You run @code{gprof} like this:
+
+@example
+@code{gprof} @var{options} [@var{executable-file} [@var{profile-data-files}@dots{}]] [> @var{outfile}]
+@end example
+
+@noindent
+Here square-brackets indicate optional arguments.
+
+If you omit the executable file name, the file @file{a.out} is used. If
+you give no profile data file name, the file @file{gmon.out} is used. If
+any file is not in the proper format, or if the profile data file does not
+appear to belong to the executable file, an error message is printed.
+
+You can give more than one profile data file by entering all their names
+after the executable file name; then the statistics in all the data files
+are summed together.
+
+The following options may be used to selectively include or exclude
+functions in the output:
+
+@table @code
+@item -a
+The @code{-a} option causes @code{gprof} to ignore static (private)
+functions. (These are functions whose names are not listed as global,
+and which are not visible outside the file/function/block where they
+were defined.) Time spent in these functions, calls to/from them,
+etc, will all be attributed to the function that was loaded directly
+before it in the executable file. This is compatible with Unix
+@code{gprof}, but a bad idea. This option affects both the flat
+profile and the call graph.
+
+@item -e @var{function_name}
+The @code{-e @var{function}} option tells @code{gprof} to not print
+information about the function (and its children@dots{}) in the call
+graph. The function will still be listed as a child of any functions
+that call it, but its index number will be shown as @samp{[not
+printed]}.
+
+@item -E @var{function_name}
+The @code{-E @var{function}} option works like the @code{-e} option,
+but time spent in the function (and children who were not called from
+anywhere else), will not be used to compute the percentages-of-time
+for the call graph.
+
+@item -f @var{function_name}
+The @code{-f @var{function}} option causes @code{gprof} to limit the
+call graph to the function and its children (and their
+children@dots{}).
+
+@item -F @var{function_name}
+The @code{-F @var{function}} option works like the @code{-f} option,
+but only time spent in the function and its children (and their
+children@dots{}) will be used to determine total-time and
+percentages-of-time for the call graph.
+
+@item -z
+If you give the @code{-z} option, @code{gprof} will mention all
+functions in the flat profile, even those that were never called, and
+that had no time spent in them.
+@end table
+
+The order of these options does not matter.
+
+Note that only one function can be specified with each @code{-e},
+@code{-E}, @code{-f} or @code{-F} option. To specify more than one
+function, use multiple options. For example, this command:
+
+@example
+gprof -e boring -f foo -f bar myprogram > gprof.output
+@end example
+
+@noindent
+lists in the call graph all functions that were reached from either
+@code{foo} or @code{bar} and were not reachable from @code{boring}.
+
+There are two other useful @code{gprof} options:
+
+@table @code
+@item -b
+If the @code{-b} option is given, @code{gprof} doesn't print the
+verbose blurbs that try to explain the meaning of all of the fields in
+the tables. This is useful if you intend to print out the output, or
+are tired of seeing the blurbs.
+
+@item -s
+The @code{-s} option causes @code{gprof} to summarize the information
+in the profile data files it read in, and write out a profile data
+file called @file{gmon.sum}, which contains all the information from
+the profile data files that @code{gprof} read in. The file @file{gmon.sum}
+may be one of the specified input files; the effect of this is to
+merge the data in the other input files into @file{gmon.sum}.
+@xref{Sampling Error}.
+
+Eventually you can run @code{gprof} again without @samp{-s} to analyze the
+cumulative data in the file @file{gmon.sum}.
+@end table
+
+@node Flat Profile, Call Graph, Analyzing, Top
+@chapter How to Understand the Flat Profile
+@cindex flat profile
+
+The @dfn{flat profile} shows the total amount of time your program
+spent executing each function. Unless the @samp{-z} option is given,
+functions with no apparent time spent in them, and no apparent calls
+to them, are not mentioned. Note that if a function was not compiled
+for profiling, and didn't run long enough to show up on the program
+counter histogram, it will be indistinguishable from a function that
+was never called.
+@c ???
+
+Here is a sample flat profile for a small program:
+
+@example
+Each sample counts as 0.01 seconds.
+
+% time seconds cumsec calls function
+ 79.17 0.19 0.19 6 a
+ 16.67 0.04 0.23 1 main
+ 4.17 0.01 0.24 mcount
+ 0.00 0 0.24 1 profil
+@end example
+
+@noindent
+The functions are sorted by decreasing run-time spent in them. The
+functions @code{mcount} and @code{profil} are part of the profiling
+aparatus and appear in every flat profile; their time gives a measure of
+the amount of overhead due to profiling. (These internal functions are
+omitted from the call graph.)
+
+The sampling period estimates the margin of error in each of the time
+figures. A time figure that is not much larger than this is not reliable.
+In this example, the @code{seconds} field for @code{mcount} might well be 0
+or 0.02 in another run. @xref{Sampling Error}, for a complete discussion.
+
+Here is what the fields in each line mean:
+
+@table @code
+@item % time
+This is the percentage of the total execution time your program spent
+in this function. These should all add up to 100%.
+
+@item seconds
+This is the total number of seconds the computer spent executing the
+user code of this function.
+
+@item cumsec
+This is the cumulative total number of seconds the computer spent
+executing this functions, plus the time spent in all the functions
+above this one in this table.
+
+@item calls
+This is the total number of times the function was called. If the
+function was never called, or the number of times it was called cannot
+be determined (probably because the function was not compiled with
+profiling enabled), the @dfn{calls} field is blank.
+
+@item function
+This is the name of the function.
+@end table
+
+@node Call Graph, Implementation, Flat Profile, Top
+@chapter How to Read the Call Graph
+
+@cindex call graph
+The @dfn{call graph} shows how much time was spent in each function
+and its children. From this information, you can find functions that,
+while they themselves may not have used much time, called other
+functions that did use unusual amounts of time.
+
+Here is a sample call from a small program. This call came from the
+same @code{gprof} run as the flat profile example in the previous
+chapter.
+
+@example
+index % time self children called name
+ <spontaneous>
+[1] 100.00 0 0.23 0 start [1]
+ 0.04 0.19 1/1 main [2]
+----------------------------------------
+ 0.04 0.19 1/1 start [1]
+[2] 100.00 0.04 0.19 1 main [2]
+ 0.19 0 1/1 a [3]
+----------------------------------------
+ 0.19 0 1/1 main [2]
+[3] 82.61 0.19 0 1+5 a [3]
+----------------------------------------
+@end example
+
+The lines full of dashes divide this table into @dfn{entries}, one for each
+function. Each entry has one or more lines.
+
+In each entry, the primary line is the one that starts with an index number
+in square brackets. The end of this line says which function the entry is
+for. The preceding lines in the entry describe the callers of this
+function and the following lines describe its subroutines (also called
+@dfn{children} when we speak of the call graph).
+
+The entries are sorted by time spent in the function and its subroutines.
+
+The internal profiling functions @code{mcount} and @code{profil}
+(@pxref{Flat Profile}) are never mentioned in the call graph.
+
+@menu
+* Primary:: Details of the primary line's contents.
+* Callers:: Details of caller-lines' contents.
+* Subroutines:: Details of subroutine-lines' contents.
+* Cycles:: When there are cycles of recursion,
+ such as @code{a} calls @code{b} calls @code{a}@dots{}
+@end menu
+
+@node Primary, Callers, Call Graph, Call Graph
+@section The Primary Line
+
+The @dfn{primary line} in a call graph entry is the line that
+describes the function which the entry is about and gives the overall
+statistics for this function.
+
+For reference, we repeat the primary line from the entry for function
+@code{a} in our main example, together with the heading line that shows the
+names of the fields:
+
+@example
+index % time self children called name
+@dots{}
+[3] 82.61 0.19 0 1+5 a [3]
+@end example
+
+Here is what the fields in the primary line mean:
+
+@table @code
+@item index
+Entries are numbered with consecutive integers. Each function
+therefore has an index number, which appears at the beginning of its
+primary line.
+
+Each cross-reference to a function, as a caller or subroutine of
+another, gives its index number as well as its name. The index number
+guides you if you wish to look for the entry for that function.
+
+@item % time
+This is the percentage of the total time that was spent in this
+function, including time spent in subroutines called from this
+function.
+
+The time spent in this function is counted again for the callers of
+this function. Therefore, adding up these percentages is meaningless.
+
+@item self
+This is the total amount of time spent in this function. This
+should be identical to the number printed in the @code{seconds} field
+for this function in the flat profile.
+
+@item children
+This is the total amount of time spent in the subroutine calls made by
+this function. This should be equal to the sum of all the @code{self}
+and @code{children} entries of the children listed directly below this
+function.
+
+@item called
+This is the number of times the function was called.
+
+If the function called itself recursively, there are two numbers,
+separated by a @samp{+}. The first number counts non-recursive calls,
+and the second counts recursive calls.
+
+In the example above, the function @code{a} called itself five times,
+and was called once from @code{main}.
+
+@item name
+This is the name of the current function. The index number is
+repeated after it.
+
+If the function is part of a cycle of recursion, the cycle number is
+printed between the function's name and the index number
+(@pxref{Cycles}). For example, if function @code{gnurr} is part of
+cycle number one, and has index number twelve, its primary line would
+be end like this:
+
+@example
+gnurr <cycle 1> [12]
+@end example
+@end table
+
+@node Callers, Subroutines, Primary, Call Graph
+@section Lines for a Function's Callers
+
+A function's entry has a line for each function it was called by.
+These lines' fields correspond to the fields of the primary line, but
+their meanings are different because of the difference in context.
+
+For reference, we repeat two lines from the entry for the function
+@code{a}, the primary line and one caller-line preceding it, together
+with the heading line that shows the names of the fields:
+
+@example
+index % time self children called name
+@dots{}
+ 0.19 0 1/1 main [2]
+[3] 82.61 0.19 0 1+5 a [3]
+@end example
+
+Here are the meanings of the fields in the caller-line for @code{a}
+called from @code{main}:
+
+@table @code
+@item self
+An estimate of the amount of time spent in @code{a} itself when it was
+called from @code{main}.
+
+@item children
+An estimate of the amount of time spent in @code{a}'s subroutines when
+@code{a} was called from @code{main}.
+
+The sum of the @code{self} and @code{children} fields is an estimate
+of the amount of time spent within calls to @code{a} from @code{main}.
+
+@item called
+Two numbers: the number of times @code{a} was called from @code{main},
+followed by the total number of nonrecursive calls to @code{a} from
+all its callers.
+
+@item name and index number
+The name of the caller of @code{a} to which this line applies,
+followed by the caller's index number.
+
+Not all functions have entries in the call graph; some
+options to @code{gprof} request the omission of certain functions.
+When a caller has no entry of its own, it still has caller-lines
+in the entries of the functions it calls. Since this caller
+has no index number, the string @samp{[not printed]} is used
+instead of one.
+
+If the caller is part of a recursion cycle, the cycle number is
+printed between the name and the index number.
+@end table
+
+If the identity of the callers of a function cannot be determined, a
+dummy caller-line is printed which has @samp{<spontaneous>} as the
+``caller's name'' and all other fields blank. This can happen for
+signal handlers.
+@c What if some calls have determinable callers' names but not all?
+
+@node Subroutines, Cycles, Callers, Call Graph
+@section Lines for a Function's Subroutines
+
+A function's entry has a line for each of its subroutines---in other
+words, a line for each other function that it called. These lines'
+fields correspond to the fields of the primary line, but their meanings
+are different because of the difference in context.
+
+For reference, we repeat two lines from the entry for the function
+@code{main}, the primary line and a line for a subroutine, together
+with the heading line that shows the names of the fields:
+
+@example
+index % time self children called name
+@dots{}
+[2] 100.00 0.04 0.19 1 main [2]
+ 0.19 0 1/1 a [3]
+@end example
+
+Here are the meanings of the fields in the subroutine-line for @code{main}
+calling @code{a}:
+
+@table @code
+@item self
+An estimate of the amount of time spent directly within @code{a}
+when @code{a} was called from @code{main}.
+
+@item children
+An estimate of the amount of time spent in subroutines of @code{a}
+when @code{a} was called from @code{main}.
+
+The sum of the @code{self} and @code{children} fields is an estimate
+of the total time spent in calls to @code{a} from @code{main}.
+
+@item called
+Two numbers, the number of calls to @code{a} from @code{main}
+followed by the total number of nonrecursive calls to @code{a}.
+
+@item name
+The name of the subroutine of @code{a} to which this line applies,
+followed by the subroutine's index number. If the subroutine is
+a function omitted from the call graph, it has no index number,
+so @samp{[not printed]} appears instead.
+
+If the caller is part of a recursion cycle, the cycle number is
+printed between the name and the index number.
+@end table
+
+@node Cycles,, Subroutines, Call Graph
+@section How Mutually Recursive Functions Are Described
+@cindex cycle
+@cindex recursion cycle
+
+The graph may be complicated by the presence of @dfn{cycles of
+recursion} in the call graph. A cycle exists if a function calls
+another function that (directly or indirectly) calls (or appears to
+call) the original function. For example: if @code{a} calls @code{b},
+and @code{b} calls @code{a}, then @code{a} and @code{b} form a cycle.
+
+Whenever there are call-paths both ways between a pair of functions, they
+belong to the same cycle. If @code{a} and @code{b} call each other and
+@code{b} and @code{c} call each other, all three make one cycle. Note that
+even if @code{b} only calls @code{a} if it was not called from @code{a},
+@code{gprof} cannot determine this, so @code{a} and @code{b} are still
+considered a cycle.
+
+The cycles are numbered with consecutive integers. When a function
+belongs to a cycle, each time the function name appears in the call graph
+it is followed by @samp{<cycle @var{number}>}.
+
+The reason cycles matter is that they make the time values in the call
+graph paradoxical. The ``time spent in children'' of @code{a} should
+include the time spent in its subroutine @code{b} and in @code{b}'s
+subroutines---but one of @code{b}'s subroutines is @code{a}! How much of
+@code{a}'s time should be included in the children of @code{a}, when
+@code{a} is indirectly recursive?
+
+The way @code{gprof} resolves this paradox is by creating a single entry
+for the cycle as a whole. The primary line of this entry describes the
+total time spent directly in the functions of the cycle. The
+``subroutines'' of the cycle are the individual functions of the cycle, and
+all other functions that were called directly by them. The ``callers'' of
+the cycle are the functions, outside the cycle, that called functions in
+the cycle.
+
+Here is a portion of the call graph which shows a cycle containing
+functions @code{a} and @code{b}. The cycle was entered by a call to
+@code{a} from @code{main}; both @code{a} and @code{b} called @code{c}.@refill
+
+@example
+index % time self children called name
+----------------------------------------
+ 1.77 0 1/1 main [2]
+[3] 91.71 1.77 0 1+5 <cycle 1 as a whole> [3]
+ 1.02 0 3 b <cycle 1> [4]
+ 0.75 0 2 a <cycle 1> [5]
+----------------------------------------
+ 3 a <cycle 1> [5]
+[4] 52.85 1.02 0 0 b <cycle 1> [4]
+ 2 a <cycle 1> [5]
+ 0 0 3/6 c [6]
+----------------------------------------
+ 1.77 0 1/1 main [2]
+ 2 b <cycle 1> [4]
+[5] 38.86 0.75 0 1 a <cycle 1> [5]
+ 3 b <cycle 1> [4]
+ 0 0 3/6 c [6]
+----------------------------------------
+@end example
+
+@noindent
+(The entire call graph for this program contains in addition an entry for
+@code{main}, which calls @code{a}, and an entry for @code{c}, with callers
+@code{a} and @code{b}.)
+
+@example
+index % time self children called name
+ <spontaneous>
+[1] 100.00 0 1.93 0 start [1]
+ 0.16 1.77 1/1 main [2]
+----------------------------------------
+ 0.16 1.77 1/1 start [1]
+[2] 100.00 0.16 1.77 1 main [2]
+ 1.77 0 1/1 a <cycle 1> [5]
+----------------------------------------
+ 1.77 0 1/1 main [2]
+[3] 91.71 1.77 0 1+5 <cycle 1 as a whole> [3]
+ 1.02 0 3 b <cycle 1> [4]
+ 0.75 0 2 a <cycle 1> [5]
+ 0 0 6/6 c [6]
+----------------------------------------
+ 3 a <cycle 1> [5]
+[4] 52.85 1.02 0 0 b <cycle 1> [4]
+ 2 a <cycle 1> [5]
+ 0 0 3/6 c [6]
+----------------------------------------
+ 1.77 0 1/1 main [2]
+ 2 b <cycle 1> [4]
+[5] 38.86 0.75 0 1 a <cycle 1> [5]
+ 3 b <cycle 1> [4]
+ 0 0 3/6 c [6]
+----------------------------------------
+ 0 0 3/6 b <cycle 1> [4]
+ 0 0 3/6 a <cycle 1> [5]
+[6] 0.00 0 0 6 c [6]
+----------------------------------------
+@end example
+
+The @code{self} field of the cycle's primary line is the total time
+spent in all the functions of the cycle. It equals the sum of the
+@code{self} fields for the individual functions in the cycle, found
+in the entry in the subroutine lines for these functions.
+
+The @code{children} fields of the cycle's primary line and subroutine lines
+count only subroutines outside the cycle. Even though @code{a} calls
+@code{b}, the time spent in those calls to @code{b} is not counted in
+@code{a}'s @code{children} time. Thus, we do not encounter the problem of
+what to do when the time in those calls to @code{b} includes indirect
+recursive calls back to @code{a}.
+
+The @code{children} field of a caller-line in the cycle's entry estimates
+the amount of time spent @emph{in the whole cycle}, and its other
+subroutines, on the times when that caller called a function in the cycle.
+
+The @code{calls} field in the primary line for the cycle has two numbers:
+first, the number of times functions in the cycle were called by functions
+outside the cycle; second, the number of times they were called by
+functions in the cycle (including times when a function in the cycle calls
+itself). This is a generalization of the usual split into nonrecursive and
+recursive calls.
+
+The @code{calls} field of a subroutine-line for a cycle member in the
+cycle's entry says how many time that function was called from functions in
+the cycle. The total of all these is the second number in the primary line's
+@code{calls} field.
+
+In the individual entry for a function in a cycle, the other functions in
+the same cycle can appear as subroutines and as callers. These lines show
+how many times each function in the cycle called or was called from each other
+function in the cycle. The @code{self} and @code{children} fields in these
+lines are blank because of the difficulty of defining meanings for them
+when recursion is going on.
+
+@node Implementation, Sampling Error, Call Graph, Top
+@chapter Implementation of Profiling
+
+Profiling works by changing how every function in your program is compiled
+so that when it is called, it will stash away some information about where
+it was called from. From this, the profiler can figure out what function
+called it, and can count how many times it was called. This change is made
+by the compiler when your program is compiled with the @samp{-pg} option.
+
+Profiling also involves watching your program as it runs, and keeping a
+histogram of where the program counter happens to be every now and then.
+Typically the program counter is looked at around 100 times per second of
+run time, but the exact frequency may vary from system to system.
+
+A special startup routine allocates memory for the histogram and sets up a
+clock signal handler to make entries in it. Use of this special startup
+routine is one of the effects of using @samp{cc -pg} to link. The startup
+file also includes an @code{exit} function which is responsible for writing
+the file @file{gmon.out}.
+
+Number-of-calls information for library routines is collected by using a
+special version of the C library. The programs in it are the same as in
+the usual C library, but they were compiled with @samp{-pg}. If you link
+your program with @samp{cc -pg}, it automatically uses the profiling
+version of the library.
+
+The output from @code{gprof} gives no indication of parts of your program that
+are limited by I/O or swapping bandwidth. This is because samples of the
+program counter are taken at fixed intervals of run time. Therefore, the
+time measurements in @code{gprof} output say nothing about time that your
+program was not running. For example, a part of the program that creates
+so much data that it cannot all fit in physical memory at once may run very
+slowly due to thrashing, but @code{gprof} will say it uses little time. On
+the other hand, sampling by run time has the advantage that the amount of
+load due to other users won't directly affect the output you get.
+
+@node Sampling Error, Assumptions, Implementation, Top
+@chapter Statistical Inaccuracy of @code{gprof} Output
+
+The run-time figures that @code{gprof} gives you are based on a sampling
+process, so they are subject to statistical inaccuracy. If a function runs
+only a small amount of time, so that on the average the sampling process
+ought to catch that function in the act only once, there is a pretty good
+chance it will actually find that function zero times, or twice.
+
+By contrast, the number-of-calls figures are derived by counting, not
+sampling. They are completely accurate and will not vary from run to run
+if your program is deterministic.
+
+The @dfn{sampling period} that is printed at the beginning of the flat
+profile says how often samples are taken. The rule of thumb is that a
+run-time figure is accurate if it is considerably bigger than the sampling
+period.
+
+The actual amount of error is usually more than one sampling period. In
+fact, if a value is @var{n} times the sampling period, the @emph{expected}
+error in it is the square-root of @var{n} sampling periods. If the
+sampling period is 0.01 seconds and @code{foo}'s run-time is 1 second, the
+expected error in @code{foo}'s run-time is 0.1 seconds. It is likely to
+vary this much @emph{on the average} from one profiling run to the next.
+(@emph{Sometimes} it will vary more.)
+
+This does not mean that a small run-time figure is devoid of information.
+If the program's @emph{total} run-time is large, a small run-time for one
+function does tell you that that function used an insignificant fraction of
+the whole program's time. Usually this means it is not worth optimizing.
+
+One way to get more accuracy is to give your program more (but similar)
+input data so it will take longer. Another way is to combine the data from
+several runs, using the @samp{-s} option of @code{gprof}. Here is how:
+
+@enumerate
+@item
+Run your program once.
+
+@item
+Issue the command @samp{mv gmon.out gmon.sum}.
+
+@item
+Run your program again, the same as before.
+
+@item
+Merge the new data in @file{gmon.out} into @file{gmon.sum} with this command:
+
+@example
+gprof -s @var{executable-file} gmon.out gmon.sum
+@end example
+
+@item
+Repeat the last two steps as often as you wish.
+
+@item
+Analyze the cumulative data using this command:
+
+@example
+gprof @var{executable-file} gmon.sum > @var{output-file}
+@end example
+@end enumerate
+
+@node Assumptions, Incompatibilities, Sampling Error, Top
+@chapter Estimating @code{children} Times Uses an Assumption
+
+Some of the figures in the call graph are estimates---for example, the
+@code{children} time values and all the the time figures in caller and
+subroutine lines.
+
+There is no direct information about these measurements in the profile
+data itself. Instead, @code{gprof} estimates them by making an assumption
+about your program that might or might not be true.
+
+The assumption made is that the average time spent in each call to any
+function @code{foo} is not correlated with who called @code{foo}. If
+@code{foo} used 5 seconds in all, and 2/5 of the calls to @code{foo} came
+from @code{a}, then @code{foo} contributes 2 seconds to @code{a}'s
+@code{children} time, by assumption.
+
+This assumption is usually true enough, but for some programs it is far
+from true. Suppose that @code{foo} returns very quickly when its argument
+is zero; suppose that @code{a} always passes zero as an argument, while
+other callers of @code{foo} pass other arguments. In this program, all the
+time spent in @code{foo} is in the calls from callers other than @code{a}.
+But @code{gprof} has no way of knowing this; it will blindly and
+incorrectly charge 2 seconds of time in @code{foo} to the children of
+@code{a}.
+
+We hope some day to put more complete data into @file{gmon.out}, so that
+this assumption is no longer needed, if we can figure out how. For the
+nonce, the estimated figures are usually more useful than misleading.
+
+@node Incompatibilities, , Assumptions, Top
+@chapter Incompatibilities with Unix @code{gprof}
+
+GNU @code{gprof} and Berkeley Unix @code{gprof} use the same data file
+@file{gmon.out}, and provide essentially the same information. But there a
+few differences.@refill
+
+GNU @code{gprof} does not support the @samp{-c} option which prints a
+static call graph based on reading the machine language of your
+program. We think that program cross-references ought to be based on
+the source files, which can be analyzed in a machine-independent
+fashion.@refill
+
+For a recursive function, Unix @code{gprof} lists the function as a parent
+and as a child, with a @code{calls} field that lists the number of
+recursive calls. GNU @code{gprof} omits these lines and puts the number of
+recursive calls in the primary line.
+
+When a function is suppressed from the call graph with @samp{-e}, GNU
+@code{gprof} still lists it as a subroutine of functions that call it.
+
+The function names printed in GNU @code{gprof} output do not include
+the leading underscores that are added internally to the front of all
+C identifiers on many operating systems.
+
+The blurbs, field widths, and output formats are different. GNU
+@code{gprof} prints blurbs after the tables, so that you can see the
+tables without skipping the blurbs.
+
+@contents
+@bye
diff --git a/binutils-1.9/hp-bin/Makefile b/binutils-1.9/hp-bin/Makefile
new file mode 100644
index 0000000..8ca44f1
--- /dev/null
+++ b/binutils-1.9/hp-bin/Makefile
@@ -0,0 +1,15 @@
+CFLAGS = -O -I../hp-include
+EXECUTABLES = hpxt chatr
+
+all : $(EXECUTABLES)
+
+clean :
+ rm -f *.o $(EXECUTABLES)
+
+hpxt : hpxt.o ioutil.o
+ $(CC) $(CFLAGS) -o hpxt hpxt.o ioutil.o
+
+chatr : chatr.o ioutil.o
+ $(CC) $(CFLAGS) -o chatr chatr.o ioutil.o
+
+hpxt.o chatr.o : ioutil.h
diff --git a/binutils-1.9/hp-bin/chatr.c b/binutils-1.9/hp-bin/chatr.c
new file mode 100644
index 0000000..1d7cbad
--- /dev/null
+++ b/binutils-1.9/hp-bin/chatr.c
@@ -0,0 +1,214 @@
+/* Change Attributes program for GNU.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <a.out.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include "ioutil.h"
+
+#define forward extern
+
+enum boolean { false, true };
+typedef enum boolean boolean;
+
+boolean change_to_shared_p;
+boolean change_to_demand_loaded_p;
+boolean silent_p;
+int failures;
+
+char *input_filename;
+char output_filename [20];
+int output_descriptor;
+
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int argi;
+ register char **argp;
+ forward void usage ();
+ forward void process_file ();
+ forward void file_abort_handler ();
+ extern char *mktemp ();
+
+ iou_set_program_name (argv);
+ argi = 1;
+ argp = (& (argv [1]));
+
+ change_to_shared_p = false;
+ change_to_demand_loaded_p = false;
+ silent_p = false;
+
+ while ((argi < argc) && (((*argp) [0]) == '-'))
+ {
+ switch ((*argp) [1])
+ {
+ case 'n':
+ change_to_shared_p = true;
+ break;
+ case 'q':
+ change_to_demand_loaded_p = true;
+ break;
+ case 's':
+ silent_p = true;
+ break;
+ default:
+ usage ();
+ }
+ if (((*argp) [2]) != '\0')
+ usage ();
+ argi += 1;
+ argp += 1;
+ }
+
+ if (change_to_shared_p && change_to_demand_loaded_p)
+ iou_error ("conflicting options: -n and -q");
+
+ if ((! change_to_shared_p) && (! change_to_demand_loaded_p) && silent_p)
+ exit (0);
+
+ if (argi == argc)
+ exit (255);
+
+ strcpy (output_filename, "/tmp/chatrXXXXXX");
+ if (output_filename != (mktemp (output_filename)))
+ iou_error ("mktemp failure");
+
+ failures = 0;
+ for (; (argi < argc); argi += 1)
+ {
+ input_filename = (*argp++);
+ output_descriptor =
+ (iou_open (output_filename, (O_RDWR | O_CREAT | O_TRUNC), 0666));
+ iou_abort_handler_bind (process_file, file_abort_handler);
+ iou_close (output_descriptor);
+ }
+ iou_unlink (output_filename);
+ exit (failures);
+}
+
+void
+usage ()
+{
+ fprintf (stderr, "usage: %s [-n] [-q] [-s] file ...\n", iou_program_name);
+ iou_error ();
+}
+
+void
+file_abort_handler ()
+{
+ failures += 1;
+ return;
+}
+
+void
+file_error (message)
+ char *message;
+{
+ char buffer [256];
+
+ sprintf (buffer, "%s: \"%s\"", message, input_filename);
+ iou_error (buffer);
+}
+
+void
+file_copy (input_descriptor, output_descriptor)
+ int input_descriptor;
+ int output_descriptor;
+{
+ char buffer [8192];
+ register int bytes_read;
+
+ while (1)
+ {
+ bytes_read = (iou_read (input_descriptor, buffer, 8192));
+ if (bytes_read == 0) break;
+ iou_write (output_descriptor, buffer, bytes_read);
+ }
+ return;
+}
+
+void
+process_file ()
+{
+ int input_descriptor;
+ struct exec input_exec;
+ struct exec output_exec;
+
+ input_descriptor = (iou_open (input_filename, O_RDONLY));
+
+ if ((iou_read (input_descriptor, (& input_exec), (sizeof (input_exec)))) !=
+ (sizeof (input_exec)))
+ file_error ("unable to read file header");
+
+ switch (N_MAGIC (input_exec))
+ {
+ case NMAGIC:
+ if (change_to_shared_p)
+ file_error ("file not demand load executable");
+ break;
+
+ case ZMAGIC:
+ if (change_to_demand_loaded_p)
+ file_error ("file not shared executable");
+ break;
+
+ default:
+ file_error ("file not executable format");
+ }
+
+ if (! silent_p)
+ {
+ printf ("%s:\n", input_filename);
+ if (change_to_shared_p || change_to_demand_loaded_p)
+ printf (" current values:\n");
+ printf
+ (" %s executable\n",
+ (((N_MAGIC (input_exec)) == NMAGIC) ? "shared" : "demand loaded"));
+ fflush (stdout);
+ }
+
+ if ((! change_to_shared_p) && (! change_to_demand_loaded_p))
+ return;
+
+ output_exec = input_exec;
+ N_SET_MAGIC (output_exec, (change_to_shared_p ? NMAGIC : ZMAGIC));
+
+ iou_write (output_descriptor, (& output_exec), (sizeof (output_exec)));
+ iou_lseek (input_descriptor, (N_TXTOFF (input_exec)), 0);
+ iou_lseek (output_descriptor, (N_TXTOFF (output_exec)), 0);
+ file_copy (input_descriptor, output_descriptor);
+
+ /* Now copy the temporary output file back into the input file. */
+ iou_close (input_descriptor);
+ iou_lseek (output_descriptor, 0, 0);
+ input_descriptor = (iou_open (input_filename, (O_WRONLY | O_TRUNC), 0777));
+ file_copy (output_descriptor, input_descriptor);
+ iou_close (input_descriptor);
+
+ if (! silent_p)
+ {
+ printf (" new values:\n");
+ printf
+ (" %s executable\n",
+ (((N_MAGIC (output_exec)) == NMAGIC) ? "shared" : "demand loaded"));
+ fflush (stdout);
+ }
+ return;
+}
diff --git a/binutils-1.9/hp-bin/hpxt.c b/binutils-1.9/hp-bin/hpxt.c
new file mode 100644
index 0000000..a07188a
--- /dev/null
+++ b/binutils-1.9/hp-bin/hpxt.c
@@ -0,0 +1,1077 @@
+/* Program to translate binary format files from HP-UX to GNU.
+ Input formats for HP 9000 series 300/400 only.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined(hp9000s300) && !defined(__hp9000s300)
+#include "error: hpxt is for 300- or 400-series machines only"
+#endif
+
+#include <stdio.h>
+#include <varargs.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <string.h>
+#define index(s, c) strchr (s, c)
+#define bzero(p, n) memset (p, 0, n)
+#include "ioutil.h"
+
+#define forward extern
+
+/* IO primitives */
+
+void
+xread (input_file, buffer, length)
+ int input_file;
+ char *buffer;
+ int length;
+{
+ if ((iou_read (input_file, buffer, length)) != length)
+ iou_error ("read failed to complete");
+ return;
+}
+
+/* HP-UX data structure descriptions */
+
+struct hp_magic
+ {
+ unsigned short system_id;
+ unsigned short file_type;
+ };
+
+#define HP_SYSID_98x6 0x020A
+#define HP_SYSID_9000S200 0x020C
+
+#define HP_SYSID_OK(sysid) \
+ (((sysid) == HP_SYSID_9000S200) \
+ || ((sysid) == HP_SYSID_98x6))
+
+#define HP_FILETYPE_RELOC 0x0106 /* relocatable only */
+#define HP_FILETYPE_EXEC 0x0107 /* normal executable */
+#define HP_FILETYPE_SHARE 0x0108 /* shared executable */
+#define HP_FILETYPE_DEMAND 0x010B /* demand-load executable */
+
+#define HP_FILETYPE_OK(filetype) \
+ (((filetype) == HP_FILETYPE_EXEC) \
+ || ((filetype) == HP_FILETYPE_SHARE) \
+ || ((filetype) == HP_FILETYPE_DEMAND) \
+ || ((filetype) == HP_FILETYPE_RELOC))
+
+#define HP_MAGIC_OK(magic) \
+ ((HP_SYSID_OK ((magic) . system_id)) \
+ && (HP_FILETYPE_OK ((magic) . file_type)))
+
+struct hp_exec
+ {
+ struct hp_magic a_magic;
+ short a_stamp; /* version id */
+ short a_unused;
+ long a_sparehp;
+ long a_text; /* size of text segment */
+ long a_data; /* size of data segment */
+ long a_bss; /* size of bss segment */
+ long a_trsize; /* text relocation size */
+ long a_drsize; /* data relocation size */
+ long a_pasint; /* pascal interface size */
+ long a_lesyms; /* symbol table size */
+ long a_dnttsize; /* debug name table size */
+ long a_entry; /* entry point */
+ long a_sltsize; /* source line table size */
+ long a_vtsize; /* value table size */
+ long a_spare3;
+ long a_spare4;
+ };
+
+#define HP_EXEC_MAGIC(header) (((header) . a_magic) . file_type)
+
+#define HP_PAGE_SIZE 0x1000
+
+#define HP_PAGE_SEEK(descriptor, header, offset) \
+{ \
+ if ((HP_EXEC_MAGIC (header)) == HP_FILETYPE_DEMAND) \
+ { \
+ int HP_PAGE_SEEK_remainder; \
+ \
+ HP_PAGE_SEEK_remainder = ((offset) % HP_PAGE_SIZE); \
+ if (HP_PAGE_SEEK_remainder != 0) \
+ iou_lseek \
+ ((descriptor), (HP_PAGE_SIZE - HP_PAGE_SEEK_remainder), 1); \
+ } \
+}
+
+struct hp_nlist
+ {
+ long n_value;
+ unsigned char n_type;
+ unsigned char n_length; /* length of ascii symbol name */
+ short n_almod; /* alignment mod */
+ short n_unused;
+ };
+
+#define HP_SYMTYPE_UNDEFINED 0x00
+#define HP_SYMTYPE_ABSOLUTE 0x01
+#define HP_SYMTYPE_TEXT 0x02
+#define HP_SYMTYPE_DATA 0x03
+#define HP_SYMTYPE_BSS 0x04
+#define HP_SYMTYPE_COMMON 0x05
+#define HP_SYMTYPE_FILENAME 0x1F
+
+#define HP_SYMTYPE_ALIGN 0x10
+#define HP_SYMTYPE_EXTERNAL 0x20
+
+#define HP_SYMTYPE_TYPE 0x0F
+
+struct hp_relocation_info
+ {
+ long r_address; /* position of relocation in segment */
+ short r_symbolnum; /* id of the symbol of external relocations */
+ char r_segment;
+ char r_length;
+ };
+
+#define HP_RSEGMENT_TEXT 0x00
+#define HP_RSEGMENT_DATA 0x01
+#define HP_RSEGMENT_BSS 0x02
+#define HP_RSEGMENT_EXTERNAL 0x03
+#define HP_RSEGMENT_NOOP 0x3F
+
+#define HP_RLENGTH_BYTE 0x00
+#define HP_RLENGTH_WORD 0x01
+#define HP_RLENGTH_LONG 0x02
+#define HP_RLENGTH_ALIGN 0x03
+
+#define HP_ARMAG "!<arch>\n"
+#define HP_SARMAG 8
+#define HP_ARFMAG "`\n"
+
+struct hp_ar_hdr
+ {
+ char ar_name [16]; /* file member name - `/' terminated */
+ char ar_date [12]; /* file member date - decimal */
+ char ar_uid [6]; /* file member user id - decimal */
+ char ar_gid [6]; /* file member group id - decimal */
+ char ar_mode [8]; /* file member mode - octal */
+ char ar_size [10]; /* file member size - decimal */
+ char ar_fmag [2]; /* ARFMAG - string to end header */
+ };
+
+struct hp_ar_symtab_hdr
+ {
+ unsigned short n_entries;
+ long string_table_size;
+ };
+
+struct hp_ar_symtab_entry
+ {
+ long string_index;
+ long file_index;
+ };
+
+/* GNU data structure descriptions */
+
+#ifdef hpux
+
+/* The `exec' structure and overall layout must be close to HP's when
+ we are running on an HP system, otherwise we will not be able to
+ execute the resulting file. */
+
+#define GNU_OMAGIC HP_FILETYPE_EXEC
+#define GNU_NMAGIC HP_FILETYPE_SHARE
+#define GNU_ZMAGIC HP_FILETYPE_SHARE
+
+struct gnu_exec
+ {
+ struct hp_magic a_magic;
+ unsigned long a_spare1;
+ unsigned long a_spare2;
+ unsigned long a_text; /* size of text segment */
+ unsigned long a_data; /* size of data segment */
+ unsigned long a_bss; /* size of bss segment */
+ unsigned long a_trsize; /* text relocation size */
+ unsigned long a_drsize; /* data relocation size */
+ unsigned long a_spare3; /* HP = pascal interface size */
+ unsigned long a_spare4; /* HP = symbol table size */
+ unsigned long a_spare5; /* HP = debug name table size */
+ unsigned long a_entry; /* entry point */
+ unsigned long a_spare6; /* HP = source line table size */
+ unsigned long a_spare7; /* HP = value table size */
+ unsigned long a_syms; /* symbol table size */
+ unsigned long a_spare8;
+ };
+
+#define GNU_EXEC_MAGIC(header) (((header) . a_magic) . file_type)
+
+#define GNU_EXEC_SET_MAGIC(header, magic) \
+{ \
+ (((header) . a_magic) . system_id) = HP_SYSID_9000S200; \
+ (((header) . a_magic) . file_type) = (magic); \
+}
+
+#define GNU_PAGE_SEEK_HEADER HP_PAGE_SEEK
+#define GNU_PAGE_SEEK_TEXT HP_PAGE_SEEK
+
+#else /* not hpux */
+
+#define GNU_OMAGIC 0407 /* old impure format */
+#define GNU_NMAGIC 0410 /* read-only text */
+#define GNU_ZMAGIC 0413 /* demand load format */
+
+struct gnu_exec
+ {
+ unsigned long a_magic; /* magic number */
+ unsigned long a_text; /* size of text segment */
+ unsigned long a_data; /* size of initialized data */
+ unsigned long a_bss; /* size of uninitialized data */
+ unsigned long a_syms; /* size of symbol table */
+ unsigned long a_entry; /* entry point */
+ unsigned long a_trsize; /* size of text relocation */
+ unsigned long a_drsize; /* size of data relocation */
+ };
+
+#define GNU_EXEC_MAGIC(header) ((header) . a_magic)
+#define GNU_EXEC_SET_MAGIC(header, magic) ((header) . a_magic) = (magic)
+
+#define GNU_PAGE_SIZE 0x400
+
+#define GNU_PAGE_SEEK_HEADER(descriptor, header, offset) \
+{ \
+ if ((GNU_EXEC_MAGIC (header)) == GNU_ZMAGIC) \
+ { \
+ int GNU_PAGE_SEEK_remainder; \
+ \
+ GNU_PAGE_SEEK_remainder = ((offset) % GNU_PAGE_SIZE); \
+ if (GNU_PAGE_SEEK_remainder != 0) \
+ iou_lseek \
+ ((descriptor), (GNU_PAGE_SIZE - GNU_PAGE_SEEK_remainder), 1); \
+ } \
+}
+
+#define GNU_PAGE_SEEK_TEXT(descriptor, header, offset)
+
+#endif /* hpux */
+
+struct gnu_nlist
+ {
+ union
+ {
+ char *n_name; /* for use when in-core */
+ long n_strx; /* index into file string table */
+ } n_un;
+ unsigned char n_type; /* type flag (N_TEXT,..) */
+ char n_other; /* unused */
+ short n_desc; /* see <stab.h> */
+ unsigned long n_value; /* value of symbol (or sdb offset) */
+ };
+
+#define GNU_SYMTYPE_UNDEFINED 0x0
+#define GNU_SYMTYPE_ABSOLUTE 0x2
+#define GNU_SYMTYPE_TEXT 0x4
+#define GNU_SYMTYPE_DATA 0x6
+#define GNU_SYMTYPE_BSS 0x8
+#define GNU_SYMTYPE_COMMON 0x12
+#define GNU_SYMTYPE_FILENAME 0x1F
+#define GNU_SYMTYPE_EXTERNAL 0x01
+
+struct gnu_relocation_info
+ {
+ long r_address; /* address which is relocated */
+ unsigned int
+ r_symbolnum : 24, /* local symbol ordinal */
+ r_pcrel : 1, /* was relocated pc relative already */
+ r_length : 2, /* BYTE, WORD, or LONG */
+ r_extern : 1, /* does not include value of sym referenced */
+ : 4; /* nothing, yet */
+ };
+
+#define GNU_RLENGTH_BYTE 0x00
+#define GNU_RLENGTH_WORD 0x01
+#define GNU_RLENGTH_LONG 0x02
+
+#define GNU_ARMAG "!<arch>\n"
+#define GNU_SARMAG 8
+#define GNU_ARFMAG "`\n"
+
+struct gnu_ar_hdr
+ {
+ char ar_name [16];
+ char ar_date [12];
+ char ar_uid [6];
+ char ar_gid [6];
+ char ar_mode [8];
+ char ar_size [10];
+ char ar_fmag [2];
+ };
+
+struct gnu_symdef
+ {
+ int symbol_name_string_index;
+ int library_member_offset;
+ };
+
+/* List abstraction */
+
+struct pair
+ {
+ char *car;
+ char *cdr;
+ };
+
+struct pair *
+pair_cons (car, cdr)
+ char *car;
+ char *cdr;
+{
+ register struct pair *result;
+
+ result = ((struct pair *) (iou_malloc (sizeof (struct pair))));
+ (result -> car) = car;
+ (result -> cdr) = cdr;
+ return (result);
+}
+
+#define LIST_CDR(list) ((struct pair *) ((list) -> cdr))
+#define LIST_SET_CDR(list, newcdr) (list -> cdr) = ((char *) newcdr)
+
+struct pair *
+list_reverse (list)
+ register struct pair *list;
+{
+ register struct pair *previous;
+ register struct pair *next;
+
+ previous = NULL;
+ while (list != NULL)
+ {
+ next = (LIST_CDR (list));
+ LIST_SET_CDR (list, previous);
+ previous = list;
+ list = next;
+ }
+ return (previous);
+}
+
+struct pair *
+read_list (input_file, n_bytes, field_name, read_item, length)
+ int input_file;
+ int n_bytes;
+ char * field_name;
+ char * (* read_item) ();
+ register int * length; /* return value */
+{
+ register struct pair *result;
+
+ result = NULL;
+ (* length) = 0;
+ while (n_bytes > 0)
+ {
+ result = (pair_cons (((* read_item) (input_file, (& n_bytes))), result));
+ (* length) += 1;
+ }
+ if (n_bytes != 0)
+ iou_error ("%s field size incorrect", field_name);
+ return (list_reverse (result));
+}
+
+/* Symbol Table */
+
+struct gnu_nlist *
+read_symbol (input_file, n_bytes)
+ int input_file;
+ int *n_bytes; /* return value */
+{
+ struct hp_nlist input_nlist;
+ register struct gnu_nlist *output_nlist;
+ register char *name;
+
+ {
+ register int name_length;
+
+ xread (input_file, (& input_nlist), (sizeof (input_nlist)));
+ name_length = (input_nlist . n_length);
+ name = (iou_malloc (name_length + 1));
+ xread (input_file, name, name_length);
+ (name [name_length]) = '\0';
+ (* n_bytes) -= ((sizeof (input_nlist)) + name_length);
+ }
+
+ output_nlist =
+ ((struct gnu_nlist *) (iou_malloc (sizeof (struct gnu_nlist))));
+ ((output_nlist -> n_un) . n_name) = name;
+ (output_nlist -> n_other) = 0;
+ (output_nlist -> n_desc) = 0;
+ (output_nlist -> n_value) = (input_nlist . n_value);
+
+ {
+ register int name_type;
+
+ name_type = (input_nlist . n_type);
+ if ((name_type & HP_SYMTYPE_ALIGN) != 0)
+ iou_error ("aligned symbol encountered: %s", name);
+ if (name_type == HP_SYMTYPE_FILENAME)
+ (output_nlist -> n_type) = GNU_SYMTYPE_FILENAME;
+ else
+ {
+ switch (name_type & HP_SYMTYPE_TYPE)
+ {
+ case HP_SYMTYPE_UNDEFINED:
+ (output_nlist -> n_type) = GNU_SYMTYPE_UNDEFINED;
+ break;
+
+ case HP_SYMTYPE_ABSOLUTE:
+ (output_nlist -> n_type) = GNU_SYMTYPE_ABSOLUTE;
+ break;
+
+ case HP_SYMTYPE_TEXT:
+ (output_nlist -> n_type) = GNU_SYMTYPE_TEXT;
+ break;
+
+ case HP_SYMTYPE_DATA:
+ (output_nlist -> n_type) = GNU_SYMTYPE_DATA;
+ break;
+
+ case HP_SYMTYPE_BSS:
+ (output_nlist -> n_type) = GNU_SYMTYPE_BSS;
+ break;
+
+ case HP_SYMTYPE_COMMON:
+ (output_nlist -> n_type) = GNU_SYMTYPE_COMMON;
+ break;
+
+ default:
+ iou_error ("unknown symbol type encountered: %x", name_type);
+ }
+ if ((name_type & HP_SYMTYPE_EXTERNAL) != 0)
+ (output_nlist -> n_type) |= GNU_SYMTYPE_EXTERNAL;
+ }
+ }
+
+ return (output_nlist);
+}
+
+struct pair *
+read_symbol_table (input_file, n_bytes, length)
+ int input_file;
+ int n_bytes;
+ int * length; /* return value */
+{
+ return
+ (read_list (input_file, n_bytes, "symbol table", read_symbol, length));
+}
+
+void
+write_symbol_table (output_file, symbol_table, length)
+ int output_file;
+ struct pair *symbol_table;
+ int length;
+{
+ register struct pair *scan;
+ register char *name;
+ struct gnu_nlist output_nlist;
+ int string_table_index;
+
+ (output_nlist . n_other) = 0;
+ (output_nlist . n_desc) = 0;
+
+ string_table_index = (sizeof (string_table_index));
+ for (scan = symbol_table; (scan != NULL); scan = (LIST_CDR (scan)))
+ {
+ register struct gnu_nlist *symbol;
+
+ symbol = ((struct gnu_nlist *) (scan -> car));
+ name = ((symbol -> n_un) . n_name);
+
+ ((output_nlist . n_un) . n_strx) = string_table_index;
+ (output_nlist . n_type) = (symbol -> n_type);
+ (output_nlist . n_value) = (symbol -> n_value);
+ iou_write (output_file, (& output_nlist), (sizeof (output_nlist)));
+
+ string_table_index += ((strlen (name)) + 1);
+ (scan -> car) = name;
+ iou_free (symbol);
+ }
+ iou_write
+ (output_file, (& string_table_index), (sizeof (string_table_index)));
+
+ scan = symbol_table;
+ while (scan != NULL)
+ {
+ register struct pair *cdr;
+
+ name = (scan -> car);
+ iou_write (output_file, name, ((strlen (name)) + 1));
+ iou_free (name);
+ cdr = (LIST_CDR (scan));
+ iou_free (scan);
+ scan = cdr;
+ }
+ return;
+}
+
+/* Relocation Info */
+
+struct gnu_relocation_info *
+read_relocation_info_1 (input_file, n_bytes)
+ int input_file;
+ register int * n_bytes; /* return value */
+{
+ struct hp_relocation_info input_info;
+ register struct gnu_relocation_info *output_info;
+
+ xread (input_file, (& input_info), (sizeof (input_info)));
+ (* n_bytes) -= (sizeof (input_info));
+
+ output_info =
+ ((struct gnu_relocation_info *)
+ (iou_malloc (sizeof (struct gnu_relocation_info))));
+ (output_info -> r_pcrel) = 0;
+ (output_info -> r_address) = (input_info . r_address);
+
+ switch (input_info . r_segment)
+ {
+ case HP_RSEGMENT_TEXT:
+ (output_info -> r_symbolnum) = GNU_SYMTYPE_TEXT;
+ (output_info -> r_extern) = 0;
+ break;
+
+ case HP_RSEGMENT_DATA:
+ (output_info -> r_symbolnum) = GNU_SYMTYPE_DATA;
+ (output_info -> r_extern) = 0;
+ break;
+
+ case HP_RSEGMENT_BSS:
+ (output_info -> r_symbolnum) = GNU_SYMTYPE_BSS;
+ (output_info -> r_extern) = 0;
+ break;
+
+ case HP_RSEGMENT_EXTERNAL:
+ (output_info -> r_symbolnum) = (input_info . r_symbolnum);
+ (output_info -> r_extern) = 1;
+ break;
+
+ default:
+ iou_error
+ ("illegal relocation segment type: %x", (input_info . r_segment));
+ }
+
+ switch (input_info . r_length)
+ {
+ case HP_RLENGTH_BYTE:
+ (output_info -> r_length) = GNU_RLENGTH_BYTE;
+ break;
+
+ case HP_RLENGTH_WORD:
+ (output_info -> r_length) = GNU_RLENGTH_WORD;
+ break;
+
+ case HP_RLENGTH_LONG:
+ (output_info -> r_length) = GNU_RLENGTH_LONG;
+ break;
+
+ default:
+ iou_error ("illegal relocation length: %x", (input_info . r_length));
+ }
+
+ return (output_info);
+}
+
+struct pair *
+read_relocation_info (input_file, n_bytes, length)
+ int input_file;
+ int n_bytes;
+ int * length;
+{
+ return
+ (read_list
+ (input_file, n_bytes, "relocation info", read_relocation_info_1, length));
+}
+
+void
+write_relocation_info (output_file, relocation_info, length)
+ int output_file;
+ struct pair *relocation_info;
+ int length;
+{
+ register struct pair *this;
+ register struct gnu_relocation_info *car;
+ register struct pair *cdr;
+
+ this = relocation_info;
+ while (this != NULL)
+ {
+ car = ((struct gnu_relocation_info *) (this -> car));
+ iou_write (output_file, car, (sizeof (struct gnu_relocation_info)));
+ iou_free (car);
+ cdr = (LIST_CDR (this));
+ iou_free (this);
+ this = cdr;
+ }
+ return;
+}
+
+/* Convert an executable (or relocatable) file. */
+
+void
+process_executable_file (input_file, output_file)
+ int input_file;
+ int output_file;
+{
+ struct hp_exec input_exec;
+ struct gnu_exec output_exec;
+ char *text_segment;
+ char *data_segment;
+ struct pair *symbol_table;
+ int symbol_table_length;
+ struct pair *text_relocation_info;
+ int text_relocation_info_length;
+ struct pair *data_relocation_info;
+ int data_relocation_info_length;
+
+ xread (input_file, (& input_exec), (sizeof (input_exec)));
+ HP_PAGE_SEEK (input_file, input_exec, (sizeof (input_exec)));
+
+ if ((input_exec . a_text) != 0)
+ {
+ text_segment = (iou_malloc (input_exec . a_text));
+ xread (input_file, text_segment, (input_exec . a_text));
+ HP_PAGE_SEEK (input_file, input_exec, (input_exec . a_text));
+ }
+ else
+ text_segment = NULL;
+
+ if ((input_exec . a_data) != 0)
+ {
+ data_segment = (iou_malloc (input_exec . a_data));
+ xread (input_file, data_segment, (input_exec . a_data));
+ HP_PAGE_SEEK (input_file, input_exec, (input_exec . a_data));
+ }
+ else
+ data_segment = NULL;
+
+ /* Skip the pascal interface text */
+ iou_lseek (input_file, (input_exec . a_pasint), 1);
+
+ symbol_table =
+ (read_symbol_table
+ (input_file, (input_exec . a_lesyms), (& symbol_table_length)));
+
+ /* Skip the debugging tables */
+ iou_lseek
+ (input_file,
+ ((input_exec . a_dnttsize)
+ + (input_exec . a_sltsize)
+ + (input_exec . a_vtsize)),
+ 1);
+
+ text_relocation_info =
+ (read_relocation_info
+ (input_file, (input_exec . a_trsize), (& text_relocation_info_length)));
+ data_relocation_info =
+ (read_relocation_info
+ (input_file, (input_exec . a_drsize), (& data_relocation_info_length)));
+
+ bzero ((& output_exec), (sizeof (output_exec)));
+ switch (HP_EXEC_MAGIC (input_exec))
+ {
+ case HP_FILETYPE_RELOC:
+ case HP_FILETYPE_EXEC:
+ GNU_EXEC_SET_MAGIC (output_exec, GNU_OMAGIC);
+ break;
+
+ case HP_FILETYPE_SHARE:
+ GNU_EXEC_SET_MAGIC (output_exec, GNU_NMAGIC);
+ break;
+
+ case HP_FILETYPE_DEMAND:
+ GNU_EXEC_SET_MAGIC (output_exec, GNU_ZMAGIC);
+ break;
+
+ default:
+ iou_error ("unknown magic type: %x", (HP_EXEC_MAGIC (input_exec)));
+ }
+ (output_exec . a_text) = (input_exec . a_text);
+ (output_exec . a_data) = (input_exec . a_data);
+ (output_exec . a_bss) = (input_exec . a_bss);
+ (output_exec . a_syms) = (symbol_table_length * (sizeof (struct gnu_nlist)));
+ (output_exec . a_entry) = (input_exec . a_entry);
+ (output_exec . a_trsize) = (input_exec . a_trsize);
+ (output_exec . a_drsize) = (input_exec . a_drsize);
+
+ iou_write (output_file, (& output_exec), (sizeof (output_exec)));
+ GNU_PAGE_SEEK_HEADER (output_file, output_exec, (sizeof (output_exec)));
+ if (text_segment != NULL)
+ {
+ iou_write (output_file, text_segment, (output_exec . a_text));
+ iou_free (text_segment);
+ GNU_PAGE_SEEK_TEXT (output_file, output_exec, (output_exec . a_text));
+ }
+ if (data_segment != NULL)
+ {
+ iou_write (output_file, data_segment, (output_exec . a_data));
+ iou_free (data_segment);
+ GNU_PAGE_SEEK_TEXT (output_file, output_exec, (output_exec . a_data));
+ }
+ write_relocation_info
+ (output_file, text_relocation_info, text_relocation_info_length);
+ write_relocation_info
+ (output_file, data_relocation_info, data_relocation_info_length);
+ write_symbol_table (output_file, symbol_table, symbol_table_length);
+
+ return;
+}
+
+/* Convert an archive file. */
+
+/* These procedures take advantage of the fact that the HP and GNU
+ formats for struct ar_hdr are virtually identical. */
+
+long symtab_start_position;
+char *symtab_member_data;
+struct hp_ar_symtab_entry *hp_symtab_entries;
+struct gnu_symdef *gnu_symtab_entries;
+long symtab_entries_length;
+long symtab_names_length;
+
+void
+process_archive_file (input_file, output_file)
+ int input_file;
+ int output_file;
+{
+ int start_position;
+ int length;
+ struct hp_ar_hdr input_header;
+ int member_length;
+ forward void process_archive_symtab ();
+ forward void update_symtab_entries ();
+ forward void output_symtab_entries ();
+ forward void process_archive_entry ();
+
+ gnu_symtab_entries = NULL;
+ while (1)
+ {
+ start_position = (iou_lseek (input_file, 0, 1));
+ length = (read (input_file, (& input_header), (sizeof (input_header))));
+ if (length == 0)
+ break;
+ if (length != (sizeof (input_header)))
+ iou_error ("input archive ends prematurely");
+ if (((strncmp
+ ((input_header . ar_fmag),
+ HP_ARFMAG,
+ (sizeof (input_header . ar_fmag))))
+ != 0)
+ ||
+ ((sscanf ((input_header . ar_size), "%d", (& member_length)))
+ != 1))
+ iou_error ("malformatted header of archive member");
+
+ if (((input_header . ar_name) [0]) == '/')
+ process_archive_symtab
+ (input_file, output_file, (& input_header), member_length);
+ else
+ {
+ if (gnu_symtab_entries != NULL)
+ update_symtab_entries
+ (start_position, (iou_lseek (output_file, 0, 1)));
+ process_archive_entry (input_file, output_file, (& input_header),
+ member_length);
+ }
+ }
+ if (gnu_symtab_entries != NULL)
+ output_symtab_entries (output_file, (& input_header));
+ return;
+}
+
+#ifdef DEBUG_SYMTAB
+
+void
+dump_symtab_data ()
+{
+ register struct hp_ar_symtab_entry *symtab_entries;
+ register char *symtab_names;
+ register int i;
+
+ symtab_names = (symtab_member_data + (sizeof (struct hp_ar_symtab_hdr)));
+ symtab_entries =
+ ((struct hp_ar_symtab_entry *) (symtab_names + symtab_names_length));
+ for (i = 0; (i < symtab_entries_length); i += 1)
+ {
+ fprintf
+ (stdout,
+ "Entry %d: string_index = %d; file_index = %d; name = %s\n",
+ i,
+ ((symtab_entries [i]) . string_index),
+ ((symtab_entries [i]) . file_index),
+ (symtab_names + ((symtab_entries [i]) . string_index)));
+ }
+ fflush (stdout);
+ return;
+}
+
+#endif /* DEBUG_SYMTAB */
+
+void
+process_archive_symtab (input_file, output_file, input_header, member_length)
+ int input_file;
+ int output_file;
+ struct hp_ar_hdr *input_header;
+ int member_length;
+{
+ long symtab_entries_bytes;
+ void initialize_symtab_entries ();
+
+ symtab_member_data = (iou_malloc (member_length));
+ xread (input_file, symtab_member_data, member_length);
+
+ symtab_entries_length =
+ (((struct hp_ar_symtab_hdr *) symtab_member_data) -> n_entries);
+ symtab_entries_bytes =
+ (symtab_entries_length * (sizeof (struct hp_ar_symtab_entry)));
+ symtab_names_length =
+ (((struct hp_ar_symtab_hdr *) symtab_member_data) -> string_table_size);
+
+#ifdef DEBUG_SYMTAB
+ dump_symtab_data ();
+#endif
+
+ {
+ char string_buffer [((sizeof (input_header -> ar_name)) + 1)];
+
+ sprintf
+ (string_buffer, "%-*s", (sizeof (input_header -> ar_name)), "__.SYMDEF");
+ strncpy
+ ((input_header -> ar_name),
+ string_buffer,
+ (sizeof (input_header -> ar_name)));
+ }
+ {
+ char string_buffer [((sizeof (input_header -> ar_size)) + 1)];
+
+ sprintf
+ (string_buffer,
+ "%-*d",
+ (sizeof (input_header -> ar_size)),
+ (symtab_entries_bytes + symtab_names_length + (2 * (sizeof (long)))));
+ strncpy
+ ((input_header -> ar_size),
+ string_buffer,
+ (sizeof (input_header -> ar_size)));
+ }
+ iou_write (output_file, input_header, (sizeof (* input_header)));
+ iou_write (output_file, (& symtab_entries_bytes), (sizeof (long)));
+
+ /* Leave slot for entries, which we fill in later. */
+ symtab_start_position = (iou_lseek (output_file, 0, 1));
+ initialize_symtab_entries ();
+ iou_lseek (output_file, symtab_entries_bytes, 1);
+
+ iou_write (output_file, (& symtab_names_length), (sizeof (long)));
+ iou_write
+ (output_file,
+ (symtab_member_data + (sizeof (struct hp_ar_symtab_hdr))),
+ symtab_names_length);
+
+ return;
+}
+
+void
+initialize_symtab_entries ()
+{
+ register struct hp_ar_symtab_entry *scan_hp;
+ register struct hp_ar_symtab_entry *end;
+ register struct gnu_symdef *scan_gnu;
+
+ hp_symtab_entries =
+ ((struct hp_ar_symtab_entry *)
+ (symtab_member_data
+ + (sizeof (struct hp_ar_symtab_hdr))
+ + symtab_names_length));
+ gnu_symtab_entries =
+ ((struct gnu_symdef *)
+ (iou_malloc (symtab_entries_length * (sizeof (struct gnu_symdef)))));
+
+ scan_hp = hp_symtab_entries;
+ end = (scan_hp + symtab_entries_length);
+ scan_gnu = gnu_symtab_entries;
+ while (scan_hp < end)
+ {
+ (scan_gnu -> symbol_name_string_index) = (scan_hp -> string_index);
+ (scan_gnu -> library_member_offset) = (-1);
+ scan_hp += 1;
+ scan_gnu += 1;
+ }
+
+ return;
+}
+
+void
+update_symtab_entries (old_offset, new_offset)
+ register long old_offset;
+ long new_offset;
+{
+ register struct hp_ar_symtab_entry *scan_hp;
+ register struct hp_ar_symtab_entry *end;
+ register struct gnu_symdef *scan_gnu;
+
+#ifdef DEBUG_SYMTAB
+ fprintf (stdout, "Update: old = %d, new = %d\n", old_offset, new_offset);
+#endif
+
+ scan_hp = hp_symtab_entries;
+ end = (scan_hp + symtab_entries_length);
+ scan_gnu = gnu_symtab_entries;
+ while (scan_hp < end)
+ {
+ if ((scan_hp -> file_index) == old_offset)
+ {
+#ifdef DEBUG_SYMTAB
+ fprintf
+ (stdout,
+ "\t%s\n",
+ (symtab_member_data
+ + (sizeof (struct hp_ar_symtab_hdr))
+ + (scan -> string_index)));
+#endif
+ (scan_gnu -> library_member_offset) = new_offset;
+ }
+ scan_hp += 1;
+ scan_gnu += 1;
+ }
+ return;
+}
+
+void
+check_symtab_entries ()
+{
+ register struct gnu_symdef *scan;
+ register struct gnu_symdef *end;
+
+ scan = gnu_symtab_entries;
+ end = (scan + symtab_entries_length);
+ while (scan < end)
+ if (((scan++) -> library_member_offset) == (-1))
+ iou_error ("Uninitialized __.SYMTAB entry");
+
+ return;
+}
+
+void
+output_symtab_entries (output_file, input_header)
+ int output_file;
+ struct hp_ar_hdr *input_header;
+{
+ check_symtab_entries ();
+ iou_lseek (output_file, symtab_start_position, 0);
+ iou_write
+ (output_file,
+ gnu_symtab_entries,
+ (symtab_entries_length * (sizeof (struct gnu_symdef))));
+ iou_free (symtab_member_data);
+ iou_free (gnu_symtab_entries);
+ return;
+}
+
+void
+process_archive_entry (input_file, output_file, input_header, member_length)
+ int input_file;
+ int output_file;
+ struct hp_ar_hdr *input_header;
+ int member_length;
+{
+ long header_position;
+ long output_start;
+ long output_end;
+ long input_end;
+ char *slashptr;
+
+ /* Strategy: leave a hole for the header, then process the file.
+ Afterwards, back up and write the header in place. */
+ header_position = (iou_lseek (output_file, 0, 1));
+ output_start = (iou_lseek (output_file, (sizeof (* input_header)), 1));
+ input_end = ((iou_lseek (input_file, 0, 1)) + member_length);
+
+ process_executable_file (input_file, output_file);
+ if ((iou_lseek (input_file, 0, 1)) != input_end)
+ iou_error ("process_executable_file used wrong amount of input");
+
+ output_end = (iou_lseek (output_file, 0, 1));
+ iou_lseek (output_file, header_position, 0);
+ if (slashptr = index(input_header->ar_name, '/'))
+ *slashptr = ' ';
+ {
+ char string_buffer [((sizeof (input_header -> ar_size)) + 1)];
+
+ sprintf
+ (string_buffer,
+ "%-*d",
+ (sizeof (input_header -> ar_size)),
+ (output_end - output_start));
+ strncpy
+ ((input_header -> ar_size),
+ string_buffer,
+ (sizeof (input_header -> ar_size)));
+ }
+ iou_write (output_file, input_header, (sizeof (* input_header)));
+ iou_lseek (output_file, output_end, 0);
+
+ /* Pad to even byte boundary if needed */
+ if ((input_end & 1) != 0)
+ iou_lseek (input_file, 1, 1);
+ if ((output_end & 1) != 0)
+ iou_write (output_file, "\0", 1);
+
+ return;
+}
+
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int input_file;
+ int output_file;
+ register int length;
+ struct hp_magic input_magic;
+
+ iou_set_program_name (argv);
+ if (argc != 3)
+ {
+ fprintf (stderr, "usage: %s input-file output-file\n", iou_program_name);
+ iou_error ();
+ }
+
+ input_file = (iou_open ((argv [1]), O_RDONLY));
+ output_file = (iou_open ((argv [2]), (O_WRONLY | O_CREAT | O_TRUNC), 0666));
+
+ xread (input_file, (& input_magic), (sizeof (input_magic)));
+ if (HP_MAGIC_OK (input_magic))
+ {
+ iou_lseek (input_file, 0, 0);
+ process_executable_file (input_file, output_file);
+ }
+ else
+ {
+ char armag [HP_SARMAG];
+
+ iou_lseek (input_file, 0, 0);
+ xread (input_file, armag, HP_SARMAG);
+ if ((strncmp (armag, HP_ARMAG, HP_SARMAG)) != 0)
+ iou_error ("input file not executable or archive");
+ iou_write (output_file, GNU_ARMAG, GNU_SARMAG);
+ process_archive_file (input_file, output_file);
+ }
+ exit (0);
+ /*NOTREACHED*/
+}
diff --git a/binutils-1.9/hp-bin/ioutil.c b/binutils-1.9/hp-bin/ioutil.c
new file mode 100644
index 0000000..e488c87
--- /dev/null
+++ b/binutils-1.9/hp-bin/ioutil.c
@@ -0,0 +1,332 @@
+/* I/O Utilities
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <varargs.h>
+#include <sys/file.h>
+#include <string.h>
+#define index(s, c) strchr (s, c)
+#include <errno.h>
+#include <setjmp.h>
+#include "ioutil.h"
+
+char *iou_program_name;
+
+void
+iou_set_program_name (argv)
+ char *argv [];
+{
+ register char *start;
+ register char *slash;
+
+ start = (argv [0]);
+ while (1)
+ {
+ slash = (index (start, '/'));
+ if (slash == NULL) break;
+ start = (slash + 1);
+ }
+ iou_program_name = start;
+ return;
+}
+
+struct abort_list
+ {
+ struct abort_list *next;
+ void (* handler) ();
+ jmp_buf catch_point;
+ };
+typedef struct abort_list *abort_list;
+
+static abort_list abort_handlers = NULL;
+
+void
+iou_abort ()
+{
+ register abort_list handlers;
+
+ handlers = abort_handlers;
+ if (handlers == NULL) abort ();
+ longjmp ((handlers -> catch_point), 1); /*NOTREACHED*/
+}
+
+void
+iou_abort_handler_bind (thunk, handler)
+ void (* thunk) ();
+ void (* handler) ();
+{
+ register abort_list handlers;
+ register int setjmp_result;
+
+ handlers = ((abort_list) (iou_malloc (sizeof (struct abort_list))));
+ (handlers -> next) = abort_handlers;
+ (handlers -> handler) = handler;
+ abort_handlers = handlers;
+ setjmp_result = (setjmp (handlers -> catch_point));
+ switch (setjmp_result)
+ {
+ case 0:
+ (* thunk) ();
+ if (handlers != abort_handlers)
+ iou_fatal_error ("iou_abort_handler_bind: sync error");
+ abort_handlers = (handlers -> next);
+ iou_free (handlers);
+ return;
+
+ case 1:
+ {
+ register abort_list handlers;
+ register void (* handler) ();
+
+ handlers = abort_handlers;
+ handler = (handlers -> handler);
+ abort_handlers = (handlers -> next);
+ iou_free (handlers);
+ (* handler) ();
+ return;
+ }
+
+ default:
+ iou_fatal_error ("Illegal setjmp value: %d", setjmp_result);
+ /*NOTREACHED*/
+ }
+}
+
+#ifndef hpux
+#ifdef bsd
+
+static void
+vfprintf (stream, format, args)
+ FILE *stream;
+ char *format;
+ char *args;
+{
+ _doprnt (format, args, stderr);
+ return;
+}
+
+#else
+#include "error: no definition for `vfprintf' procedure"
+#endif
+#endif
+
+#define WARN() \
+{ \
+ va_list args; \
+ char *format; \
+ \
+ fprintf (stderr, "%s: ", iou_program_name); \
+ va_start (args); \
+ format = (va_arg (args, char *)); \
+ vfprintf (stderr, format, args); \
+ va_end (args); \
+ putc ('\n', stderr); \
+}
+
+/*VARARGS0*/ void
+iou_warning (va_alist)
+ va_dcl
+{
+ WARN();
+ return;
+}
+
+/*VARARGS0*/ void
+iou_error (va_alist)
+ va_dcl
+{
+ WARN();
+ iou_abort (); /*NOTREACHED*/
+}
+
+/*VARARGS0*/ void
+iou_fatal_error (va_alist)
+ va_dcl
+{
+ WARN();
+ abort (); /*NOTREACHED*/
+}
+
+void
+iou_call_warning (name)
+ char *name;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist [];
+
+ if (errno < sys_nerr)
+ iou_warning ("%s during system call: %s", (sys_errlist [errno]), name);
+ else
+ iou_warning ("error code %d during system call: %s", errno, name);
+ return;
+}
+
+void
+iou_call_error (name)
+ char *name;
+{
+ iou_call_warning (name);
+ iou_abort (); /*NOTREACHED*/
+}
+
+void
+iou_stat (path, buf)
+ char *path;
+ struct stat *buf;
+{
+ extern int stat ();
+ register int result;
+
+ while (1)
+ {
+ result = (stat (path, buf));
+ if (result == 0) break;
+ if (errno != EINTR) iou_call_error ("stat");
+ }
+ return;
+}
+
+void
+iou_unlink (path)
+ char *path;
+{
+ extern int unlink ();
+
+ if ((unlink (path)) != 0)
+ iou_call_error ("unlink");
+ return;
+}
+
+int
+iou_open (path, oflag, mode)
+ char *path;
+ int oflag;
+ int mode;
+{
+ register int result;
+
+ while (1)
+ {
+ result = (open (path, oflag, mode));
+ if (result >= 0) break;
+ if (errno != EINTR) iou_call_error ("open");
+ }
+ return (result);
+}
+
+void
+iou_close (descriptor)
+ int descriptor;
+{
+ if ((close (descriptor)) != 0)
+ iou_call_error ("close");
+ return;
+}
+
+long
+iou_lseek (descriptor, offset, whence)
+ int descriptor;
+ long offset;
+ int whence;
+{
+ extern long lseek ();
+ register long result;
+
+ while (1)
+ {
+ result = (lseek (descriptor, offset, whence));
+ if (result >= 0) break;
+ if (errno != EINTR) iou_call_error ("lseek");
+ }
+ return (result);
+}
+
+int
+iou_read (input_file, buffer, length)
+ int input_file;
+ register char *buffer;
+ int length;
+{
+ extern int read ();
+ register int bytes_remaining;
+ register int result;
+
+ bytes_remaining = length;
+ while (bytes_remaining > 0)
+ {
+ result = (read (input_file, buffer, bytes_remaining));
+ if (result == 0) return (length - bytes_remaining);
+ if (result > 0)
+ {
+ buffer += result;
+ bytes_remaining -= result;
+ continue;
+ }
+ if (errno != EINTR) iou_call_error ("read");
+ }
+ return (length);
+}
+
+void
+iou_write (output_file, buffer, length)
+ int output_file;
+ register char *buffer;
+ register int length;
+{
+ extern int write ();
+ register int bytes_remaining;
+ register int result;
+
+ bytes_remaining = length;
+ while (bytes_remaining > 0)
+ {
+ result = (write (output_file, buffer, bytes_remaining));
+ if (result >= 0)
+ {
+ buffer += result;
+ bytes_remaining -= result;
+ continue;
+ }
+ if (errno != EINTR) iou_call_error ("write");
+ }
+ return;
+}
+
+char *
+iou_malloc (length)
+ unsigned length;
+{
+ extern char *malloc ();
+ register char *result;
+
+ result = (malloc (length));
+ if (result == NULL) iou_error ("virtual memory exhausted");
+ return (result);
+}
+
+char *
+iou_realloc (pointer, length)
+ char *pointer;
+ unsigned length;
+{
+ extern char *realloc ();
+ register char *result;
+
+ result = (realloc (pointer, length));
+ if (result == NULL) iou_error ("virtual memory exhausted");
+ return (result);
+}
diff --git a/binutils-1.9/hp-bin/ioutil.h b/binutils-1.9/hp-bin/ioutil.h
new file mode 100644
index 0000000..27bde15
--- /dev/null
+++ b/binutils-1.9/hp-bin/ioutil.h
@@ -0,0 +1,20 @@
+extern char *iou_program_name;
+extern void iou_set_program_name ();
+extern void iou_abort ();
+extern void iou_abort_handler_bind ();
+extern void iou_warning ();
+extern void iou_error ();
+extern void iou_fatal_error ();
+extern void iou_call_warning ();
+extern void iou_call_error ();
+extern void iou_stat ();
+extern void iou_unlink ();
+extern int iou_open ();
+extern void iou_close ();
+extern long iou_lseek ();
+extern int iou_read ();
+extern void iou_write ();
+extern char *iou_malloc ();
+extern char *iou_realloc ();
+#define iou_free free
+extern void iou_free ();
diff --git a/binutils-1.9/hp-bin/mkhplib b/binutils-1.9/hp-bin/mkhplib
new file mode 100755
index 0000000..2a86289
--- /dev/null
+++ b/binutils-1.9/hp-bin/mkhplib
@@ -0,0 +1,30 @@
+#!/bin/csh -f
+
+if (! -d /usr/local/lib/gnu) then
+ mkdir /usr/local/lib/gnu
+endif
+
+# Make a dummy "libg.a".
+/bin/ar q /tmp/libg$$.a
+hpxt /tmp/libg$$.a /usr/local/lib/gnu/libg.a
+rm -f /tmp/libg$$.a
+
+# Note: ordering of directories must be reverse of the normal search
+# order! This is because we are compressing all of the directories
+# into a single directory. If two directories each contain a library
+# with the same name, the one we convert second will be the one we
+# end up with.
+
+foreach dir (/usr/local/lib /usr/lib /lib)
+ cd $dir
+ foreach i (lib*.a)
+ echo "$dir/$i"
+ hpxt $i /usr/local/lib/gnu/$i
+ end
+end
+
+cd /lib
+foreach i (*crt0.o)
+ echo "/lib/$i"
+ hpxt $i /usr/local/lib/gnu/$i
+end
diff --git a/binutils-1.9/hp-include/a.out.h b/binutils-1.9/hp-include/a.out.h
new file mode 100644
index 0000000..87e7219
--- /dev/null
+++ b/binutils-1.9/hp-include/a.out.h
@@ -0,0 +1,79 @@
+/* Special version of <a.out.h> for use under hp-ux.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this file; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The `exec' structure and overall layout must be close to HP's when
+ we are running on an HP system, otherwise we will not be able to
+ execute the resulting file. */
+
+/* Allow this file to be included twice. */
+#ifndef __GNU_EXEC_MACROS__
+
+struct exec
+{
+ unsigned short a_machtype; /* machine type */
+ unsigned short a_magic; /* magic number */
+ unsigned long a_spare1;
+ unsigned long a_spare2;
+ unsigned long a_text; /* length of text, in bytes */
+ unsigned long a_data; /* length of data, in bytes */
+ unsigned long a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned long a_trsize; /* length of relocation info for text, in bytes */
+ unsigned long a_drsize; /* length of relocation info for data, in bytes */
+ unsigned long a_spare3; /* HP = pascal interface size */
+ unsigned long a_spare4; /* HP = symbol table size */
+ unsigned long a_spare5; /* HP = debug name table size */
+ unsigned long a_entry; /* start address */
+ unsigned long a_spare6; /* HP = source line table size */
+ unsigned long a_spare7; /* HP = value table size */
+ unsigned long a_syms; /* length of symbol table data in file, in bytes */
+ unsigned long a_spare8;
+};
+
+/* Tell a.out.gnu.h not to define `struct exec'. */
+#define __STRUCT_EXEC_OVERRIDE__
+
+#include "../a.out.gnu.h"
+
+#undef N_MAGIC
+#undef N_MACHTYPE
+#undef N_FLAGS
+#undef N_SET_INFO
+#undef N_SET_MAGIC
+#undef N_SET_MACHTYPE
+#undef N_SET_FLAGS
+
+#define N_MAGIC(exec) ((exec) . a_magic)
+#define N_MACHTYPE(exec) ((exec) . a_machtype)
+#define N_SET_MAGIC(exec, magic) (((exec) . a_magic) = (magic))
+#define N_SET_MACHTYPE(exec, machtype) (((exec) . a_machtype) = (machtype))
+
+#undef N_BADMAG
+#define N_BADMAG(x) ((_N_BADMAG (x)) || (_N_BADMACH (x)))
+
+#define _N_BADMACH(x) \
+(((N_MACHTYPE (x)) != HP9000S200_ID) && \
+ ((N_MACHTYPE (x)) != HP98x6_ID))
+
+#define HP98x6_ID 0x20A
+#define HP9000S200_ID 0x20C
+
+#undef _N_HDROFF
+#define _N_HDROFF(x) (SEGMENT_SIZE - (sizeof (struct exec)))
+
+#define SEGMENT_SIZE 0x1000
+
+#endif /* __GNU_EXEC_MACROS__ */
diff --git a/binutils-1.9/hp-include/stab.def b/binutils-1.9/hp-include/stab.def
new file mode 100644
index 0000000..b81cda4
--- /dev/null
+++ b/binutils-1.9/hp-include/stab.def
@@ -0,0 +1,115 @@
+/* Table of DBX symbol codes for the GNU system.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Global variable. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_GSYM, 0x20, "GSYM")
+
+/* Function name for BSD Fortran. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_FNAME, 0x22, "FNAME")
+
+/* Function name or text-segment variable for C. Value is its address.
+ Desc is supposedly starting line number, but GCC doesn't set it
+ and DBX seems not to miss it. */
+__define_stab (N_FUN, 0x24, "FUN")
+
+/* Data-segment variable with internal linkage. Value is its address. */
+__define_stab (N_STSYM, 0x26, "STSYM")
+
+/* BSS-segment variable with internal linkage. Value is its address. */
+__define_stab (N_LCSYM, 0x28, "LCSYM")
+
+/* Name of main routine. Only the name is significant.
+ This is not used in C. */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Register variable. Value is number of register. */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Structure or union element. Value is offset in the structure. */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* Parameter variable. Value is offset from argument pointer.
+ (On most machines the argument pointer is the same as the frame pointer. */
+__define_stab (N_PSYM, 0xa0, "PSYM")
+
+/* Automatic variable in the stack. Value is offset from frame pointer.
+ Also used for type descriptions. */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Alternate entry point. Value is its address. */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Name of main source file.
+ Value is starting text address of the compilation. */
+__define_stab (N_SO, 0x64, "SO")
+
+/* Name of sub-source file.
+ Value is starting text address of the compilation. */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Line number in text segment. Desc is the line number;
+ value is corresponding address. */
+__define_stab (N_SLINE, 0x44, "SLINE")
+/* Similar, for data segment. */
+__define_stab (N_DSLINE, 0x46, "DSLINE")
+/* Similar, for bss segment. */
+__define_stab (N_BSLINE, 0x48, "BSLINE")
+
+/* Beginning of an include file. Only Sun uses this.
+ In an object file, only the name is significant.
+ The Sun linker puts data into some of the other fields. */
+__define_stab (N_BINCL, 0x82, "BINCL")
+/* End of an include file. No name.
+ These two act as brackets around the file's output.
+ In an object file, there is no significant data in this entry.
+ The Sun linker puts data into some of the fields. */
+__define_stab (N_EINCL, 0xa2, "EINCL")
+/* Place holder for deleted include file.
+ This appears only in output from the Sun linker. */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* Beginning of lexical block.
+ The desc is the nesting level in lexical blocks.
+ The value is the address of the start of the text for the block.
+ The variables declared inside the block *precede* the N_LBRAC symbol. */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+/* End of a lexical block. Desc matches the N_LBRAC's desc.
+ The value is the address of the end of the text for the block. */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block. Only the name is significant. */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+/* Begin named common block. Only the name is significant
+ (and it should match the N_BCOMM). */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+/* End common (local name): value is address.
+ I'm not sure how this is used. */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+/* Second symbol entry containing a length-value for the preceding entry.
+ The value is the length. */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* Global symbol in Pascal.
+ Supposedly the value is its line number; I'm skeptical. */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Modula-2 compilation unit. Can someone say what info it contains? */
+__define_stab (N_M2C, 0x42, "M2C")
+/* Modula-2 scope information. Can someone say what info it contains? */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
diff --git a/binutils-1.9/hp-include/stab.h b/binutils-1.9/hp-include/stab.h
new file mode 100644
index 0000000..80bd594
--- /dev/null
+++ b/binutils-1.9/hp-include/stab.h
@@ -0,0 +1,17 @@
+#ifndef __GNU_STAB__
+
+/* Indicate the GNU stab.h is in use. */
+
+#define __GNU_STAB__
+
+#define __define_stab(NAME, CODE, STRING) NAME=CODE,
+
+enum __stab_debug_code
+{
+#include "stab.def"
+LAST_UNUSED_STAB_CODE
+};
+
+#undef __define_stab
+
+#endif /* __GNU_STAB_ */
diff --git a/binutils-1.9/ld.c b/binutils-1.9/ld.c
new file mode 100644
index 0000000..d7bc0ce
--- /dev/null
+++ b/binutils-1.9/ld.c
@@ -0,0 +1,6312 @@
+/* Linker `ld' for GNU
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Richard Stallman with some help from Eric Albert.
+ Set, indirect, and warning symbol features added by Randy Smith. */
+
+#include <ar.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#ifndef USG
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#ifndef sony_news
+#include <fcntl.h>
+#endif
+#ifdef ns32000
+struct relocation_info
+{ /* Look for the default declaration in a.out.gnu.h for documentation. */
+ int r_address;
+ unsigned int r_symbolnum:24;
+ unsigned int r_pcrel:1;
+ unsigned int r_length:2;
+ unsigned int r_extern:1;
+ unsigned int r_bsr:1;
+ unsigned int r_disp:2;
+ unsigned int r_pad:1;
+};
+#define N_RELOCATION_INFO_DECLARED
+#endif /*ns32000*/
+
+#if !defined(A_OUT) && !defined(MACH_O)
+#define A_OUT
+#endif
+
+#ifdef A_OUT
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+#endif
+
+#ifdef MACH_O
+#ifndef A_OUT
+#include <nlist.h>
+#include <reloc.h>
+#endif
+#ifndef N_TEXT
+#define N_TEXT 0x04
+#define N_DATA 0x06
+#define N_BSS 0x08
+#endif
+#include <sys/loader.h>
+#endif
+
+#ifndef N_SET_MAGIC
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = val)
+#endif
+
+/* If compiled with GNU C, use the built-in alloca */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if defined(sun) && defined(sparc)
+# include "alloca.h"
+# else
+char *alloca ();
+# endif
+#endif
+
+#include "getopt.h"
+
+/* Always use the GNU version of debugging symbol type codes, if possible. */
+
+#include "stab.h"
+#define CORE_ADDR unsigned long /* For symseg.h */
+#include "symseg.h"
+
+#ifdef USG
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* Determine whether we should attempt to handle (minimally)
+ N_BINCL and N_EINCL. */
+
+#if defined (__GNU_STAB__) || defined (N_BINCL)
+#define HAVE_SUN_STABS
+#endif
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+/* Macro to control the number of undefined references printed */
+#define MAX_UREFS_PRINTED 10
+
+/* Size of a page; obtained from the operating system. */
+
+int page_size;
+
+/* Name this program was invoked by. */
+
+char *progname;
+
+/* System dependencies */
+
+/* Define this if names etext, edata and end should not start with `_'. */
+/* #define nounderscore 1 */
+
+/* Define NON_NATIVE if using BSD or pseudo-BSD file format on a system
+ whose native format is different. */
+/* #define NON_NATIVE */
+
+/* Define this to specify the default executable format. */
+
+#ifdef hpux
+#define DEFAULT_OUTPUT_STYLE OUTPUT_READONLY_TEXT
+#endif
+
+/* Ordinary 4.3bsd lacks these macros in a.out.h. */
+
+#ifndef N_TXTADDR
+#if defined(vax) || defined(sony_news) || defined(hp300) || defined(pyr)
+#define N_TXTADDR(X) 0
+#endif
+#ifdef is68k
+#define N_TXTADDR(x) (sizeof (struct exec))
+#endif
+#ifdef sequent
+#define N_TXTADDR(x) (N_ADDRADJ(x))
+#endif
+#ifdef tek4300
+#define N_TXTADDR(x) ((x).a_magic == ZMAGIC ? page_size : 0)
+#endif
+#ifdef NeXT
+#define N_TXTADDR(X) ((X).a_magic == ZMAGIC ? page_size : 0)
+#endif
+#endif
+
+#ifndef N_DATADDR
+#if defined(vax) || defined(sony_news) || defined(hp300) || defined(pyr)
+#define N_DATADDR(x) \
+ (((x).a_magic==OMAGIC)? (N_TXTADDR(x)+(x).a_text) \
+ : (page_size+((N_TXTADDR(x)+(x).a_text-1) & ~(page_size-1))))
+#endif
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#define N_DATADDR(x) \
+ (((x).a_magic==Omagic)? (N_TXTADDR(x)+(x).a_text) \
+ : (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))))
+#endif
+#ifdef sequent
+#define N_DATADDR(x) \
+ (((x).a_magic==OMAGIC)? (N_TXTADDR(x)+(x).a_text) \
+ : (page_size+(((x).a_text-1) & ~(page_size-1))))
+#endif
+#ifdef tek4300
+#define N_DATADDR(x) \
+ (((x).a_magic==OMAGIC)? (N_TXTADDR(x)+(x).a_text) \
+ : (page_size+((N_TXTADDR(x)+(x).a_text-1) & ~(page_size-1))))
+#endif
+#ifdef NeXT
+#define N_DATADDR(X) \
+ (((X).a_magic==ZMAGIC)?(N_TXTADDR(X)+(X).a_text+0xFFFF)&~0xFFFF \
+ :N_TXTADDR(X)+(X).a_text)
+#endif
+#endif
+
+/* The "address" of the data segment in a relocatable file.
+ The text address of a relocatable file is always
+ considered to be zero (instead of the value of N_TXTADDR, which
+ is what the address is in an executable), so we need to subtract
+ N_TXTADDR from N_DATADDR to get the "address" for the input file. */
+#define DATA_ADDR_DOT_O(hdr) (N_DATADDR(hdr) - N_TXTADDR(hdr))
+
+/* Define how to initialize system-dependent header fields. */
+#ifdef sun
+#ifdef sparc
+#define INITIALIZE_HEADER \
+ {outheader.a_machtype = M_SPARC; outheader.a_toolversion = 1;}
+#endif /* sparc. */
+#if defined(mc68000)
+/* Set the machine type according to the machine type of the .o files.
+ If they are all sun2 (68010), then the type of the executable is sun2.
+ If any is sun3 (68020), then the type of the executable is sun3.
+ This is consistent with the Sun loader and more useful than having
+ it depend on which machine you are on when you run ld. */
+static int sun_machtype = M_68010;
+#define INITIALIZE_HEADER outheader.a_machtype = sun_machtype
+#define READ_HEADER_HOOK(machtype) \
+ if (machtype == M_68020) \
+ { \
+ sun_machtype = M_68020; \
+ }
+#endif /* mc68000. */
+#endif /* Sun. */
+
+#ifdef ALTOS
+#define INITIALIZE_HEADER N_SET_MACHTYPE (outheader, M_68020)
+#endif
+#ifdef is68k
+#ifdef M_68020
+/* ISI rel 4.0D doesn't use it, and rel 3.05 doesn't have an
+ a_machtype field and so won't recognize the magic number. To keep
+ binary compatibility for now, just ignore it */
+#define INITIALIZE_HEADER outheader.a_machtype = 0;
+#endif
+#endif
+#ifdef hpux
+#define INITIALIZE_HEADER N_SET_MACHTYPE (outheader, HP9000S200_ID)
+#endif
+#if defined(i386) && !defined(sequent)
+#define INITIALIZE_HEADER N_SET_MACHTYPE (outheader, M_386)
+#endif /* Sequent symmetry. */
+#if defined(hp300)
+#define INITIALIZE_HEADER outheader.a_mid = MID_HP300
+/* MORE/bsd tags the filename symbol with N_FN|N_EXT not N_TEXT */
+#define OFILE_FN_FLAGGED
+#endif /* hp300. */
+#ifdef pyr
+#define INITIALIZE_HEADER outheader.a_machid = PYR90X
+#endif /* Pyramid. */
+
+#ifdef tek4300
+#undef INITIALIZE_HEADER
+#define INITIALIZE_HEADER (outheader).a_archclass = ARCHCLASS_MC68020, (outheader).a_textoff = ZMOFF
+/* The alternative to the following patch is to change field "header"
+ in struct file_entry, from struct exec to struct zexec; this affects
+ the -A option */
+#undef N_DATOFF
+#define N_DATOFF(x) ( (x).a_magic==ZMAGIC \
+ ? (ZMOFF + (x).a_text) \
+ : (sizeof (struct exec) + (x).a_text) )
+#endif
+
+#ifdef is68k
+/* This enables code to take care of an ugly hack in the ISI OS.
+ If a symbol beings with _$, then the object file is included only
+ if the rest of the symbol name has been referenced. */
+#define DOLLAR_KLUDGE
+#endif
+
+/* Values for 3rd argument to lseek(). */
+#ifndef L_SET
+#define L_SET 0
+#endif
+/* This is called L_INCR in BSD, but SEEK_CUR in POSIX. */
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+/*
+ * Ok. Following are the relocation information macros. If your
+ * system cannot use the default set (below), you must define all of these:
+
+ * relocation_info: This must be typedef'd (or #define'd) to the type
+ * of structure that is stored in the relocation info section of your
+ * a.out files. Often this is defined in the a.out.h for your system.
+ *
+ * RELOC_ADDRESS (rval): Offset into the current section of the
+ * <whatever> to be relocated. *Must be an lvalue*.
+ *
+ * RELOC_EXTERN_P (rval): Is this relocation entry based on an
+ * external symbol (1), or was it fully resolved upon entering the
+ * loader (0) in which case some combination of the value in memory
+ * (if RELOC_MEMORY_ADD_P) and the extra (if RELOC_ADD_EXTRA) contains
+ * what the value of the relocation actually was. *Must be an lvalue*.
+ *
+ * RELOC_TYPE (rval): For a non-external relocation, this is the
+ * segment to relocate for. *Must be an lvalue.*
+ *
+ * RELOC_SYMBOL (rval): For an external relocation, this is the
+ * index of its symbol in the symbol table. *Must be an lvalue*.
+ *
+ * RELOC_MEMORY_ADD_P (rval): This should be 1 if the final
+ * relocation value output here should be added to memory; 0, if the
+ * section of memory described should simply be set to the relocation
+ * value.
+ *
+ * RELOC_MEMORY_ADD_P (rval): If this is nonzero, the value previously
+ * present in the memory location to be relocated is *added*
+ * to the relocation value, to produce the final result.
+ * Otherwise, the relocation value is stored in the memory location
+ * and the value previously found there is ignored.
+ * By default, this is always 1.
+ *
+ * RELOC_MEMORY_SUB_P (rval): If this is nonzero, the value previously
+ * present in the memory location to be relocated is *subtracted*
+ * from the relocation value, to produce the final result.
+ * By default, this is always 0.
+ *
+ * RELOC_ADD_EXTRA (rval): (Optional) This macro, if defined, gives
+ * an extra value to be added to the relocation value based on the
+ * individual relocation entry. *Must be an lvalue if defined*.
+ *
+ * RELOC_PCREL_P (rval): True if the relocation value described is
+ * pc relative.
+ *
+ * RELOC_VALUE_RIGHTSHIFT (rval): Number of bits right to shift the
+ * final relocation value before putting it where it belongs.
+ *
+ * RELOC_TARGET_SIZE (rval): log to the base 2 of the number of
+ * bytes of size this relocation entry describes; 1 byte == 0; 2 bytes
+ * == 1; 4 bytes == 2, and etc. This is somewhat redundant (we could
+ * do everything in terms of the bit operators below), but having this
+ * macro could end up producing better code on machines without fancy
+ * bit twiddling. Also, it's easier to understand/code big/little
+ * endian distinctions with this macro.
+ *
+ * RELOC_TARGET_BITPOS (rval): The starting bit position within the
+ * object described in RELOC_TARGET_SIZE in which the relocation value
+ * will go.
+ *
+ * RELOC_TARGET_BITSIZE (rval): How many bits are to be replaced
+ * with the bits of the relocation value. It may be assumed by the
+ * code that the relocation value will fit into this many bits. This
+ * may be larger than RELOC_TARGET_SIZE if such be useful.
+ *
+ *
+ * Things I haven't implemented
+ * ----------------------------
+ *
+ * Values for RELOC_TARGET_SIZE other than 0, 1, or 2.
+ *
+ * Pc relative relocation for External references.
+ *
+ *
+ */
+
+#if defined(sun) && defined(sparc)
+/* Sparc (Sun 4) macros */
+#undef relocation_info
+#define relocation_info reloc_info_sparc
+#define RELOC_ADDRESS(r) ((r)->r_address)
+#define RELOC_EXTERN_P(r) ((r)->r_extern)
+#define RELOC_TYPE(r) ((r)->r_index)
+#define RELOC_SYMBOL(r) ((r)->r_index)
+#define RELOC_MEMORY_SUB_P(r) 0
+#define RELOC_MEMORY_ADD_P(r) 0
+#define RELOC_ADD_EXTRA(r) ((r)->r_addend)
+#define RELOC_PCREL_P(r) \
+ ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
+#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type])
+#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type])
+#define RELOC_TARGET_BITPOS(r) 0
+#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type])
+
+/* Note that these are very dependent on the order of the enums in
+ enum reloc_type (in a.out.h); if they change the following must be
+ changed */
+/* Also note that the last few may be incorrect; I have no information */
+static int reloc_target_rightshift[] = {
+ 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
+};
+static int reloc_target_size[] = {
+ 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+static int reloc_target_bitsize[] = {
+ 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
+};
+
+#define MAX_ALIGNMENT (sizeof (double))
+#endif
+
+#if defined(sequent) || defined(ns32000)
+#define RELOC_ADDRESS(r) ((r)->r_address)
+#define RELOC_EXTERN_P(r) ((r)->r_extern)
+#define RELOC_TYPE(r) ((r)->r_symbolnum)
+#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
+#ifdef sequent /* I think r_bsr is needed only for compat.
+ with sequent object files, or that's
+ what Ian has done. But might be that
+ this is needed for all 32k machines.*/
+#define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr)
+#else
+#define RELOC_MEMORY_SUB_P(r) 0
+#endif
+#define RELOC_MEMORY_ADD_P(r) 1
+#undef RELOC_ADD_EXTRA
+#ifdef sequent /* might need to be on all 32k machines */
+#define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr)
+#else
+#define RELOC_PCREL_P(r) ((r)->r_pcrel)
+#endif
+#define RELOC_VALUE_RIGHTSHIFT(r) 0
+#define RELOC_TARGET_SIZE(r) ((r)->r_length)
+#define RELOC_TARGET_BITPOS(r) 0
+#define RELOC_TARGET_BITSIZE(r) 32
+#endif
+
+/* Default macros */
+#ifndef RELOC_ADDRESS
+#define RELOC_ADDRESS(r) ((r)->r_address)
+#define RELOC_EXTERN_P(r) ((r)->r_extern)
+#define RELOC_TYPE(r) ((r)->r_symbolnum)
+#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
+#define RELOC_MEMORY_SUB_P(r) 0
+#define RELOC_MEMORY_ADD_P(r) 1
+#undef RELOC_ADD_EXTRA
+#define RELOC_PCREL_P(r) ((r)->r_pcrel)
+#define RELOC_VALUE_RIGHTSHIFT(r) 0
+#define RELOC_TARGET_SIZE(r) ((r)->r_length)
+#define RELOC_TARGET_BITPOS(r) 0
+#define RELOC_TARGET_BITSIZE(r) 32
+#endif
+
+#ifndef MAX_ALIGNMENT
+#define MAX_ALIGNMENT (sizeof (int))
+#endif
+
+#ifdef nounderscore
+#define LPREFIX '.'
+#else
+#define LPREFIX 'L'
+#endif
+
+
+/* Special global symbol types understood by GNU LD. */
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition.
+
+ So, for example, the following two lines placed in an assembler
+ input file would result in an object file which would direct gnu ld
+ to resolve all references to symbol "foo" as references to symbol
+ "bar".
+
+ .stabs "_foo",11,0,0,0
+ .stabs "_bar",1,0,0,0
+
+ Note that (11 == (N_INDR | N_EXT)) and (1 == (N_UNDF | N_EXT)). */
+
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* The following symbols refer to set elements. These are expected
+ only in input to the loader; they should not appear in loader
+ output (unless relocatable output is requested). To be recognized
+ by the loader, the input symbols must have their N_EXT bit set.
+ All the N_SET[ATDB] symbols with the same name form one set. The
+ loader collects all of these elements at load time and outputs a
+ vector for each name.
+ Space (an array of 32 bit words) is allocated for the set in the
+ data section, and the n_value field of each set element value is
+ stored into one word of the array.
+ The first word of the array is the length of the set (number of
+ elements). The last word of the vector is set to zero for possible
+ use by incremental loaders. The array is ordered by the linkage
+ order; the first symbols which the linker encounters will be first
+ in the array.
+
+ In C syntax this looks like:
+
+ struct set_vector {
+ unsigned int length;
+ unsigned int vector[length];
+ unsigned int always_zero;
+ };
+
+ Before being placed into the array, each element is relocated
+ according to its type. This allows the loader to create an array
+ of pointers to objects automatically. N_SETA type symbols will not
+ be relocated.
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references.
+
+ For the purposes of determining whether or not to load in a library
+ file, set element definitions are not considered "real
+ definitions"; they will not cause the loading of a library
+ member.
+
+ If relocatable output is requested, none of this processing is
+ done. The symbols are simply relocated and passed through to the
+ output file.
+
+ So, for example, the following three lines of assembler code
+ (whether in one file or scattered between several different ones)
+ will produce a three element vector (total length is five words;
+ see above), referenced by the symbol "_xyzzy", which will have the
+ addresses of the routines _init1, _init2, and _init3.
+
+ *NOTE*: If symbolic addresses are used in the n_value field of the
+ defining .stabs, those symbols must be defined in the same file as
+ that containing the .stabs.
+
+ .stabs "_xyzzy",23,0,0,_init1
+ .stabs "_xyzzy",23,0,0,_init2
+ .stabs "_xyzzy",23,0,0,_init3
+
+ Note that (23 == (N_SETT | N_EXT)). */
+
+#ifndef N_SETA
+#define N_SETA 0x14 /* Absolute set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETT
+#define N_SETT 0x16 /* Text set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETD
+#define N_SETD 0x18 /* Data set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETB
+#define N_SETB 0x1A /* Bss set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+/* Macros dealing with the set element symbols defined in a.out.h */
+#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
+#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)
+
+#ifndef N_SETV
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+#endif /* This is output from LD. */
+
+/* If a this type of symbol is encountered, its name is a warning
+ message to print each time the symbol referenced by the next symbol
+ table entry is referenced.
+
+ This feature may be used to allow backwards compatibility with
+ certain functions (eg. gets) but to discourage programmers from
+ their use.
+
+ So if, for example, you wanted to have ld print a warning whenever
+ the function "gets" was used in their C program, you would add the
+ following to the assembler file in which gets is defined:
+
+ .stabs "Obsolete function \"gets\" referenced",30,0,0,0
+ .stabs "_gets",1,0,0,0
+
+ These .stabs do not necessarily have to be in the same file as the
+ gets function, they simply must exist somewhere in the compilation. */
+
+#ifndef N_WARNING
+#define N_WARNING 0x1E /* Warning message to print if symbol
+ included */
+#endif /* This is input to ld */
+
+#ifndef __GNU_STAB__
+
+/* Line number for the data section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_DSLINE
+#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
+#endif
+
+/* Line number for the bss section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_BSLINE
+#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
+#endif
+
+#endif /* not __GNU_STAB__ */
+
+/* Symbol table */
+
+/* Global symbol data is recorded in these structures,
+ one for each global symbol.
+ They are found via hashing in 'symtab', which points to a vector of buckets.
+ Each bucket is a chain of these structures through the link field. */
+
+typedef
+ struct glosym
+ {
+ /* Pointer to next symbol in this symbol's hash bucket. */
+ struct glosym *link;
+ /* Name of this symbol. */
+ char *name;
+ /* Value of this symbol as a global symbol. */
+ long value;
+ /* Chain of external 'nlist's in files for this symbol, both defs
+ and refs. */
+ struct nlist *refs;
+ /* Any warning message that might be associated with this symbol
+ from an N_WARNING symbol encountered. */
+ char *warning;
+ /* Nonzero means definitions of this symbol as common have been seen,
+ and the value here is the largest size specified by any of them. */
+ int max_common_size;
+ /* For OUTPUT_RELOCATABLE, records the index of this global sym in the
+ symbol table to be written, with the first global sym given index 0.*/
+ int def_count;
+ /* Nonzero means a definition of this global symbol is known to exist.
+ Library members should not be loaded on its account. */
+ char defined;
+ /* Nonzero means a reference to this global symbol has been seen
+ in a file that is surely being loaded.
+ A value higher than 1 is the n_type code for the symbol's
+ definition. */
+ char referenced;
+ /* A count of the number of undefined references printed for a
+ specific symbol. If a symbol is unresolved at the end of
+ digest_symbols (and the loading run is supposed to produce
+ relocatable output) do_file_warnings keeps track of how many
+ unresolved reference error messages have been printed for
+ each symbol here. When the number hits MAX_UREFS_PRINTED,
+ messages stop. */
+ unsigned char undef_refs;
+ /* 1 means that this symbol has multiple definitions. 2 means
+ that it has multiple definitions, and some of them are set
+ elements, one of which has been printed out already. */
+ unsigned char multiply_defined;
+ /* Pointer to the file_entry for the last library that contained a
+ subfile referencing this symbol. */
+ struct file_entry *last_library_ref;
+ /* Nonzero means print a message at all refs or defs of this symbol */
+ char trace;
+ }
+ symbol;
+
+/* Demangler for C++. */
+extern char *cplus_demangle ();
+
+/* Demangler function to use. We unconditionally enable the C++ demangler
+ because we assume any name it successfully demangles was probably produced
+ by the C++ compiler. Enabling it only if -lg++ was specified seems too
+ much of a kludge. */
+char *(*demangler)() = cplus_demangle;
+
+/* Number of buckets in symbol hash table */
+#define TABSIZE 1009
+
+/* The symbol hash table: a vector of TABSIZE pointers to struct glosym. */
+symbol *symtab[TABSIZE];
+
+/* Number of symbols in symbol hash table. */
+int num_hash_tab_syms = 0;
+
+/* Count the number of nlist entries that are for local symbols.
+ This count and the three following counts
+ are incremented as as symbols are entered in the symbol table. */
+int local_sym_count;
+
+/* Count number of nlist entries that are for local symbols
+ whose names don't start with L. */
+int non_L_local_sym_count;
+
+/* Count the number of nlist entries for debugger info. */
+int debugger_sym_count;
+
+/* Count the number of global symbols referenced and not defined. */
+int undefined_global_sym_count;
+
+/* Count the number of global symbols multiply defined. */
+int multiple_def_count;
+
+/* Count the number of defined global symbols.
+ Each symbol is counted only once
+ regardless of how many different nlist entries refer to it,
+ since the output file will need only one nlist entry for it.
+ This count is computed by `digest_symbols';
+ it is undefined while symbols are being loaded. */
+int defined_global_sym_count;
+
+/* Count the number of symbols defined through common declarations.
+ This count is kept in symdef_library, linear_library, and
+ enter_global_ref. It is incremented when the defined flag is set
+ in a symbol because of a common definition, and decremented when
+ the symbol is defined "for real" (ie. by something besides a common
+ definition). */
+int common_defined_global_count;
+
+/* Count the number of set element type symbols and the number of
+ separate vectors which these symbols will fit into. See the
+ GNU a.out.h for more info.
+ This count is computed by 'enter_file_symbols' */
+int set_symbol_count;
+int set_vector_count;
+
+/* Define a linked list of strings which define symbols which should
+ be treated as set elements even though they aren't. Any symbol
+ with a prefix matching one of these should be treated as a set
+ element.
+
+ This is to make up for deficiencies in many assemblers which aren't
+ willing to pass any stabs through to the loader which they don't
+ understand. */
+struct string_list_element {
+ char *str;
+ struct string_list_element *next;
+};
+
+struct string_list_element *set_element_prefixes;
+
+/* Count the number of definitions done indirectly (ie. done relative
+ to the value of some other symbol. */
+int global_indirect_count;
+
+/* Count the number of warning symbols encountered. */
+int warning_count;
+
+/* Total number of symbols to be written in the output file.
+ Computed by digest_symbols from the variables above. */
+int nsyms;
+
+
+/* Nonzero means ptr to symbol entry for symbol to use as start addr.
+ -e sets this. */
+symbol *entry_symbol;
+
+/* These can be NULL if we don't actually have such a symbol. */
+symbol *edata_symbol; /* the symbol _edata */
+symbol *etext_symbol; /* the symbol _etext */
+symbol *end_symbol; /* the symbol _end */
+/* We also need __{edata,etext,end} so that they can safely
+ be used from an ANSI library. */
+symbol *edata_symbol_alt;
+symbol *etext_symbol_alt;
+symbol *end_symbol_alt;
+
+/* Kinds of files potentially understood by the linker. */
+
+enum file_type { IS_UNKNOWN, IS_ARCHIVE, IS_A_OUT, IS_MACH_O };
+
+/* Each input file, and each library member ("subfile") being loaded,
+ has a `file_entry' structure for it.
+
+ For files specified by command args, these are contained in the vector
+ which `file_table' points to.
+
+ For library members, they are dynamically allocated,
+ and chained through the `chain' field.
+ The chain is found in the `subfiles' field of the `file_entry'.
+ The `file_entry' objects for the members have `superfile' fields pointing
+ to the one for the library. */
+
+struct file_entry {
+ /* Name of this file. */
+ char *filename;
+
+ /* What kind of file this is. */
+ enum file_type file_type;
+
+ /* Name to use for the symbol giving address of text start */
+ /* Usually the same as filename, but for a file spec'd with -l
+ this is the -l switch itself rather than the filename. */
+ char *local_sym_name;
+
+ /* Describe the layout of the contents of the file. */
+
+ /* The text section. */
+ unsigned long int orig_text_address;
+ unsigned long int text_size;
+ long int text_offset;
+
+ /* Text relocation. */
+ unsigned long int text_reloc_size;
+ long int text_reloc_offset;
+
+ /* The data section. */
+ unsigned long int orig_data_address;
+ unsigned long int data_size;
+ long int data_offset;
+
+ /* Data relocation. */
+ unsigned long int data_reloc_size;
+ long int data_reloc_offset;
+
+ /* The bss section. */
+ unsigned long int orig_bss_address;
+ unsigned long int bss_size;
+
+ /* The symbol and string tables. */
+ unsigned long int syms_size;
+ long int syms_offset;
+ unsigned long int strs_size;
+ long int strs_offset;
+
+ /* The GDB symbol segment, if any. */
+ unsigned long int symseg_size;
+ long int symseg_offset;
+
+#ifdef MACH_O
+ /* Section ordinals from the Mach-O load commands. These
+ are compared with the n_sect fields of symbols. */
+ int text_ordinal;
+ int data_ordinal;
+ int bss_ordinal;
+#endif
+
+ /* Describe data from the file loaded into core */
+
+ /* Symbol table of the file. */
+ struct nlist *symbols;
+
+ /* Pointer to the string table.
+ The string table is not kept in core all the time,
+ but when it is in core, its address is here. */
+ char *strings;
+
+ /* Next two used only if OUTPUT_RELOCATABLE or if needed for */
+ /* output of undefined reference line numbers. */
+
+ /* Text reloc info saved by `write_text' for `coptxtrel'. */
+ struct relocation_info *textrel;
+ /* Data reloc info saved by `write_data' for `copdatrel'. */
+ struct relocation_info *datarel;
+
+ /* Relation of this file's segments to the output file */
+
+ /* Start of this file's text seg in the output file core image. */
+ int text_start_address;
+ /* Start of this file's data seg in the output file core image. */
+ int data_start_address;
+ /* Start of this file's bss seg in the output file core image. */
+ int bss_start_address;
+ /* Offset in bytes in the output file symbol table
+ of the first local symbol for this file. Set by `write_file_symbols'. */
+ int local_syms_offset;
+
+ /* For library members only */
+
+ /* For a library, points to chain of entries for the library members. */
+ struct file_entry *subfiles;
+ /* For a library member, offset of the member within the archive.
+ Zero for files that are not library members. */
+ int starting_offset;
+ /* Size of contents of this file, if library member. */
+ int total_size;
+ /* For library member, points to the library's own entry. */
+ struct file_entry *superfile;
+ /* For library member, points to next entry for next member. */
+ struct file_entry *chain;
+
+ /* 1 if file is a library. */
+ char library_flag;
+
+ /* 1 if file's header has been read into this structure. */
+ char header_read_flag;
+
+ /* 1 means search a set of directories for this file. */
+ char search_dirs_flag;
+
+ /* 1 means this is base file of incremental load.
+ Do not load this file's text or data.
+ Also default text_start to after this file's bss. */
+ char just_syms_flag;
+};
+
+/* Vector of entries for input files specified by arguments.
+ These are all the input files except for members of specified libraries. */
+struct file_entry *file_table;
+
+/* Length of that vector. */
+int number_of_files;
+
+/* When loading the text and data, we can avoid doing a close
+ and another open between members of the same library.
+
+ These two variables remember the file that is currently open.
+ Both are zero if no file is open.
+
+ See `each_file' and `file_close'. */
+
+struct file_entry *input_file;
+int input_desc;
+
+/* The name of the file to write; "a.out" by default. */
+
+char *output_filename;
+
+/* What kind of output file to write. */
+
+enum file_type output_file_type;
+
+#ifndef DEFAULT_OUTPUT_FILE_TYPE
+#ifdef MACH_O
+#define DEFAULT_OUTPUT_FILE_TYPE IS_MACH_O
+#else
+#define DEFAULT_OUTPUT_FILE_TYPE IS_A_OUT
+#endif
+#endif
+
+/* What `style' of output file to write. For BSD a.out files
+ this specifies OMAGIC, NMAGIC, or ZMAGIC. For Mach-O files
+ this switches between MH_OBJECT and two flavors of MH_EXECUTE. */
+
+enum output_style
+ {
+ OUTPUT_UNSPECIFIED,
+ OUTPUT_RELOCATABLE, /* -r */
+ OUTPUT_WRITABLE_TEXT, /* -N */
+ OUTPUT_READONLY_TEXT, /* -n */
+ OUTPUT_DEMAND_PAGED /* -Z (default) */
+ };
+
+enum output_style output_style;
+
+#ifndef DEFAULT_OUTPUT_STYLE
+#define DEFAULT_OUTPUT_STYLE OUTPUT_DEMAND_PAGED
+#endif
+
+/* Descriptor for writing that file with `mywrite'. */
+
+int outdesc;
+
+/* The following are computed by `digest_symbols'. */
+
+int text_size; /* total size of text of all input files. */
+int text_header_size; /* size of the file header if included in the
+ text size. */
+int data_size; /* total size of data of all input files. */
+int bss_size; /* total size of bss of all input files. */
+int text_reloc_size; /* total size of text relocation of all input files. */
+int data_reloc_size; /* total size of data relocation of all input
+ files. */
+
+/* The following are computed by write_header(). */
+long int output_text_offset; /* file offset of the text section. */
+long int output_data_offset; /* file offset of the data section. */
+long int output_trel_offset; /* file offset of the text relocation info. */
+long int output_drel_offset; /* file offset of the data relocation info. */
+long int output_syms_offset; /* file offset of the symbol table. */
+long int output_strs_offset; /* file offset of the string table. */
+
+/* The following are incrementally computed by write_syms(); we keep
+ them here so we can examine their values afterwards. */
+unsigned int output_syms_size; /* total bytes of symbol table output. */
+unsigned int output_strs_size; /* total bytes of string table output. */
+
+/* This can only be computed after the size of the string table is known. */
+long int output_symseg_offset; /* file offset of the symbol segment (if any). */
+
+/* Incrementally computed by write_file_symseg(). */
+unsigned int output_symseg_size;
+
+/* Specifications of start and length of the area reserved at the end
+ of the text segment for the set vectors. Computed in 'digest_symbols' */
+int set_sect_start;
+int set_sect_size;
+
+/* Pointer for in core storage for the above vectors, before they are
+ written. */
+unsigned long *set_vectors;
+
+/* Amount of cleared space to leave at the end of the text segment. */
+
+int text_pad;
+
+/* Amount of padding at end of data segment. This has two parts:
+ That which is before the bss segment, and that which overlaps
+ with the bss segment. */
+int data_pad;
+
+/* Format of __.SYMDEF:
+ First, a longword containing the size of the 'symdef' data that follows.
+ Second, zero or more 'symdef' structures.
+ Third, a longword containing the length of symbol name strings.
+ Fourth, zero or more symbol name strings (each followed by a null). */
+
+struct symdef {
+ int symbol_name_string_index;
+ int library_member_offset;
+};
+
+/* Record most of the command options. */
+
+/* Address we assume the text section will be loaded at.
+ We relocate symbols and text and data for this, but we do not
+ write any padding in the output file for it. */
+int text_start;
+
+/* Address we decide the data section will be loaded at. */
+int data_start;
+
+/* Nonzero if -T was specified in the command line.
+ This prevents text_start from being set later to default values. */
+int T_flag_specified;
+
+/* Nonzero if -Tdata was specified in the command line.
+ This prevents data_start from being set later to default values. */
+int Tdata_flag_specified;
+
+/* Size to pad data section up to.
+ We simply increase the size of the data section, padding with zeros,
+ and reduce the size of the bss section to match. */
+int specified_data_size;
+
+/* Nonzero means print names of input files as processed. */
+int trace_files;
+
+/* Which symbols should be stripped (omitted from the output):
+ none, all, or debugger symbols. */
+enum { STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER } strip_symbols;
+
+/* Which local symbols should be omitted:
+ none, all, or those starting with L.
+ This is irrelevant if STRIP_NONE. */
+enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals;
+
+/* 1 => write load map. */
+int write_map;
+
+/* 1 => assign space to common symbols even if OUTPUT_RELOCATABLE. */
+int force_common_definition;
+
+/* Standard directories to search for files specified by -l. */
+char *standard_search_dirs[] =
+#ifdef STANDARD_SEARCH_DIRS
+ {STANDARD_SEARCH_DIRS};
+#else
+#ifdef NON_NATIVE
+ {"/usr/local/lib/gnu"};
+#else
+ {"/lib", "/usr/lib", "/usr/local/lib"};
+#endif
+#endif
+
+/* If set STANDARD_SEARCH_DIRS is not searched. */
+int no_standard_dirs;
+
+/* Actual vector of directories to search;
+ this contains those specified with -L plus the standard ones. */
+char **search_dirs;
+
+/* Length of the vector `search_dirs'. */
+int n_search_dirs;
+
+/* Non zero means to create the output executable.
+ Cleared by nonfatal errors. */
+int make_executable;
+
+/* Force the executable to be output, even if there are non-fatal
+ errors */
+int force_executable;
+
+/* Keep a list of any symbols referenced from the command line (so
+ that error messages for these guys can be generated). This list is
+ zero terminated. */
+struct glosym **cmdline_references;
+int cl_refs_allocated;
+
+#ifndef bcopy
+void bcopy (), bzero ();
+#endif
+char *malloc (), *realloc ();
+void free ();
+
+char *xmalloc ();
+char *xrealloc ();
+void usage ();
+void fatal ();
+void fatal_with_file ();
+void perror_name ();
+void perror_file ();
+void error ();
+
+int parse ();
+void initialize_text_start ();
+void initialize_data_start ();
+void digest_symbols ();
+void print_symbols ();
+void load_symbols ();
+void decode_command ();
+void list_undefined_symbols ();
+void list_unresolved_references ();
+void write_output ();
+void write_header ();
+void write_text ();
+void read_file_relocation ();
+void write_data ();
+void write_rel ();
+void write_syms ();
+void write_symsegs ();
+void mywrite ();
+void symtab_init ();
+void padfile ();
+char *concat ();
+char *get_file_name ();
+symbol *getsym (), *getsym_soft ();
+
+int
+main (argc, argv)
+ char **argv;
+ int argc;
+{
+ page_size = getpagesize ();
+ progname = argv[0];
+
+#ifdef RLIMIT_STACK
+ /* Avoid dumping core on large .o files. */
+ {
+ struct rlimit rl;
+
+ getrlimit (RLIMIT_STACK, &rl);
+ rl.rlim_cur = rl.rlim_max;
+ setrlimit (RLIMIT_STACK, &rl);
+ }
+#endif
+
+ /* Clear the cumulative info on the output file. */
+
+ text_size = 0;
+ data_size = 0;
+ bss_size = 0;
+ text_reloc_size = 0;
+ data_reloc_size = 0;
+
+ data_pad = 0;
+ text_pad = 0;
+
+ /* Initialize the data about options. */
+
+ specified_data_size = 0;
+ strip_symbols = STRIP_NONE;
+ trace_files = 0;
+ discard_locals = DISCARD_NONE;
+ entry_symbol = 0;
+ write_map = 0;
+ force_common_definition = 0;
+ T_flag_specified = 0;
+ Tdata_flag_specified = 0;
+ make_executable = 1;
+ force_executable = 0;
+ set_element_prefixes = 0;
+
+ /* Initialize the cumulative counts of symbols. */
+
+ local_sym_count = 0;
+ non_L_local_sym_count = 0;
+ debugger_sym_count = 0;
+ undefined_global_sym_count = 0;
+ set_symbol_count = 0;
+ set_vector_count = 0;
+ global_indirect_count = 0;
+ warning_count = 0;
+ multiple_def_count = 0;
+ common_defined_global_count = 0;
+
+ /* Keep a list of symbols referenced from the command line */
+
+ cl_refs_allocated = 10;
+ cmdline_references
+ = (struct glosym **) xmalloc (cl_refs_allocated
+ * sizeof(struct glosym *));
+ *cmdline_references = 0;
+
+ /* Completely decode ARGV. */
+
+ decode_command (argc, argv);
+
+ /* Load symbols of all input files.
+ Also search all libraries and decide which library members to load. */
+
+ load_symbols ();
+
+ /* Create various built-in symbols. This must occur after
+ all input files are loaded so that a user program can have a
+ symbol named etext (for example). */
+
+ if (output_style != OUTPUT_RELOCATABLE)
+ symtab_init ();
+
+ /* Compute where each file's sections go, and relocate symbols. */
+
+ digest_symbols ();
+
+ /* Print error messages for any missing symbols, for any warning
+ symbols, and possibly multiple definitions */
+
+ do_warnings (stderr);
+
+ /* Print a map, if requested. */
+
+ if (write_map) print_symbols (stdout);
+
+ /* Write the output file. */
+
+ if (make_executable || force_executable)
+ write_output ();
+
+ exit (!make_executable);
+}
+
+void add_cmdline_ref ();
+
+static struct option longopts[] =
+{
+ {"d", 0, 0, 'd'},
+ {"dc", 0, 0, 'd'}, /* For Sun compatibility. */
+ {"dp", 0, 0, 'd'}, /* For Sun compatibility. */
+ {"e", 1, 0, 'e'},
+ {"n", 0, 0, 'n'},
+ {"noinhibit-exec", 0, 0, 130},
+ {"nostdlib", 0, 0, 133},
+ {"o", 1, 0, 'o'},
+ {"r", 0, 0, 'r'},
+ {"s", 0, 0, 's'},
+ {"t", 0, 0, 't'},
+ {"u", 1, 0, 'u'},
+ {"x", 0, 0, 'x'},
+ {"z", 0, 0, 'z'},
+ {"A", 1, 0, 'A'},
+ {"Bstatic", 0, 0, 129}, /* For Sun compatibility. */
+ {"D", 1, 0, 'D'},
+ {"M", 0, 0, 'M'},
+ {"N", 0, 0, 'N'},
+ {"S", 0, 0, 'S'},
+ {"T", 1, 0, 'T'},
+ {"Ttext", 1, 0, 'T'},
+ {"Tdata", 1, 0, 132},
+ {"V", 1, 0, 'V'},
+ {"X", 0, 0, 'X'},
+ {0, 0, 0, 0}
+};
+
+/* Since the Unix ld accepts -lfoo, -Lfoo, and -yfoo, we must also.
+ This effectively prevents any long options from starting with
+ one of these letters. */
+#define SHORTOPTS "-l:y:L:"
+
+/* Process the command arguments,
+ setting up file_table with an entry for each input file,
+ and setting variables according to the options. */
+
+void
+decode_command (argc, argv)
+ char **argv;
+ int argc;
+{
+ int optc, longind;
+ register struct file_entry *p;
+
+ number_of_files = 0;
+ output_filename = "a.out";
+
+ n_search_dirs = 0;
+ search_dirs = (char **) xmalloc (sizeof (char *));
+
+ /* First compute number_of_files so we know how long to make file_table.
+ Also process most options completely. */
+
+ while ((optc = getopt_long_only (argc, argv, SHORTOPTS, longopts, &longind))
+ != EOF)
+ {
+ if (optc == 0)
+ optc = longopts[longind].val;
+
+ switch (optc)
+ {
+ case '?':
+ usage (0, 0);
+ break;
+
+ case 1:
+ /* Non-option argument. */
+ number_of_files++;
+ break;
+
+ case 'd':
+ force_common_definition = 1;
+ break;
+
+ case 'e':
+ entry_symbol = getsym (optarg);
+ if (!entry_symbol->defined && !entry_symbol->referenced)
+ undefined_global_sym_count++;
+ entry_symbol->referenced = 1;
+ add_cmdline_ref (entry_symbol);
+ break;
+
+ case 'l':
+ number_of_files++;
+ break;
+
+ case 'n':
+ if (output_style && output_style != OUTPUT_READONLY_TEXT)
+ fatal ("illegal combination of -n with -N, -r, or -z", (char *) 0);
+ output_style = OUTPUT_READONLY_TEXT;
+ break;
+
+ case 130: /* -noinhibit-exec */
+ force_executable = 1;
+ break;
+
+ case 133: /* -nostdlib */
+ no_standard_dirs = 1;
+ break;
+
+ case 'o':
+ output_filename = optarg;
+ break;
+
+ case 'r':
+ if (output_style && output_style != OUTPUT_RELOCATABLE)
+ fatal ("illegal combination of -r with -N, -n, or -z", (char *) 0);
+ output_style = OUTPUT_RELOCATABLE;
+ text_start = 0;
+ break;
+
+ case 's':
+ strip_symbols = STRIP_ALL;
+ break;
+
+ case 't':
+ trace_files = 1;
+ break;
+
+ case 'u':
+ {
+ register symbol *sp = getsym (optarg);
+
+ if (!sp->defined && !sp->referenced)
+ undefined_global_sym_count++;
+ sp->referenced = 1;
+ add_cmdline_ref (sp);
+ }
+ break;
+
+ case 'x':
+ discard_locals = DISCARD_ALL;
+ break;
+
+ case 'y':
+ {
+ register symbol *sp = getsym (optarg);
+
+ sp->trace = 1;
+ }
+ break;
+
+ case 'z':
+ if (output_style && output_style != OUTPUT_DEMAND_PAGED)
+ fatal ("illegal combination of -z with -N, -n, or -r", (char *) 0);
+ output_style = OUTPUT_DEMAND_PAGED;
+ break;
+
+ case 'A':
+ number_of_files++;
+ break;
+
+ case 129: /* -Bstatic. */
+ /* Ignore. */
+ break;
+
+ case 'D':
+ specified_data_size = parse (optarg, "%x", "invalid argument to -D");
+ break;
+
+ case 'L':
+ n_search_dirs++;
+ search_dirs = (char **)
+ xrealloc (search_dirs, n_search_dirs * sizeof (char *));
+ search_dirs[n_search_dirs - 1] = optarg;
+ break;
+
+ case 'M':
+ write_map = 1;
+ break;
+
+ case 'N':
+ if (output_style && output_style != OUTPUT_WRITABLE_TEXT)
+ fatal ("illegal combination of -N with -n, -r, or -z", (char *) 0);
+ output_style = OUTPUT_WRITABLE_TEXT;
+ break;
+
+ case 'S':
+ strip_symbols = STRIP_DEBUGGER;
+ break;
+
+ case 'T':
+ text_start = parse (optarg, "%x", "invalid argument to -Ttext");
+ T_flag_specified = 1;
+ break;
+
+ case 132: /* -Tdata addr */
+ data_start = parse (optarg, "%x", "invalid argument to -Tdata");
+ Tdata_flag_specified = 1;
+ break;
+
+ case 'V':
+ {
+ struct string_list_element *new
+ = (struct string_list_element *)
+ xmalloc (sizeof (struct string_list_element));
+
+ new->str = optarg;
+ new->next = set_element_prefixes;
+ set_element_prefixes = new;
+ }
+ break;
+
+ case 'X':
+ discard_locals = DISCARD_L;
+ break;
+ }
+ }
+
+ if (!number_of_files)
+ usage ("no input files", 0);
+
+ p = file_table
+ = (struct file_entry *) xmalloc (number_of_files * sizeof (struct file_entry));
+ bzero (p, number_of_files * sizeof (struct file_entry));
+
+ /* Now scan again and fill in file_table.
+ All options except -A and -l are ignored here. */
+
+ optind = 0; /* Reset getopt. */
+ while ((optc = getopt_long_only (argc, argv, SHORTOPTS, longopts, &longind))
+ != EOF)
+ {
+ if (optc == 0)
+ optc = longopts[longind].val;
+
+ switch (optc)
+ {
+ case 1:
+ /* Non-option argument. */
+ p->filename = optarg;
+ p->local_sym_name = optarg;
+ p++;
+ break;
+
+ case 'A':
+ if (p != file_table)
+ usage ("-A specified before an input file other than the first");
+ p->filename = optarg;
+ p->local_sym_name = optarg;
+ p->just_syms_flag = 1;
+ p++;
+ break;
+
+ case 'l':
+ p->filename = concat ("lib", optarg, ".a");
+ p->local_sym_name = concat ("-l", optarg, "");
+ p->search_dirs_flag = 1;
+ p++;
+ break;
+ }
+ }
+
+ if (!output_file_type)
+ output_file_type = DEFAULT_OUTPUT_FILE_TYPE;
+
+ if (!output_style)
+ output_style = DEFAULT_OUTPUT_STYLE;
+
+#if 0
+ /* THIS CONSISTENCY CHECK BELONGS SOMEWHERE ELSE. */
+ /* Now check some option settings for consistency. */
+
+ if ((output_style == OUTPUT_READONLY_TEXT || output_style == OUTPUT_DEMAND_PAGED)
+ && (text_start - text_start_alignment) & (page_size - 1))
+ usage ("-T argument not multiple of page size, with sharable output", 0);
+#endif
+
+ /* Append the standard search directories to the user-specified ones. */
+ if (!no_standard_dirs)
+ {
+ int n = sizeof standard_search_dirs / sizeof standard_search_dirs[0];
+ n_search_dirs += n;
+ search_dirs
+ = (char **) xrealloc (search_dirs, n_search_dirs * sizeof (char *));
+ bcopy (standard_search_dirs, &search_dirs[n_search_dirs - n],
+ n * sizeof (char *));
+ }
+}
+
+
+void
+add_cmdline_ref (sp)
+ struct glosym *sp;
+{
+ struct glosym **ptr;
+
+ for (ptr = cmdline_references;
+ ptr < cmdline_references + cl_refs_allocated && *ptr;
+ ptr++)
+ ;
+
+ if (ptr >= cmdline_references + cl_refs_allocated - 1)
+ {
+ int diff = ptr - cmdline_references;
+
+ cl_refs_allocated *= 2;
+ cmdline_references = (struct glosym **)
+ xrealloc (cmdline_references,
+ cl_refs_allocated * sizeof (struct glosym *));
+ ptr = cmdline_references + diff;
+ }
+
+ *ptr++ = sp;
+ *ptr = (struct glosym *) 0;
+}
+
+int
+set_element_prefixed_p (name)
+ char *name;
+{
+ struct string_list_element *p;
+ int i;
+
+ for (p = set_element_prefixes; p; p = p->next)
+ {
+ for (i = 0; p->str[i] != '\0' && (p->str[i] == name[i]); i++)
+ ;
+
+ if (p->str[i] == '\0')
+ return 1;
+ }
+ return 0;
+}
+
+/* Convenient functions for operating on one or all files being
+ loaded. */
+void print_file_name ();
+
+/* Call FUNCTION on each input file entry.
+ Do not call for entries for libraries;
+ instead, call once for each library member that is being loaded.
+
+ FUNCTION receives two arguments: the entry, and ARG. */
+
+void
+each_file (function, arg)
+ register void (*function)();
+ register int arg;
+{
+ register int i;
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ if (entry->library_flag)
+ {
+ register struct file_entry *subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain)
+ (*function) (subentry, arg);
+ }
+ else
+ (*function) (entry, arg);
+ }
+}
+
+/* Call FUNCTION on each input file entry until it returns a non-zero
+ value. Return this value.
+ Do not call for entries for libraries;
+ instead, call once for each library member that is being loaded.
+
+ FUNCTION receives two arguments: the entry, and ARG. It must be a
+ function returning unsigned long (though this can probably be fudged). */
+
+unsigned long
+check_each_file (function, arg)
+ register unsigned long (*function)();
+ register int arg;
+{
+ register int i;
+ register unsigned long return_val;
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ if (entry->library_flag)
+ {
+ register struct file_entry *subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain)
+ if (return_val = (*function) (subentry, arg))
+ return return_val;
+ }
+ else
+ if (return_val = (*function) (entry, arg))
+ return return_val;
+ }
+ return 0;
+}
+
+/* Like `each_file' but ignore files that were just for symbol definitions. */
+
+void
+each_full_file (function, arg)
+ register void (*function)();
+ register int arg;
+{
+ register int i;
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ if (entry->just_syms_flag)
+ continue;
+ if (entry->library_flag)
+ {
+ register struct file_entry *subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain)
+ (*function) (subentry, arg);
+ }
+ else
+ (*function) (entry, arg);
+ }
+}
+
+/* Close the input file that is now open. */
+
+void
+file_close ()
+{
+ close (input_desc);
+ input_desc = 0;
+ input_file = 0;
+}
+
+/* Open the input file specified by 'entry', and return a descriptor.
+ The open file is remembered; if the same file is opened twice in a row,
+ a new open is not actually done. */
+
+int
+file_open (entry)
+ register struct file_entry *entry;
+{
+ register int desc;
+
+ if (entry->superfile)
+ return file_open (entry->superfile);
+
+ if (entry == input_file)
+ return input_desc;
+
+ if (input_file) file_close ();
+
+ if (entry->search_dirs_flag && n_search_dirs)
+ {
+ int i;
+
+ for (i = 0; i < n_search_dirs; i++)
+ {
+ register char *string
+ = concat (search_dirs[i], "/", entry->filename);
+ desc = open (string, O_RDONLY, 0);
+ if (desc > 0)
+ {
+ entry->filename = string;
+ entry->search_dirs_flag = 0;
+ break;
+ }
+ free (string);
+ }
+ }
+ else
+ desc = open (entry->filename, O_RDONLY, 0);
+
+ if (desc > 0)
+ {
+ input_file = entry;
+ input_desc = desc;
+ return desc;
+ }
+
+ perror_file (entry);
+ /* NOTREACHED */
+}
+
+/* Print the filename of ENTRY on OUTFILE (a stdio stream),
+ and then a newline. */
+
+void
+prline_file_name (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ print_file_name (entry, outfile);
+ fprintf (outfile, "\n");
+}
+
+/* Print the filename of ENTRY on OUTFILE (a stdio stream). */
+
+void
+print_file_name (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ if (entry->superfile)
+ {
+ print_file_name (entry->superfile, outfile);
+ fprintf (outfile, "(%s)", entry->filename);
+ }
+ else
+ fprintf (outfile, "%s", entry->filename);
+}
+
+/* Return the filename of entry as a string (malloc'd for the purpose) */
+
+char *
+get_file_name (entry)
+ struct file_entry *entry;
+{
+ char *result, *supfile;
+ if (entry->superfile)
+ {
+ supfile = get_file_name (entry->superfile);
+ result = (char *) xmalloc (strlen (supfile)
+ + strlen (entry->filename) + 3);
+ sprintf (result, "%s(%s)", supfile, entry->filename);
+ free (supfile);
+ }
+ else
+ {
+ result = (char *) xmalloc (strlen (entry->filename) + 1);
+ strcpy (result, entry->filename);
+ }
+ return result;
+}
+
+/* Medium-level input routines for rel files. */
+
+/* Determine whether the given ENTRY is an archive, a BSD a.out file,
+ a Mach-O file, or whatever. DESC is the descriptor on which the
+ file is open. */
+void
+deduce_file_type(desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ int len;
+
+ {
+ char magic[SARMAG];
+
+ lseek (desc, entry->starting_offset, 0);
+ len = read (desc, magic, SARMAG);
+ if (len == SARMAG && !strncmp(magic, ARMAG, SARMAG))
+ {
+ entry->file_type = IS_ARCHIVE;
+ return;
+ }
+#ifdef LARMAG
+ /* Odd hack for Tektronix. */
+ if (len == SARMAG && !strncmp(magic, LARMAG, SARMAG))
+ {
+ entry->file_type = IS_ARCHIVE;
+ return;
+ }
+#endif
+ }
+
+#ifdef A_OUT
+ {
+ struct exec hdr;
+
+ lseek (desc, entry->starting_offset, 0);
+#ifdef COFF_ENCAPSULATE
+ if (entry->just_syms_flag)
+ /* Since a file given with -A will have a coff header, unlike normal
+ input files, we need to skip over it. */
+ lseek (desc, sizeof (struct coffheader), SEEK_CUR);
+#endif
+ len = read (desc, (char *) &hdr, sizeof (struct exec));
+ if (len == sizeof (struct exec) && !N_BADMAG (hdr))
+ {
+ entry->file_type = IS_A_OUT;
+ return;
+ }
+ }
+#endif
+
+#ifdef MACH_O
+ {
+ struct mach_header hdr;
+
+ lseek (desc, entry->starting_offset, 0);
+ len = read (desc, (char *) &hdr, sizeof (struct mach_header));
+ if (len == sizeof (struct mach_header) && hdr.magic == MH_MAGIC)
+ {
+ entry->file_type = IS_MACH_O;
+ return;
+ }
+ }
+#endif
+
+ fatal_with_file ("malformed input file (not rel or archive) ", entry);
+}
+
+#ifdef A_OUT
+/* Read an a.out file's header and set up the fields of
+ the ENTRY accordingly. DESC is the descriptor on which
+ the file is open. */
+void
+read_a_out_header (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ register int len;
+ struct exec hdr;
+ struct stat st;
+
+ lseek (desc, entry->starting_offset, 0);
+
+#ifdef COFF_ENCAPSULATE
+ if (entry->just_syms_flag)
+ /* Since a file given with -A will have a coff header, unlike normal
+ input files, we need to skip over it. */
+ lseek (desc, sizeof (struct coffheader), SEEK_CUR);
+#endif
+
+ read (desc, (char *) &hdr, sizeof (struct exec));
+
+#ifdef READ_HEADER_HOOK
+ READ_HEADER_HOOK(hdr.a_machtype);
+#endif
+
+ if (entry->just_syms_flag)
+ entry->orig_text_address = N_TXTADDR(hdr);
+ else
+ entry->orig_text_address = 0;
+ entry->text_size = hdr.a_text;
+ entry->text_offset = N_TXTOFF(hdr);
+
+ entry->text_reloc_size = hdr.a_trsize;
+#ifdef N_TRELOFF
+ entry->text_reloc_offset = N_TRELOFF(hdr);
+#else
+#ifdef N_DATOFF
+ entry->text_reloc_offset = N_DATOFF(hdr) + hdr.a_data;
+#else
+ entry->text_reloc_offset = N_TXTOFF(hdr) + hdr.a_text + hdr.a_data;
+#endif
+#endif
+
+ if (entry->just_syms_flag)
+ entry->orig_data_address = N_DATADDR(hdr);
+ else
+ entry->orig_data_address = entry->text_size;
+ entry->data_size = hdr.a_data;
+#ifdef N_DATOFF
+ entry->data_offset = N_DATOFF(hdr);
+#else
+ entry->data_offset = N_TXTOFF(hdr) + hdr.a_text;
+#endif
+
+#ifdef NMAGIC
+ /* If this is an NMAGIC file, then even though the text and data
+ are contiguous in the input file, the data has _already_ been
+ relocated to the next page boundary.
+ Change orig_data_address to reflect this. */
+#ifdef N_MAGIC
+ if (N_MAGIC(hdr) == NMAGIC)
+#else
+ if (hdr.a_magic == NMAGIC)
+#endif
+ entry->orig_data_address += (((hdr.a_text + page_size - 1)
+ & ~(page_size - 1)) - hdr.a_text);
+#endif
+
+ entry->data_reloc_size = hdr.a_drsize;
+#ifdef N_DRELOFF
+ entry->data_reloc_offset = N_DRELOFF(hdr);
+#else
+ entry->data_reloc_offset = entry->text_reloc_offset + entry->text_reloc_size;
+#endif
+
+#ifdef N_BSSADDR
+ if (entry->just_syms_flag)
+ entry->orig_bss_address = N_BSSADDR(hdr);
+ else
+#endif
+ entry->orig_bss_address = entry->orig_data_address + entry->data_size;
+ entry->bss_size = hdr.a_bss;
+
+ entry->syms_size = hdr.a_syms;
+ entry->syms_offset = N_SYMOFF(hdr);
+ entry->strs_offset = N_STROFF(hdr);
+ lseek(desc, entry->starting_offset + entry->strs_offset, 0);
+ if (read(desc, (char *) &entry->strs_size, sizeof (unsigned long int))
+ != sizeof (unsigned long int))
+ fatal_with_file ("failure reading string table size of ", entry);
+
+ if (!entry->superfile)
+ {
+ fstat(desc, &st);
+ if (st.st_size > entry->strs_offset + entry->strs_size)
+ {
+ entry->symseg_size = st.st_size - (entry->strs_offset + entry->strs_size);
+ entry->symseg_offset = entry->strs_offset + entry->strs_size;
+ }
+ }
+ else
+ if (entry->total_size > entry->strs_offset + entry->strs_size)
+ {
+ entry->symseg_size = entry->total_size - (entry->strs_offset + entry->strs_size);
+ entry->symseg_offset = entry->strs_offset + entry->strs_size;
+ }
+}
+#endif
+
+#ifdef MACH_O
+/* Read a Mach-O file's header. DESC is the descriptor on which the
+ file is open, and ENTRY is the file's entry. */
+void
+read_mach_o_header (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ struct mach_header mach_header;
+ char *hdrbuf;
+ struct load_command *load_command;
+ struct segment_command *segment_command;
+ struct section *section;
+ struct symtab_command *symtab_command;
+#ifdef LC_SYMSEG
+ struct symseg_command *symseg_command;
+#endif;
+ int ordinal;
+ int symtab_seen, symseg_seen;
+ int len, cmd, seg;
+
+ entry->text_ordinal = entry->data_ordinal = entry->bss_ordinal = 0;
+ symtab_seen = symseg_seen = 0;
+ ordinal = 1;
+
+ lseek (desc, entry->starting_offset, 0);
+ len = read (desc, (char *) &mach_header, sizeof (struct mach_header));
+ if (len != sizeof (struct mach_header))
+ fatal_with_file ("failure reading Mach-O header of ", entry);
+ if (mach_header.filetype != MH_OBJECT && mach_header.filetype != MH_EXECUTE)
+ fatal_with_file ("unsupported Mach-O file type (not MH_OBJECT or MH_EXECUTE) in ", entry);
+ hdrbuf = xmalloc (mach_header.sizeofcmds);
+ len = read (desc, hdrbuf, mach_header.sizeofcmds);
+ if (len != mach_header.sizeofcmds)
+ fatal_with_file ("failure reading Mach-O load commands of ", entry);
+ load_command = (struct load_command *) hdrbuf;
+ for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
+ {
+ switch (load_command->cmd)
+ {
+ case LC_SEGMENT:
+ segment_command = (struct segment_command *) load_command;
+ section = (struct section *) ((char *) (segment_command + 1));
+ for (seg = 0; seg < segment_command->nsects; ++seg, ++section, ++ordinal)
+ {
+ if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname))
+ if (entry->text_ordinal)
+ fatal_with_file ("more than one __text section in ", entry);
+ else
+ {
+ entry->text_ordinal = ordinal;
+ entry->orig_text_address = section->addr;
+ entry->text_size = section->size;
+ entry->text_offset = section->offset;
+ entry->text_reloc_size = section->nreloc * sizeof (struct relocation_info);
+ entry->text_reloc_offset = section->reloff;
+ }
+ else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname))
+ if (entry->data_ordinal)
+ fatal_with_file ("more than one __data section in ", entry);
+ else
+ {
+ entry->data_ordinal = ordinal;
+ entry->orig_data_address = section->addr;
+ entry->data_size = section->size;
+ entry->data_offset = section->offset;
+ entry->data_reloc_size = section->nreloc * sizeof (struct relocation_info);
+ entry->data_reloc_offset = section->reloff;
+ }
+ else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname))
+ if (entry->bss_ordinal)
+ fatal_with_file ("more than one __bss section in ", entry);
+ else
+ {
+ entry->bss_ordinal = ordinal;
+ entry->orig_bss_address = section->addr;
+ entry->bss_size = section->size;
+ }
+ else
+ if (section->size != 0)
+ fprintf (stderr, "%s: warning: unknown section `%.*s' in %s\n",
+ progname, sizeof section->sectname, section->sectname,
+ entry->filename);
+ }
+ break;
+ case LC_SYMTAB:
+ if (symtab_seen)
+ fatal_with_file ("more than one LC_SYMTAB in ", entry);
+ else
+ {
+ symtab_seen = 1;
+ symtab_command = (struct symtab_command *) load_command;
+ entry->syms_size = symtab_command->nsyms * sizeof (struct nlist);
+ entry->syms_offset = symtab_command->symoff;
+ entry->strs_size = symtab_command->strsize;
+ entry->strs_offset = symtab_command->stroff;
+ }
+ break;
+#ifdef LC_SYMSEG
+ case LC_SYMSEG:
+ if (symseg_seen)
+ fatal_with_file ("more than one LC_SYMSEG in ", entry);
+ else
+ {
+ symseg_seen = 1;
+ symseg_command = (struct symseg_command *) load_command;
+ entry->symseg_size = symseg_command->size;
+ entry->symseg_offset = symseg_command->offset;
+ }
+ break;
+#endif
+ }
+ load_command = (struct load_command *)
+ ((char *) load_command + load_command->cmdsize);
+ }
+
+ free (hdrbuf);
+
+ if (!symtab_seen)
+ fprintf (stderr, "%s: no symbol table in %s\n", progname, entry->filename);
+}
+#endif
+
+/* Read a file's header info into the proper place in the file_entry.
+ DESC is the descriptor on which the file is open.
+ ENTRY is the file's entry.
+ Switch in the file_type to determine the appropriate actual
+ header reading routine to call. */
+
+void
+read_header (desc, entry)
+ int desc;
+ register struct file_entry *entry;
+{
+ if (!entry->file_type)
+ deduce_file_type (desc, entry);
+
+ switch (entry->file_type)
+ {
+ case IS_ARCHIVE:
+ default:
+ /* Should never happen. */
+ abort ();
+
+#ifdef A_OUT
+ case IS_A_OUT:
+ read_a_out_header (desc, entry);
+ break;
+#endif
+
+#ifdef MACH_O
+ case IS_MACH_O:
+ read_mach_o_header (desc, entry);
+ break;
+#endif
+ }
+
+ entry->header_read_flag = 1;
+}
+
+#ifdef MACH_O
+void translate_mach_o_symbols ();
+#endif
+
+/* Read the symbols of file ENTRY into core.
+ Assume it is already open, on descriptor DESC. */
+
+void
+read_entry_symbols (desc, entry)
+ struct file_entry *entry;
+ int desc;
+{
+ int str_size;
+
+ if (!entry->header_read_flag)
+ read_header (desc, entry);
+
+ entry->symbols = (struct nlist *) xmalloc (entry->syms_size);
+
+ lseek (desc, entry->syms_offset + entry->starting_offset, 0);
+ if (entry->syms_size != read (desc, entry->symbols, entry->syms_size))
+ fatal_with_file ("premature end of file in symbols of ", entry);
+
+#ifdef MACH_O
+ if (entry->file_type == IS_MACH_O)
+ translate_mach_o_symbols (entry);
+#endif
+}
+
+/* Read the string table of file ENTRY into core.
+ Assume it is already open, on descriptor DESC. */
+
+void
+read_entry_strings (desc, entry)
+ struct file_entry *entry;
+ int desc;
+{
+ int buffer;
+
+ if (!entry->header_read_flag)
+ read_header (desc, entry);
+
+ lseek (desc, entry->strs_offset + entry->starting_offset, 0);
+ if (entry->strs_size != read (desc, entry->strings, entry->strs_size))
+ fatal_with_file ("premature end of file in strings of ", entry);
+}
+
+/* Read in the symbols of all input files. */
+
+void read_file_symbols (), read_entry_symbols (), read_entry_strings ();
+void enter_file_symbols (), enter_global_ref (), search_library ();
+
+void
+load_symbols ()
+{
+ register int i;
+
+ if (trace_files) fprintf (stderr, "Loading symbols:\n\n");
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ read_file_symbols (entry);
+ }
+
+ if (trace_files) fprintf (stderr, "\n");
+}
+
+/* If ENTRY is a rel file, read its symbol and string sections into core.
+ If it is a library, search it and load the appropriate members
+ (which means calling this function recursively on those members). */
+
+void
+read_file_symbols (entry)
+ register struct file_entry *entry;
+{
+ register int desc;
+
+ desc = file_open (entry);
+
+ if (!entry->file_type)
+ deduce_file_type (desc, entry);
+
+ if (entry->file_type == IS_ARCHIVE)
+ {
+ entry->library_flag = 1;
+ search_library (desc, entry);
+ }
+ else
+ {
+ read_entry_symbols (desc, entry);
+ entry->strings = (char *) alloca (entry->strs_size);
+ read_entry_strings (desc, entry);
+ enter_file_symbols (entry);
+ entry->strings = 0;
+ }
+
+ file_close ();
+}
+
+/* Enter the external symbol defs and refs of ENTRY in the hash table. */
+
+void
+enter_file_symbols (entry)
+ struct file_entry *entry;
+{
+ register struct nlist
+ *p,
+ *end = entry->symbols + entry->syms_size / sizeof (struct nlist);
+
+ if (trace_files) prline_file_name (entry, stderr);
+
+ for (p = entry->symbols; p < end; p++)
+ {
+ if (p->n_type == (N_SETV | N_EXT)) continue;
+ if (set_element_prefixes
+ && set_element_prefixed_p (p->n_un.n_strx + entry->strings))
+ p->n_type += (N_SETA - N_ABS);
+
+ if (SET_ELEMENT_P (p->n_type))
+ {
+ set_symbol_count++;
+ if (output_style != OUTPUT_RELOCATABLE)
+ enter_global_ref (p, p->n_un.n_strx + entry->strings, entry);
+ }
+ else if (p->n_type == N_WARNING)
+ {
+ char *name = p->n_un.n_strx + entry->strings;
+
+ /* Grab the next entry. */
+ p++;
+ if (p->n_type != (N_UNDF | N_EXT))
+ {
+ fprintf (stderr, "%s: Warning symbol found in %s without external reference following.\n",
+ progname, entry->filename);
+ make_executable = 0;
+ p--; /* Process normally. */
+ }
+ else
+ {
+ symbol *sp;
+ char *sname = p->n_un.n_strx + entry->strings;
+ /* Deal with the warning symbol. */
+ enter_global_ref (p, p->n_un.n_strx + entry->strings, entry);
+ sp = getsym (sname);
+ sp->warning = (char *) xmalloc (strlen(name) + 1);
+ strcpy (sp->warning, name);
+ warning_count++;
+ }
+ }
+ else if (p->n_type & N_EXT)
+ enter_global_ref (p, p->n_un.n_strx + entry->strings, entry);
+ else if (p->n_un.n_strx && !(p->n_type & (N_STAB | N_EXT)))
+ {
+ if ((p->n_un.n_strx + entry->strings)[0] != LPREFIX)
+ non_L_local_sym_count++;
+ local_sym_count++;
+ }
+ else debugger_sym_count++;
+ }
+
+ /* Count one for the local symbol that we generate,
+ whose name is the file's name (usually) and whose address
+ is the start of the file's text. */
+
+ local_sym_count++;
+ non_L_local_sym_count++;
+}
+
+/* Enter one global symbol in the hash table.
+ NLIST_P points to the `struct nlist' read from the file
+ that describes the global symbol. NAME is the symbol's name.
+ ENTRY is the file entry for the file the symbol comes from.
+
+ The `struct nlist' is modified by placing it on a chain of
+ all such structs that refer to the same global symbol.
+ This chain starts in the `refs' field of the symbol table entry
+ and is chained through the `n_name'. */
+
+void
+enter_global_ref (nlist_p, name, entry)
+ register struct nlist *nlist_p;
+ char *name;
+ struct file_entry *entry;
+{
+ register symbol *sp = getsym (name);
+ register int type = nlist_p->n_type;
+ int oldref = sp->referenced;
+ int olddef = sp->defined;
+
+ nlist_p->n_un.n_name = (char *) sp->refs;
+ sp->refs = nlist_p;
+
+ sp->referenced = 1;
+ sp->last_library_ref = entry->superfile;
+
+ if (type != (N_UNDF | N_EXT) || nlist_p->n_value)
+ {
+ if (!sp->defined || sp->defined == (N_UNDF | N_EXT))
+ sp->defined = type;
+
+ if (oldref && !olddef)
+ /* It used to be undefined and we're defining it. */
+ undefined_global_sym_count--;
+
+ if (!olddef && type == (N_UNDF | N_EXT) && nlist_p->n_value)
+ {
+ /* First definition and it's common. */
+ common_defined_global_count++;
+ sp->max_common_size = nlist_p->n_value;
+ }
+ else if (olddef && sp->max_common_size && type != (N_UNDF | N_EXT))
+ {
+ /* It used to be common and we're defining it as
+ something else. */
+ common_defined_global_count--;
+ sp->max_common_size = 0;
+ }
+ else if (olddef && sp->max_common_size && type == (N_UNDF | N_EXT)
+ && sp->max_common_size < nlist_p->n_value)
+ /* It used to be common and this is a new common entry to
+ which we need to pay attention. */
+ sp->max_common_size = nlist_p->n_value;
+
+ /* Are we defining it as a set element? */
+ if (SET_ELEMENT_P (type)
+ && (!olddef || (olddef && sp->max_common_size)))
+ set_vector_count++;
+ /* As an indirection? */
+ else if (type == (N_INDR | N_EXT))
+ {
+ /* Indirect symbols value should be modified to point
+ a symbol being equivalenced to. */
+ nlist_p->n_value
+#ifndef NeXT
+ = (unsigned int) getsym ((nlist_p + 1)->n_un.n_strx
+ + entry->strings);
+#else
+ /* NeXT also has indirection but they do it weirdly. */
+ = (unsigned int) getsym (nlist_p->n_value + entry->strings);
+#endif
+ if ((symbol *) nlist_p->n_value == sp)
+ {
+ /* Somebody redefined a symbol to be itself. */
+ fprintf (stderr, "%s: Symbol %s indirected to itself.\n",
+ entry->filename, name);
+ /* Rewrite this symbol as being a global text symbol
+ with value 0. */
+ nlist_p->n_type = sp->defined = N_TEXT | N_EXT;
+ nlist_p->n_value = 0;
+ /* Don't make the output executable. */
+ make_executable = 0;
+ }
+ else
+ global_indirect_count++;
+ }
+ }
+ else
+ if (!oldref)
+#ifndef DOLLAR_KLUDGE
+ undefined_global_sym_count++;
+#else
+ {
+ if (entry->superfile && type == (N_UNDF | N_EXT) && name[1] == '$')
+ {
+ /* This is an (ISI?) $-conditional; skip it */
+ sp->referenced = 0;
+ if (sp->trace)
+ {
+ fprintf (stderr, "symbol %s is a $-conditional ignored in ", sp->name);
+ print_file_name (entry, stderr);
+ fprintf (stderr, "\n");
+ }
+ return;
+ }
+ else
+ undefined_global_sym_count++;
+ }
+#endif
+
+ if (sp == end_symbol && entry->just_syms_flag && !T_flag_specified)
+ text_start = nlist_p->n_value;
+
+ if (sp->trace)
+ {
+ register char *reftype;
+ switch (type & ~N_EXT)
+ {
+ case N_UNDF:
+ if (nlist_p->n_value)
+ reftype = "defined as common";
+ else reftype = "referenced";
+ break;
+
+ case N_ABS:
+ reftype = "defined as absolute";
+ break;
+
+ case N_TEXT:
+ reftype = "defined in text section";
+ break;
+
+ case N_DATA:
+ reftype = "defined in data section";
+ break;
+
+ case N_BSS:
+ reftype = "defined in BSS section";
+ break;
+
+ case N_SETT:
+ reftype = "is a text set element";
+ break;
+
+ case N_SETD:
+ reftype = "is a data set element";
+ break;
+
+ case N_SETB:
+ reftype = "is a BSS set element";
+ break;
+
+ case N_SETA:
+ reftype = "is an absolute set element";
+ break;
+
+ case N_SETV:
+ reftype = "defined in data section as vector";
+ break;
+
+ case N_INDR:
+ reftype = (char *) alloca (23 + strlen (((symbol *) nlist_p->n_value)->name));
+ sprintf (reftype, "defined equivalent to %s",
+ ((symbol *) nlist_p->n_value)->name);
+ break;
+
+#ifdef sequent
+ case N_SHUNDF:
+ reftype = "shared undf";
+ break;
+
+/* These conflict with cases above.
+ case N_SHDATA:
+ reftype = "shared data";
+ break;
+
+ case N_SHBSS:
+ reftype = "shared BSS";
+ break;
+*/
+#endif
+
+ default:
+ reftype = "I don't know this type";
+ break;
+ }
+
+ fprintf (stderr, "symbol %s %s in ", sp->name, reftype);
+ print_file_name (entry, stderr);
+ fprintf (stderr, "\n");
+ }
+}
+
+/* This return 0 if the given file entry's symbol table does *not*
+ contain the nlist point entry, and it returns the files entry
+ pointer (cast to unsigned long) if it does. */
+
+unsigned long
+contains_symbol (entry, n_ptr)
+ struct file_entry *entry;
+ register struct nlist *n_ptr;
+{
+ if (n_ptr >= entry->symbols &&
+ n_ptr < (entry->symbols
+ + (entry->syms_size / sizeof (struct nlist))))
+ return (unsigned long) entry;
+ return 0;
+}
+
+
+/* Searching libraries */
+
+struct file_entry *decode_library_subfile ();
+void linear_library (), symdef_library ();
+
+/* Search the library ENTRY, already open on descriptor DESC.
+ This means deciding which library members to load,
+ making a chain of `struct file_entry' for those members,
+ and entering their global symbols in the hash table. */
+
+void
+search_library (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ int member_length;
+ register char *name;
+ register struct file_entry *subentry;
+
+ if (!undefined_global_sym_count) return;
+
+ /* Examine its first member, which starts SARMAG bytes in. */
+ subentry = decode_library_subfile (desc, entry, SARMAG, &member_length);
+ if (!subentry) return;
+
+ name = subentry->filename;
+ free (subentry);
+
+ /* Search via __.SYMDEF if that exists, else linearly. */
+
+ if (!strcmp (name, "__.SYMDEF"))
+ symdef_library (desc, entry, member_length);
+ else
+ linear_library (desc, entry);
+}
+
+/* Construct and return a file_entry for a library member.
+ The library's file_entry is library_entry, and the library is open on DESC.
+ SUBFILE_OFFSET is the byte index in the library of this member's header.
+ We store the length of the member into *LENGTH_LOC. */
+
+struct file_entry *
+decode_library_subfile (desc, library_entry, subfile_offset, length_loc)
+ int desc;
+ struct file_entry *library_entry;
+ int subfile_offset;
+ int *length_loc;
+{
+ int bytes_read;
+ register int namelen;
+ int member_length;
+ register char *name;
+ struct ar_hdr hdr1;
+ register struct file_entry *subentry;
+
+ lseek (desc, subfile_offset, 0);
+
+#ifdef LARMAG
+ bytes_read = getarhdr (desc, &hdr1);
+#else
+ bytes_read = read (desc, &hdr1, sizeof hdr1);
+#endif
+
+ if (!bytes_read)
+ return 0; /* end of archive */
+
+#ifdef LARMAG
+ if (bytes_read < 0)
+#else
+ if (sizeof hdr1 != bytes_read)
+#endif
+ fatal_with_file ("malformed library archive ", library_entry);
+
+ if (sscanf (hdr1.ar_size, "%d", &member_length) != 1)
+ fatal_with_file ("malformatted header of archive member in ", library_entry);
+
+ subentry = (struct file_entry *) xmalloc (sizeof (struct file_entry));
+ bzero (subentry, sizeof (struct file_entry));
+
+#ifdef LARMAG
+ namelen = strlen (hdr1.ar_name);
+#else
+ for (namelen = 0;
+ namelen < sizeof hdr1.ar_name
+ && hdr1.ar_name[namelen] != 0 && hdr1.ar_name[namelen] != ' '
+ && hdr1.ar_name[namelen] != '/';
+ namelen++);
+#endif
+
+ name = (char *) xmalloc (namelen+1);
+ strncpy (name, hdr1.ar_name, namelen);
+ name[namelen] = 0;
+
+ subentry->filename = name;
+ subentry->local_sym_name = name;
+ subentry->symbols = 0;
+ subentry->strings = 0;
+ subentry->subfiles = 0;
+#ifdef LARMAG
+ /* The struct ar_hdr is packed in the file */
+ /* The return value of getarhdr accounts for just part of it */
+ bytes_read += sizeof hdr1 - sizeof hdr1.ar_name;
+ subentry->starting_offset = subfile_offset + bytes_read;
+#else
+ subentry->starting_offset = subfile_offset + sizeof hdr1;
+#endif
+ subentry->superfile = library_entry;
+ subentry->library_flag = 0;
+ subentry->header_read_flag = 0;
+ subentry->just_syms_flag = 0;
+ subentry->chain = 0;
+ subentry->total_size = member_length;
+
+ (*length_loc) = member_length;
+
+ return subentry;
+}
+
+int subfile_wanted_p ();
+
+/* Search a library that has a __.SYMDEF member.
+ DESC is a descriptor on which the library is open.
+ The file pointer is assumed to point at the __.SYMDEF data.
+ ENTRY is the library's file_entry.
+ MEMBER_LENGTH is the length of the __.SYMDEF data. */
+
+void
+symdef_library (desc, entry, member_length)
+ int desc;
+ struct file_entry *entry;
+ int member_length;
+{
+ int *symdef_data = (int *) xmalloc (member_length);
+ register struct symdef *symdef_base;
+ char *sym_name_base;
+ int number_of_symdefs;
+ int length_of_strings;
+ int not_finished;
+ int bytes_read;
+ register int i;
+ struct file_entry *prev = 0;
+ int prev_offset = 0;
+
+ bytes_read = read (desc, symdef_data, member_length);
+ if (bytes_read != member_length)
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+
+ number_of_symdefs = *symdef_data / sizeof (struct symdef);
+ if (number_of_symdefs < 0 ||
+ number_of_symdefs * sizeof (struct symdef) + 2 * sizeof (int) > member_length)
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+
+ symdef_base = (struct symdef *) (symdef_data + 1);
+ length_of_strings = *(int *) (symdef_base + number_of_symdefs);
+
+ if (length_of_strings < 0
+ || number_of_symdefs * sizeof (struct symdef) + length_of_strings
+ + 2 * sizeof (int) != member_length)
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+
+ sym_name_base = sizeof (int) + (char *) (symdef_base + number_of_symdefs);
+
+ /* Check all the string indexes for validity. */
+
+ for (i = 0; i < number_of_symdefs; i++)
+ {
+ register int index = symdef_base[i].symbol_name_string_index;
+ if (index < 0 || index >= length_of_strings
+ || (index && *(sym_name_base + index - 1)))
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+ }
+
+ /* Search the symdef data for members to load.
+ Do this until one whole pass finds nothing to load. */
+
+ not_finished = 1;
+ while (not_finished)
+ {
+ not_finished = 0;
+
+ /* Scan all the symbols mentioned in the symdef for ones that we need.
+ Load the library members that contain such symbols. */
+
+ for (i = 0;
+ (i < number_of_symdefs
+ && (undefined_global_sym_count || common_defined_global_count));
+ i++)
+ if (symdef_base[i].symbol_name_string_index >= 0)
+ {
+ register symbol *sp;
+
+ sp = getsym_soft (sym_name_base
+ + symdef_base[i].symbol_name_string_index);
+
+ /* If we find a symbol that appears to be needed, think carefully
+ about the archive member that the symbol is in. */
+
+ if (sp && ((sp->referenced && !sp->defined)
+ || (sp->defined && sp->max_common_size)))
+ {
+ int junk;
+ register int j;
+ register int offset = symdef_base[i].library_member_offset;
+ struct file_entry *subentry;
+
+ /* Don't think carefully about any archive member
+ more than once in a given pass. */
+
+ if (prev_offset == offset)
+ continue;
+ prev_offset = offset;
+
+ /* Read the symbol table of the archive member. */
+
+ subentry = decode_library_subfile (desc, entry, offset, &junk);
+ if (subentry == 0)
+ fatal ("invalid offset for %s in symbol table of %s",
+ sym_name_base
+ + symdef_base[i].symbol_name_string_index,
+ entry->filename);
+ read_entry_symbols (desc, subentry);
+ subentry->strings = xmalloc (subentry->strs_size);
+ read_entry_strings (desc, subentry);
+
+ /* Now scan the symbol table and decide whether to load. */
+
+ if (!subfile_wanted_p (subentry))
+ {
+ free (subentry->symbols);
+ free (subentry->strings);
+ free (subentry);
+ }
+ else
+ {
+ /* This member is needed; load it.
+ Since we are loading something on this pass,
+ we must make another pass through the symdef data. */
+
+ not_finished = 1;
+
+ enter_file_symbols (subentry);
+
+ if (prev)
+ prev->chain = subentry;
+ else entry->subfiles = subentry;
+ prev = subentry;
+
+ /* Clear out this member's symbols from the symdef data
+ so that following passes won't waste time on them. */
+
+ for (j = 0; j < number_of_symdefs; j++)
+ {
+ if (symdef_base[j].library_member_offset == offset)
+ symdef_base[j].symbol_name_string_index = -1;
+ }
+
+ /* We'll read the strings again if we need them again. */
+ free (subentry->strings);
+ subentry->strings = 0;
+ }
+ }
+ }
+ }
+
+ free (symdef_data);
+}
+
+
+/* Handle a subentry for a file with no __.SYMDEF. */
+
+process_subentry (desc, subentry, entry, prev_addr)
+ int desc;
+ register struct file_entry *subentry;
+ struct file_entry **prev_addr, *entry;
+{
+ read_entry_symbols (desc, subentry);
+ subentry->strings = (char *) alloca (subentry->strs_size);
+ read_entry_strings (desc, subentry);
+
+ if (!subfile_wanted_p (subentry))
+ {
+ free (subentry->symbols);
+ free (subentry);
+ }
+ else
+ {
+ enter_file_symbols (subentry);
+
+ if (*prev_addr)
+ (*prev_addr)->chain = subentry;
+ else
+ entry->subfiles = subentry;
+ *prev_addr = subentry;
+ subentry->strings = 0; /* Since space will dissapear on return */
+ }
+}
+
+/* Search a library that has no __.SYMDEF.
+ ENTRY is the library's file_entry.
+ DESC is the descriptor it is open on. */
+
+void
+linear_library (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ struct file_entry *prev = 0;
+ register int this_subfile_offset = SARMAG;
+
+ while (undefined_global_sym_count || common_defined_global_count)
+ {
+ int member_length;
+ register struct file_entry *subentry;
+
+ subentry = decode_library_subfile (desc, entry, this_subfile_offset,
+ &member_length);
+ if (!subentry) return;
+
+ process_subentry (desc, subentry, entry, &prev);
+#ifdef LARMAG
+ this_subfile_offset = member_length + subentry->starting_offset;
+#else
+ this_subfile_offset += member_length + sizeof (struct ar_hdr);
+#endif
+ if (this_subfile_offset & 1) this_subfile_offset++;
+ }
+}
+
+/* ENTRY is an entry for a library member.
+ Its symbols have been read into core, but not entered.
+ Return nonzero if we ought to load this member. */
+
+int
+subfile_wanted_p (entry)
+ struct file_entry *entry;
+{
+ register struct nlist *p;
+ register struct nlist *end
+ = entry->symbols + entry->syms_size / sizeof (struct nlist);
+#ifdef DOLLAR_KLUDGE
+ register int dollar_cond = 0;
+#endif
+
+ for (p = entry->symbols; p < end; p++)
+ {
+ register int type = p->n_type;
+ register char *name = p->n_un.n_strx + entry->strings;
+
+ /* If the symbol has an interesting definition, we could
+ potentially want it. */
+ if (type & N_EXT
+ && (type != (N_UNDF | N_EXT) || p->n_value
+
+#ifdef DOLLAR_KLUDGE
+ || name[1] == '$'
+#endif
+ )
+ && !SET_ELEMENT_P (type)
+ && !set_element_prefixed_p (name))
+ {
+ register symbol *sp = getsym_soft (name);
+
+#ifdef DOLLAR_KLUDGE
+ if (name[1] == '$')
+ {
+ sp = getsym_soft (&name[2]);
+ dollar_cond = 1;
+ if (!sp) continue;
+ if (sp->referenced)
+ {
+ if (write_map)
+ {
+ print_file_name (entry, stdout);
+ fprintf (stdout, " needed due to $-conditional %s\n", name);
+ }
+ return 1;
+ }
+ continue;
+ }
+#endif
+
+ /* If this symbol has not been hashed, we can't be looking for it. */
+
+ if (!sp) continue;
+
+ /* Note: There has been a lot of discussion about what to
+ when a common definition was previously seen (i.e. when
+ sp->max_common_size > 0).
+ The latest solution is to treat a previous common definition
+ (wrt to subfile_wanted_p) no differently from a real definition.
+ This has the advantage of simplicity and consistency: a common
+ definition is just like a common definition (consistent
+ with strict ANSI C) except that we allow duplicate definitions.
+ Possible disadvantage: May not be the best choice for Fortran,
+ though it is consistent with the standard.
+
+ An earlier solution:
+ We wanted to see a common definition in the subfile,
+ and note its size, but ignore any other definition
+ if the symbol was already defined (even as a common).
+ This meant that if there were multiple common definitions,
+ the final definition would use the largest size of any of them,
+ as it should. But if there was a common definition and another
+ definition, like "int pipe;" in a program and "int pipe() {}"
+ in the library, only the common would be used.
+ Disadvantage: a poorly justified kludge.
+
+ Another previous solution:
+ If the symbol already had a definition as a common symbol,
+ we would want this subfile if some other subfile of the
+ same library that we already need anyway also used the symbol.
+ This seemed like an even more ad hoc decision.
+ It would also cause subfiles to be pulled in that would
+ then conflict with previous entries. I.e. you couldn't
+ have: ld ... start.o libc.a ... if libc.a contained start.o.
+
+ Other hybrid solutions were also considered.
+ */
+ if ((sp->referenced && !sp->defined))
+ {
+#ifdef DOLLAR_KLUDGE
+ if (dollar_cond) continue;
+#endif
+ if (type == (N_UNDF | N_EXT))
+ {
+ /* Symbol being defined as common.
+ Remember this, but don't load subfile just for this. */
+
+ common_defined_global_count++;
+ sp->max_common_size = p->n_value;
+ undefined_global_sym_count--;
+ sp->defined = 1;
+ continue;
+ }
+ if (write_map)
+ {
+ print_file_name (entry, stdout);
+ fprintf (stdout, " needed due to %s\n", sp->name);
+ }
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void consider_file_section_lengths (), relocate_file_addresses ();
+
+/* Having entered all the global symbols and found the sizes of sections
+ of all files to be linked, make all appropriate deductions from this data.
+
+ We propagate global symbol values from definitions to references.
+ We compute the layout of the output file and where each input file's
+ contents fit into it. */
+
+void
+digest_symbols ()
+{
+ register int i;
+ int setv_fill_count;
+
+ if (trace_files)
+ fprintf (stderr, "Digesting symbol information:\n\n");
+
+ /* Initialize the text_start address; this depends on the output file formats. */
+
+ initialize_text_start ();
+
+ text_size = text_header_size;
+
+ /* Compute total size of sections */
+
+ each_file (consider_file_section_lengths, 0);
+
+ /* If necessary, pad text section to full page in the file.
+ Include the padding in the text segment size. */
+
+ if (output_style == OUTPUT_READONLY_TEXT || output_style == OUTPUT_DEMAND_PAGED)
+ {
+#ifdef tek4300
+ int page_size = ZMALIGN; /* a lie */
+#endif
+#ifdef is68k
+ text_pad = ((text_size + SEGMENT_SIZE - 1) & (- SEGMENT_SIZE) - text_size;
+#else
+ text_pad = ((text_size + page_size - 1) & (- page_size)) - text_size;
+#endif
+ text_size += text_pad;
+ }
+
+ /* Now that the text_size is known, initialize the data start address;
+ this depends on text_size as well as the output file format. */
+
+ initialize_data_start ();
+
+ /* Set up the set element vector */
+
+ if (output_style != OUTPUT_RELOCATABLE)
+ {
+ /* The set sector size is the number of set elements + a word
+ for each symbol for the length word at the beginning of the
+ vector, plus a word for each symbol for a zero at the end of
+ the vector (for incremental linking). */
+ set_sect_size
+ = (2 * set_symbol_count + set_vector_count) * sizeof (unsigned long);
+ set_sect_start = data_start + data_size;
+ data_size += set_sect_size;
+ set_vectors = (unsigned long *) xmalloc (set_sect_size);
+ setv_fill_count = 0;
+ }
+
+ /* Make sure bss starts out aligned as much as anyone can want. */
+ {
+ int new_data_size = (data_size + sizeof(double) - 1) & ~(sizeof(double)-1);
+
+ data_pad += new_data_size - data_size;
+ data_size = new_data_size;
+ }
+
+ /* Compute start addresses of each file's sections and symbols. */
+
+ each_full_file (relocate_file_addresses, 0);
+
+ /* Now, for each symbol, verify that it is defined globally at most once.
+ Put the global value into the symbol entry.
+ Common symbols are allocated here, in the BSS section.
+ Each defined symbol is given a '->defined' field
+ which is the correct N_ code for its definition,
+ except in the case of common symbols with -r.
+ Then make all the references point at the symbol entry
+ instead of being chained together. */
+
+ defined_global_sym_count = 0;
+
+ for (i = 0; i < TABSIZE; i++)
+ {
+ register symbol *sp;
+ for (sp = symtab[i]; sp; sp = sp->link)
+ {
+ /* For each symbol */
+ register struct nlist *p, *next;
+ int defs = 0, com = sp->max_common_size;
+ struct nlist *first_definition;
+ for (p = sp->refs; p; p = next)
+ {
+ register int type = p->n_type;
+
+ if (SET_ELEMENT_P (type))
+ {
+ if (output_style == OUTPUT_RELOCATABLE)
+ fatal ("internal: global ref to set element with -r");
+ if (!defs++)
+ {
+ sp->value = set_sect_start
+ + setv_fill_count++ * sizeof (unsigned long);
+ sp->defined = N_SETV | N_EXT;
+ first_definition = p;
+ }
+ else if ((sp->defined & ~N_EXT) != N_SETV)
+ {
+ sp->multiply_defined = 1;
+ multiple_def_count++;
+ }
+ set_vectors[setv_fill_count++] = p->n_value;
+ }
+ else if ((type & N_EXT) && type != (N_UNDF | N_EXT))
+ {
+ /* non-common definition */
+ if (defs++ && sp->value != p->n_value)
+ {
+ sp->multiply_defined = 1;
+ multiple_def_count++;
+ }
+ sp->value = p->n_value;
+ sp->defined = type;
+ first_definition = p;
+ }
+ next = (struct nlist *) p->n_un.n_name;
+ p->n_un.n_name = (char *) sp;
+ }
+ /* Allocate as common if defined as common and not defined for real */
+ if (com && !defs)
+ {
+ if (output_style != OUTPUT_RELOCATABLE || force_common_definition)
+ {
+ int align = sizeof (int);
+
+ /* Round up to nearest sizeof (int). I don't know
+ whether this is necessary or not (given that
+ alignment is taken care of later), but it's
+ traditional, so I'll leave it in. Note that if
+ this size alignment is ever removed, ALIGN above
+ will have to be initialized to 1 instead of
+ sizeof (int). */
+
+ com = (com + sizeof (int) - 1) & (- sizeof (int));
+
+ while (!(com & align))
+ align <<= 1;
+
+ align = align > MAX_ALIGNMENT ? MAX_ALIGNMENT : align;
+
+ bss_size = ((((bss_size + data_size + data_start)
+ + (align - 1)) & (- align))
+ - data_size - data_start);
+
+ sp->value = data_start + data_size + bss_size;
+ sp->defined = N_BSS | N_EXT;
+ bss_size += com;
+ if (write_map)
+ printf ("Allocating common %s: %x at %x\n",
+ sp->name, com, sp->value);
+ }
+ else
+ {
+ sp->defined = 0;
+ undefined_global_sym_count++;
+ }
+ }
+ /* Set length word at front of vector and zero byte at end.
+ Reverse the vector itself to put it in file order. */
+ if ((sp->defined & ~N_EXT) == N_SETV)
+ {
+ unsigned long length_word_index
+ = (sp->value - set_sect_start) / sizeof (unsigned long);
+ unsigned long i, tmp;
+
+ set_vectors[length_word_index]
+ = setv_fill_count - 1 - length_word_index;
+
+ /* Reverse the vector. */
+ for (i = 1;
+ i < (setv_fill_count - length_word_index - 1) / 2 + 1;
+ i++)
+ {
+ tmp = set_vectors[length_word_index + i];
+ set_vectors[length_word_index + i]
+ = set_vectors[setv_fill_count - i];
+ set_vectors[setv_fill_count - i] = tmp;
+ }
+
+ set_vectors[setv_fill_count++] = 0;
+ }
+ if (sp->defined)
+ defined_global_sym_count++;
+ }
+ }
+
+ /* Make sure end of bss is aligned as much as anyone can want. */
+
+ bss_size = (bss_size + sizeof(double) - 1) & ~(sizeof(double)-1);
+
+ /* Give values to _end and friends. */
+ {
+ int end_value = data_start + data_size + bss_size;
+ if (end_symbol)
+ end_symbol->value = end_value;
+ if (end_symbol_alt)
+ end_symbol_alt->value = end_value;
+ }
+
+ {
+ int etext_value = text_size + text_start;
+ if (etext_symbol)
+ etext_symbol->value = etext_value;
+ if (etext_symbol_alt)
+ etext_symbol_alt->value = etext_value;
+ }
+
+ {
+ int edata_value = data_start + data_size;
+ if (edata_symbol)
+ edata_symbol->value = edata_value;
+ if (edata_symbol_alt)
+ edata_symbol_alt->value = edata_value;
+ }
+
+ /* Figure the data_pad now, so that it overlaps with the bss addresses. */
+
+ {
+ /* The amount of data_pad that we are computing now. This is the
+ part which overlaps with bss. What was computed previously
+ goes before bss. */
+ int data_pad_additional = 0;
+
+ if (specified_data_size && specified_data_size > data_size)
+ data_pad_additional = specified_data_size - data_size;
+
+ if (output_style == OUTPUT_DEMAND_PAGED)
+ data_pad_additional =
+ ((data_pad_additional + data_size + page_size - 1) & (- page_size)) - data_size;
+
+ bss_size -= data_pad_additional;
+ if (bss_size < 0) bss_size = 0;
+
+ data_size += data_pad_additional;
+
+ data_pad += data_pad_additional;
+ }
+}
+
+/* Accumulate the section sizes of input file ENTRY
+ into the section sizes of the output file. */
+
+void
+consider_file_section_lengths (entry)
+ register struct file_entry *entry;
+{
+ if (entry->just_syms_flag)
+ return;
+
+ entry->text_start_address = text_size;
+ /* If there were any vectors, we need to chop them off */
+ text_size += entry->text_size;
+ entry->data_start_address = data_size;
+ data_size += entry->data_size;
+ entry->bss_start_address = bss_size;
+ bss_size += entry->bss_size;
+
+ text_reloc_size += entry->text_reloc_size;
+ data_reloc_size += entry->data_reloc_size;
+}
+
+/* Determine where the sections of ENTRY go into the output file,
+ whose total section sizes are already known.
+ Also relocate the addresses of the file's local and debugger symbols. */
+
+void
+relocate_file_addresses (entry)
+ register struct file_entry *entry;
+{
+ entry->text_start_address += text_start;
+
+ /* Note that `data_start' and `data_size' have not yet been adjusted
+ for the portion of data_pad which overlaps with bss. If they had
+ been, we would get the wrong results here. */
+ entry->data_start_address += data_start;
+ entry->bss_start_address += data_start + data_size;
+
+ {
+ register struct nlist *p;
+ register struct nlist *end
+ = entry->symbols + entry->syms_size / sizeof (struct nlist);
+
+ for (p = entry->symbols; p < end; p++)
+ {
+ /* If this belongs to a section, update it by the section's start address */
+ register int type = p->n_type & N_TYPE;
+
+ switch (type)
+ {
+ case N_TEXT:
+ case N_SETT:
+ p->n_value += entry->text_start_address - entry->orig_text_address;
+ break;
+ case N_DATA:
+ case N_SETV:
+ case N_SETD:
+ /* Data segment symbol. Subtract the address of the
+ data segment in the input file, and add the address
+ of this input file's data segment in the output file. */
+ p->n_value +=
+ entry->data_start_address - entry->orig_data_address;
+ break;
+ case N_BSS:
+ case N_SETB:
+ /* likewise for symbols with value in BSS. */
+ p->n_value += entry->bss_start_address - entry->orig_bss_address;
+ break;
+ }
+ }
+ }
+}
+
+void describe_file_sections (), list_file_locals ();
+
+/* Print a complete or partial map of the output file. */
+
+void
+print_symbols (outfile)
+ FILE *outfile;
+{
+ register int i;
+
+ fprintf (outfile, "\nFiles:\n\n");
+
+ each_file (describe_file_sections, outfile);
+
+ fprintf (outfile, "\nGlobal symbols:\n\n");
+
+ for (i = 0; i < TABSIZE; i++)
+ {
+ register symbol *sp;
+ for (sp = symtab[i]; sp; sp = sp->link)
+ {
+ if (sp->defined == 1)
+ fprintf (outfile, " %s: common, length 0x%x\n", sp->name, sp->max_common_size);
+ if (sp->defined)
+ fprintf (outfile, " %s: 0x%x\n", sp->name, sp->value);
+ else if (sp->referenced)
+ fprintf (outfile, " %s: undefined\n", sp->name);
+ }
+ }
+
+ each_file (list_file_locals, outfile);
+}
+
+void
+describe_file_sections (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ fprintf (outfile, " ");
+ print_file_name (entry, outfile);
+ if (entry->just_syms_flag)
+ fprintf (outfile, " symbols only\n", 0);
+ else
+ fprintf (outfile, " text %x(%x), data %x(%x), bss %x(%x) hex\n",
+ entry->text_start_address, entry->text_size,
+ entry->data_start_address, entry->data_size,
+ entry->bss_start_address, entry->bss_size);
+}
+
+void
+list_file_locals (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ register struct nlist
+ *p,
+ *end = entry->symbols + entry->syms_size / sizeof (struct nlist);
+
+ entry->strings = (char *) alloca (entry->strs_size);
+ read_entry_strings (file_open (entry), entry);
+
+ fprintf (outfile, "\nLocal symbols of ");
+ print_file_name (entry, outfile);
+ fprintf (outfile, ":\n\n");
+
+ for (p = entry->symbols; p < end; p++)
+ /* If this is a definition,
+ update it if necessary by this file's start address. */
+ if (!(p->n_type & (N_STAB | N_EXT)))
+ fprintf (outfile, " %s: 0x%x\n",
+ entry->strings + p->n_un.n_strx, p->n_value);
+
+ entry->strings = 0; /* All done with them. */
+}
+
+
+/* Static vars for do_warnings and subroutines of it */
+int list_unresolved_refs; /* List unresolved refs */
+int list_warning_symbols; /* List warning syms */
+int list_multiple_defs; /* List multiple definitions */
+
+/*
+ * Structure for communication between do_file_warnings and it's
+ * helper routines. Will in practice be an array of three of these:
+ * 0) Current line, 1) Next line, 2) Source file info.
+ */
+struct line_debug_entry
+{
+ int line;
+ char *filename;
+ struct nlist *sym;
+};
+
+void qsort ();
+/*
+ * Helper routines for do_file_warnings.
+ */
+
+/* Return an integer less than, equal to, or greater than 0 as per the
+ relation between the two relocation entries. Used by qsort. */
+
+int
+relocation_entries_relation (rel1, rel2)
+ struct relocation_info *rel1, *rel2;
+{
+ return RELOC_ADDRESS(rel1) - RELOC_ADDRESS(rel2);
+}
+
+/* Moves to the next debugging symbol in the file. USE_DATA_SYMBOLS
+ determines the type of the debugging symbol to look for (DSLINE or
+ SLINE). STATE_POINTER keeps track of the old and new locatiosn in
+ the file. It assumes that state_pointer[1] is valid; ie
+ that it.sym points into some entry in the symbol table. If
+ state_pointer[1].sym == 0, this routine should not be called. */
+
+int
+next_debug_entry (use_data_symbols, state_pointer)
+ register int use_data_symbols;
+ /* Next must be passed by reference! */
+ struct line_debug_entry state_pointer[3];
+{
+ register struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1,
+ /* Used to store source file */
+ *source = state_pointer + 2;
+ struct file_entry *entry = (struct file_entry *) source->sym;
+
+ current->sym = next->sym;
+ current->line = next->line;
+ current->filename = next->filename;
+
+ while (++(next->sym) < (entry->symbols
+ + entry->syms_size/sizeof (struct nlist)))
+ {
+ /* n_type is a char, and N_SOL, N_EINCL and N_BINCL are > 0x80, so
+ * may look negative...therefore, must mask to low bits
+ */
+ switch (next->sym->n_type & 0xff)
+ {
+ case N_SLINE:
+ if (use_data_symbols) continue;
+ next->line = next->sym->n_desc;
+ return 1;
+ case N_DSLINE:
+ if (!use_data_symbols) continue;
+ next->line = next->sym->n_desc;
+ return 1;
+#ifdef HAVE_SUN_STABS
+ case N_EINCL:
+ next->filename = source->filename;
+ continue;
+#endif
+ case N_SO:
+ source->filename = next->sym->n_un.n_strx + entry->strings;
+ source->line++;
+#ifdef HAVE_SUN_STABS
+ case N_BINCL:
+#endif
+ case N_SOL:
+ next->filename
+ = next->sym->n_un.n_strx + entry->strings;
+ default:
+ continue;
+ }
+ }
+ next->sym = (struct nlist *) 0;
+ return 0;
+}
+
+/* Create a structure to save the state of a scan through the debug
+ symbols. USE_DATA_SYMBOLS is set if we should be scanning for
+ DSLINE's instead of SLINE's. entry is the file entry which points
+ at the symbols to use. */
+
+struct line_debug_entry *
+init_debug_scan (use_data_symbols, entry)
+ int use_data_symbols;
+ struct file_entry *entry;
+{
+ struct line_debug_entry
+ *state_pointer
+ = (struct line_debug_entry *)
+ xmalloc (3 * sizeof (struct line_debug_entry));
+ register struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1,
+ *source = state_pointer + 2; /* Used to store source file */
+
+ struct nlist *tmp;
+
+ for (tmp = entry->symbols;
+ tmp < (entry->symbols
+ + entry->syms_size/sizeof (struct nlist));
+ tmp++)
+ if (tmp->n_type == (int) N_SO)
+ break;
+
+ if (tmp >= (entry->symbols
+ + entry->syms_size/sizeof (struct nlist)))
+ {
+ /* I believe this translates to "We lose" */
+ current->filename = next->filename = entry->filename;
+ current->line = next->line = -1;
+ current->sym = next->sym = (struct nlist *) 0;
+ return state_pointer;
+ }
+
+ next->line = source->line = 0;
+ next->filename = source->filename
+ = (tmp->n_un.n_strx + entry->strings);
+ source->sym = (struct nlist *) entry;
+ next->sym = tmp;
+
+ next_debug_entry (use_data_symbols, state_pointer); /* To setup next */
+
+ if (!next->sym) /* No line numbers for this section; */
+ /* setup output results as appropriate */
+ {
+ if (source->line)
+ {
+ current->filename = source->filename = entry->filename;
+ current->line = -1; /* Don't print lineno */
+ }
+ else
+ {
+ current->filename = source->filename;
+ current->line = 0;
+ }
+ return state_pointer;
+ }
+
+
+ next_debug_entry (use_data_symbols, state_pointer); /* To setup current */
+
+ return state_pointer;
+}
+
+/* Takes an ADDRESS (in either text or data space) and a STATE_POINTER
+ which describes the current location in the implied scan through
+ the debug symbols within the file which ADDRESS is within, and
+ returns the source line number which corresponds to ADDRESS. */
+
+int
+address_to_line (address, state_pointer)
+ unsigned long address;
+ /* Next must be passed by reference! */
+ struct line_debug_entry state_pointer[3];
+{
+ struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1;
+ struct line_debug_entry *tmp_pointer;
+
+ int use_data_symbols;
+
+ if (next->sym)
+ use_data_symbols = (next->sym->n_type & ~N_EXT) == N_DATA;
+ else
+ return current->line;
+
+ /* Go back to the beginning if we've already passed it. */
+ if (current->sym->n_value > address)
+ {
+ tmp_pointer = init_debug_scan (use_data_symbols,
+ (struct file_entry *)
+ ((state_pointer + 2)->sym));
+ state_pointer[0] = tmp_pointer[0];
+ state_pointer[1] = tmp_pointer[1];
+ state_pointer[2] = tmp_pointer[2];
+ free (tmp_pointer);
+ }
+
+ /* If we're still in a bad way, return -1, meaning invalid line. */
+ if (current->sym->n_value > address)
+ return -1;
+
+ while (next->sym
+ && next->sym->n_value <= address
+ && next_debug_entry (use_data_symbols, state_pointer))
+ ;
+ return current->line;
+}
+
+
+/* Macros for manipulating bitvectors. */
+#define BIT_SET_P(bv, index) ((bv)[(index) >> 3] & 1 << ((index) & 0x7))
+#define SET_BIT(bv, index) ((bv)[(index) >> 3] |= 1 << ((index) & 0x7))
+
+/* This routine will scan through the relocation data of file ENTRY,
+ printing out references to undefined symbols and references to
+ symbols defined in files with N_WARNING symbols. If DATA_SEGMENT
+ is non-zero, it will scan the data relocation segment (and use
+ N_DSLINE symbols to track line number); otherwise it will scan the
+ text relocation segment. Warnings will be printed on the output
+ stream OUTFILE. Eventually, every nlist symbol mapped through will
+ be marked in the NLIST_BITVECTOR, so we don't repeat ourselves when
+ we scan the nlists themselves. */
+
+do_relocation_warnings (entry, data_segment, outfile, nlist_bitvector)
+ struct file_entry *entry;
+ int data_segment;
+ FILE *outfile;
+ unsigned char *nlist_bitvector;
+{
+ struct relocation_info
+ *reloc_start = data_segment ? entry->datarel : entry->textrel,
+ *reloc;
+ long syms_size = entry->syms_size / sizeof (struct nlist);
+ int reloc_size
+ = ((data_segment ? entry->data_reloc_size : entry->text_reloc_size)
+ / sizeof (struct relocation_info));
+ int start_of_segment
+ = (data_segment ? entry->data_start_address : entry->text_start_address);
+ struct nlist *start_of_syms = entry->symbols;
+ struct line_debug_entry *state_pointer
+ = init_debug_scan (data_segment != 0, entry);
+ register struct line_debug_entry *current = state_pointer;
+ /* Assigned to generally static values; should not be written into. */
+ char *errfmt;
+ /* Assigned to alloca'd values cand copied into; should be freed
+ when done. */
+ char *errmsg;
+ int invalidate_line_number;
+
+ /* We need to sort the relocation info here. Sheesh, so much effort
+ for one lousy error optimization. */
+
+ qsort (reloc_start, reloc_size, sizeof (struct relocation_info),
+ relocation_entries_relation);
+
+ for (reloc = reloc_start;
+ reloc < (reloc_start + reloc_size);
+ reloc++)
+ {
+ register struct nlist *s;
+ register symbol *g;
+ int s_index;
+
+ /* If the relocation isn't resolved through a symbol, continue */
+ if (!RELOC_EXTERN_P(reloc))
+ continue;
+
+ s_index = RELOC_SYMBOL(reloc);
+ if (s_index < 0 || s_index >= syms_size)
+ fatal_with_file ("bad symbol in relocation table of ", entry);
+ s = &entry->symbols[s_index];
+
+ /* Local symbols shouldn't ever be used by relocation info, so
+ the next should be safe.
+ This is, of course, wrong. References to local BSS symbols can be
+ the targets of relocation info, and they can (must) be
+ resolved through symbols. However, these must be defined properly,
+ (the assembler would have caught it otherwise), so we can
+ ignore these cases. */
+ if (!(s->n_type & N_EXT))
+ continue;
+
+ g = (symbol *) s->n_un.n_name;
+ errmsg = 0;
+
+ if (!g->defined && list_unresolved_refs) /* Reference */
+ {
+ /* Mark as being noted by relocation warning pass. */
+ SET_BIT (nlist_bitvector, s - start_of_syms);
+
+ if (g->undef_refs >= MAX_UREFS_PRINTED) /* Listed too many */
+ continue;
+
+ /* Undefined symbol which we should mention */
+
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED)
+ {
+ errfmt = "More undefined symbol %s refs follow";
+ invalidate_line_number = 1;
+ }
+ else
+ {
+ errfmt = "Undefined symbol %s referenced from %s segment";
+ invalidate_line_number = 0;
+ }
+ }
+ else /* Defined */
+ {
+ /* Potential symbol warning here */
+ if (!g->warning) continue;
+
+ /* Mark as being noted by relocation warning pass. */
+ SET_BIT (nlist_bitvector, s - start_of_syms);
+
+ errfmt = 0;
+ errmsg = g->warning;
+ invalidate_line_number = 0;
+ }
+
+
+ /* If errfmt == 0, errmsg has already been defined. */
+ if (errfmt != 0)
+ {
+ char *nm;
+
+ if (!demangler || !(nm = (*demangler)(g->name)))
+ nm = g->name;
+ errmsg = xmalloc (strlen (errfmt) + strlen (nm) + 1);
+ sprintf (errmsg, errfmt, nm, data_segment ? "data" : "text");
+ if (nm != g->name)
+ free (nm);
+ }
+
+ address_to_line (RELOC_ADDRESS (reloc) + start_of_segment,
+ state_pointer);
+
+ if (current->line >=0)
+ {
+ fprintf (outfile, "%s:%d (", current->filename,
+ invalidate_line_number ? 0 : current->line);
+ print_file_name (entry, outfile);
+ fprintf (outfile, "): %s\n", errmsg);
+ }
+ else
+ {
+ print_file_name(entry, outfile);
+ fprintf(outfile, ": %s\n", errmsg);
+ }
+
+ if (errfmt != 0)
+ free (errmsg);
+ }
+
+ free (state_pointer);
+}
+
+/* Print on OUTFILE a list of all warnings generated by references
+ and/or definitions in the file ENTRY. List source file and line
+ number if possible, just the .o file if not. */
+
+void
+do_file_warnings (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ int number_of_syms = entry->syms_size / sizeof (struct nlist);
+ unsigned char *nlist_bitvector
+ = (unsigned char *) alloca ((number_of_syms >> 3) + 1);
+ struct line_debug_entry *text_scan, *data_scan;
+ int i;
+ char *errfmt, *file_name;
+ int line_number;
+ int dont_allow_symbol_name;
+
+ bzero (nlist_bitvector, (number_of_syms >> 3) + 1);
+
+ /* Read in the files strings if they aren't available */
+ if (!entry->strings)
+ {
+ int desc;
+
+ entry->strings = (char *) alloca (entry->strs_size);
+ desc = file_open (entry);
+ read_entry_strings (desc, entry);
+ }
+
+ read_file_relocation (entry);
+
+ /* Do text warnings based on a scan through the relocation info. */
+ do_relocation_warnings (entry, 0, outfile, nlist_bitvector);
+
+ /* Do data warnings based on a scan through the relocation info. */
+ do_relocation_warnings (entry, 1, outfile, nlist_bitvector);
+
+ /* Scan through all of the nlist entries in this file and pick up
+ anything that the scan through the relocation stuff didn't. */
+
+ text_scan = init_debug_scan (0, entry);
+ data_scan = init_debug_scan (1, entry);
+
+ for (i = 0; i < number_of_syms; i++)
+ {
+ struct nlist *s;
+ struct glosym *g;
+
+ s = entry->symbols + i;
+
+ if (!(s->n_type & N_EXT))
+ continue;
+
+ g = (symbol *) s->n_un.n_name;
+ dont_allow_symbol_name = 0;
+
+ if (list_multiple_defs && g->multiply_defined)
+ {
+ errfmt = "Definition of symbol %s (multiply defined)";
+ switch (s->n_type)
+ {
+ case N_ABS | N_EXT:
+ line_number = -1;
+ break;
+ case N_TEXT | N_EXT:
+ line_number = address_to_line (s->n_value, text_scan);
+ file_name = text_scan[0].filename;
+ break;
+ case N_DATA | N_EXT:
+ line_number = address_to_line (s->n_value, data_scan);
+ file_name = data_scan[0].filename;
+ break;
+ case N_SETA | N_EXT:
+ case N_SETT | N_EXT:
+ case N_SETD | N_EXT:
+ case N_SETB | N_EXT:
+ if (g->multiply_defined == 2)
+ continue;
+ errfmt = "First set element definition of symbol %s (multiply defined)";
+ break;
+ default:
+ continue; /* Don't print out multiple defs
+ at references. */
+ }
+ }
+ else if (BIT_SET_P (nlist_bitvector, i))
+ continue;
+ else if (list_unresolved_refs && !g->defined)
+ {
+ if (g->undef_refs >= MAX_UREFS_PRINTED)
+ continue;
+
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED)
+ errfmt = "More undefined \"%s\" refs follow";
+ else
+ errfmt = "Undefined symbol \"%s\" referenced";
+ line_number = -1;
+ }
+ else if (g->warning)
+ {
+ /* There are two cases in which we don't want to
+ do this. The first is if this is a definition instead of
+ a reference. The second is if it's the reference used by
+ the warning stabs itself. */
+ if (s->n_type != (N_EXT | N_UNDF)
+ || (i && (s-1)->n_type == N_WARNING))
+ continue;
+
+ errfmt = g->warning;
+ line_number = -1;
+ dont_allow_symbol_name = 1;
+ }
+ else
+ continue;
+
+ if (line_number == -1)
+ {
+ print_file_name (entry, outfile);
+ fprintf (outfile, ": ");
+ }
+ else
+ {
+ fprintf (outfile, "%s:%d (", file_name, line_number);
+ print_file_name (entry, outfile);
+ fprintf (outfile, "): ");
+ }
+
+ if (dont_allow_symbol_name)
+ fprintf (outfile, "%s", errfmt);
+ else
+ {
+ char *nm;
+
+ if (!demangler || !(nm = (*demangler)(g->name)))
+ fprintf (outfile, errfmt, g->name);
+ else
+ {
+ fprintf (outfile, errfmt, nm);
+ free (nm);
+ }
+ }
+
+ fputc ('\n', outfile);
+ }
+ free (text_scan);
+ free (data_scan);
+ entry->strings = 0; /* Since it will dissapear anyway. */
+}
+
+do_warnings (outfile)
+ FILE *outfile;
+{
+ list_unresolved_refs = output_style != OUTPUT_RELOCATABLE && undefined_global_sym_count;
+ list_warning_symbols = warning_count;
+ list_multiple_defs = multiple_def_count != 0;
+
+ if (!(list_unresolved_refs ||
+ list_warning_symbols ||
+ list_multiple_defs ))
+ /* No need to run this routine */
+ return;
+
+ each_file (do_file_warnings, outfile);
+
+ if (entry_symbol && !entry_symbol->defined)
+ fprintf(stderr, "%s: error: Entry symbol `%s' never defined.\n",
+ progname, entry_symbol->name);
+
+ if (list_unresolved_refs || list_multiple_defs)
+ make_executable = 0;
+}
+
+#ifdef A_OUT
+
+/* Stuff pertaining to creating a.out files. */
+
+/* The a.out header. */
+
+#ifdef tek4300
+struct zexec outheader;
+#else
+struct exec outheader;
+#endif
+
+#ifdef COFF_ENCAPSULATE
+int need_coff_header;
+struct coffheader coffheader;
+#endif
+
+/* Compute text_start and text_header_size for an a.out file. */
+
+void
+initialize_a_out_text_start ()
+{
+ int magic;
+
+ switch (output_style)
+ {
+ case OUTPUT_RELOCATABLE:
+ case OUTPUT_WRITABLE_TEXT:
+ magic = OMAGIC;
+ break;
+ case OUTPUT_READONLY_TEXT:
+#ifdef NMAGIC
+ magic = NMAGIC;
+ break;
+#endif
+ case OUTPUT_DEMAND_PAGED:
+ magic = ZMAGIC;
+ break;
+ default:
+ fatal ("unknown output style found (bug in ld)", (char *) 0);
+ break;
+ }
+
+ /* Determine whether to count the header as part of
+ the text size, and initialize the text size accordingly.
+ This depends on the kind of system and on the output format selected. */
+ N_SET_MAGIC (outheader, magic);
+#ifdef INITIALIZE_HEADER
+ INITIALIZE_HEADER;
+#endif
+
+ text_header_size = sizeof (struct exec);
+#ifdef COFF_ENCAPSULATE
+ /* Don't write the coff header for the output of ld -A (since
+ it is not executable by the kernel anyway). */
+ if (output_style != OUTPUT_RELOCATABLE && !file_table[0].just_syms_flag)
+ {
+ need_coff_header = 1;
+ /* set this flag now, since it will change the values of N_TXTOFF, etc */
+ N_SET_FLAGS (outheader, N_FLAGS_COFF_ENCAPSULATE);
+ text_header_size += sizeof (struct coffheader);
+ }
+#endif
+ if (text_header_size <= N_TXTOFF (outheader))
+ text_header_size = 0;
+ else
+ text_header_size -= N_TXTOFF (outheader);
+
+#ifdef _N_BASEADDR
+ /* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
+ outheader.a_entry = N_PAGSIZ(outheader);
+#endif
+
+ if (!T_flag_specified && output_style != OUTPUT_RELOCATABLE)
+ text_start = N_TXTADDR (outheader);
+}
+
+/* Compute data_start once text_size is known. */
+
+void
+initialize_a_out_data_start ()
+{
+ outheader.a_text = text_size;
+#ifdef sequent
+ outheader.a_text += N_ADDRADJ (outheader);
+ if (entry_symbol == 0)
+ entry_symbol = getsym ("start");
+#endif
+ if (! Tdata_flag_specified)
+ data_start = N_DATADDR (outheader) + text_start - N_TXTADDR (outheader);
+}
+
+/* Compute offsets of various pieces of the a.out output file. */
+
+void
+compute_a_out_section_offsets ()
+{
+ outheader.a_data = data_size;
+ outheader.a_bss = bss_size;
+ outheader.a_entry = (entry_symbol ? entry_symbol->value
+ : text_start + text_header_size);
+
+#ifdef COFF_ENCAPSULATE
+ if (need_coff_header)
+ {
+ /* We are encapsulating BSD format within COFF format. */
+ struct coffscn *tp, *dp, *bp;
+
+ tp = &coffheader.scns[0];
+ dp = &coffheader.scns[1];
+ bp = &coffheader.scns[2];
+
+ strcpy (tp->s_name, ".text");
+ tp->s_paddr = text_start;
+ tp->s_vaddr = text_start;
+ tp->s_size = text_size;
+ tp->s_scnptr = sizeof (struct coffheader) + sizeof (struct exec);
+ tp->s_relptr = 0;
+ tp->s_lnnoptr = 0;
+ tp->s_nreloc = 0;
+ tp->s_nlnno = 0;
+ tp->s_flags = 0x20;
+ strcpy (dp->s_name, ".data");
+ dp->s_paddr = data_start;
+ dp->s_vaddr = data_start;
+ dp->s_size = data_size;
+ dp->s_scnptr = tp->s_scnptr + tp->s_size;
+ dp->s_relptr = 0;
+ dp->s_lnnoptr = 0;
+ dp->s_nreloc = 0;
+ dp->s_nlnno = 0;
+ dp->s_flags = 0x40;
+ strcpy (bp->s_name, ".bss");
+ bp->s_paddr = dp->s_vaddr + dp->s_size;
+ bp->s_vaddr = bp->s_paddr;
+ bp->s_size = bss_size;
+ bp->s_scnptr = 0;
+ bp->s_relptr = 0;
+ bp->s_lnnoptr = 0;
+ bp->s_nreloc = 0;
+ bp->s_nlnno = 0;
+ bp->s_flags = 0x80;
+
+ coffheader.f_magic = COFF_MAGIC;
+ coffheader.f_nscns = 3;
+ /* store an unlikely time so programs can
+ * tell that there is a bsd header
+ */
+ coffheader.f_timdat = 1;
+ coffheader.f_symptr = 0;
+ coffheader.f_nsyms = 0;
+ coffheader.f_opthdr = 28;
+ coffheader.f_flags = 0x103;
+ /* aouthdr */
+ coffheader.magic = ZMAGIC;
+ coffheader.vstamp = 0;
+ coffheader.tsize = tp->s_size;
+ coffheader.dsize = dp->s_size;
+ coffheader.bsize = bp->s_size;
+ coffheader.entry = outheader.a_entry;
+ coffheader.text_start = tp->s_vaddr;
+ coffheader.data_start = dp->s_vaddr;
+ }
+#endif
+
+ if (strip_symbols == STRIP_ALL)
+ nsyms = 0;
+ else
+ {
+ nsyms = (defined_global_sym_count
+ + undefined_global_sym_count);
+ if (discard_locals == DISCARD_L)
+ nsyms += non_L_local_sym_count;
+ else if (discard_locals == DISCARD_NONE)
+ nsyms += local_sym_count;
+ /* One extra for following reference on indirects */
+ if (output_style == OUTPUT_RELOCATABLE)
+#ifndef NeXT
+ nsyms += set_symbol_count + global_indirect_count;
+#else
+ nsyms += set_symbol_count;
+#endif
+ }
+
+ if (strip_symbols == STRIP_NONE)
+ nsyms += debugger_sym_count;
+
+ outheader.a_syms = nsyms * sizeof (struct nlist);
+
+ if (output_style == OUTPUT_RELOCATABLE)
+ {
+ outheader.a_trsize = text_reloc_size;
+ outheader.a_drsize = data_reloc_size;
+ }
+ else
+ {
+ outheader.a_trsize = 0;
+ outheader.a_drsize = 0;
+#ifdef tek4300
+ /* UTek has been known to panic without the following ... */
+ outheader.a_textoff = ZMOFF;
+ outheader.a_dataoff = ZMOFF + text_size;
+ outheader.a_textaddr = text_start;
+ outheader.a_dataaddr = data_start;
+ outheader.a_bssaddr = data_start + data_size;
+#endif
+ }
+
+ /* Initialize the various file offsets. */
+
+ output_text_offset = N_TXTOFF (outheader);
+#ifdef N_DATOFF
+ output_data_offset = N_DATOFF (outheader);
+#else
+ output_data_offset = output_text_offset + text_size;
+#endif
+#ifdef N_TRELOFF
+ output_trel_offset = N_TRELOFF (outheader);
+#else
+ output_trel_offset = output_data_offset + data_size;
+#endif
+#ifdef N_DRELOFF
+ output_drel_offset = N_DRELOFF (outheader);
+#else
+ output_drel_offset = output_trel_offset + text_reloc_size;
+#endif
+ output_syms_offset = N_SYMOFF (outheader);
+ output_strs_offset = N_STROFF (outheader);
+}
+
+/* Compute more section offsets once the size of the string table is known. */
+
+void
+compute_more_a_out_section_offsets ()
+{
+ output_symseg_offset = output_strs_offset + output_strs_size;
+}
+
+/* Write the a.out header once everything else is known. */
+
+void
+write_a_out_header ()
+{
+ lseek (outdesc, 0L, 0);
+
+#ifdef COFF_ENCAPSULATE
+ if (need_coff_header)
+ mywrite (&coffheader, sizeof coffheader, 1, outdesc);
+#endif
+
+#ifdef tek4300
+ if (outheader.a_magic == ZMAGIC)
+ mywrite (&outheader, sizeof outheader, 1, outdesc);
+ else
+#endif
+ mywrite (&outheader, sizeof (struct exec), 1, outdesc);
+
+ /* Output whatever padding is required in the executable file
+ between the header and the start of the text. */
+
+#ifndef COFF_ENCAPSULATE
+ padfile (N_TXTOFF (outheader) - sizeof outheader, outdesc);
+#endif
+}
+
+#endif
+
+#ifdef MACH_O
+
+/* Stuff pertaining to creating Mach-O files. */
+
+/* Convert the Mach-O style n_sect references into something the rest
+ of the loader can understand. */
+
+void
+translate_mach_o_symbols (entry)
+ struct file_entry *entry;
+{
+ int i, n, g;
+ struct nlist *sym;
+
+ n = entry->syms_size / sizeof (struct nlist);
+ for (i = 0; i < n; ++i)
+ if (((sym = &entry->symbols[i])->n_type & ~N_EXT) == N_SECT)
+ {
+ if (sym->n_sect == entry->text_ordinal)
+ sym->n_type = (sym->n_type & N_EXT) | N_TEXT;
+ else if (sym->n_sect == entry->data_ordinal)
+ sym->n_type = (sym->n_type & N_EXT) | N_DATA;
+ else if (sym->n_sect == entry->bss_ordinal)
+ sym->n_type = (sym->n_type & N_EXT) | N_BSS;
+ else
+ fatal_with_file ("unknown section referenced in symbols of ", entry);
+ sym->n_sect = 0;
+ }
+ else if ((sym = &entry->symbols[i])->n_type == N_SLINE)
+ {
+ if (sym->n_sect == entry->text_ordinal)
+ sym->n_type = N_SLINE;
+ else if (sym->n_sect == entry->data_ordinal)
+ sym->n_type = N_DSLINE;
+ else if (sym->n_sect == entry->bss_ordinal)
+ sym->n_type = N_BSLINE;
+ else
+ fatal_with_file ("unknown section referenced in debugging symbols of ", entry);
+ }
+}
+
+/* Convert Mach-O style relocation info into a.out style relocation
+ info internally. */
+void
+translate_mach_o_relocation (entry, reloc, count)
+ struct file_entry *entry;
+ struct relocation_info *reloc;
+ int count;
+{
+ int i;
+
+ for (i = 0; i < count; ++i)
+ if (!RELOC_EXTERN_P(&reloc[i]))
+ if (RELOC_TYPE(&reloc[i]) == R_ABS)
+ RELOC_TYPE(&reloc[i]) = N_ABS;
+ else if (RELOC_TYPE(&reloc[i]) == entry->text_ordinal)
+ RELOC_TYPE(&reloc[i]) = N_TEXT;
+ else if (RELOC_TYPE(&reloc[i]) == entry->data_ordinal)
+ RELOC_TYPE(&reloc[i]) = N_DATA;
+ else if (RELOC_TYPE(&reloc[i]) == entry->bss_ordinal)
+ RELOC_TYPE(&reloc[i]) = N_BSS;
+ else
+ fatal_with_file ("unknown section ordinal in relocation info of ", entry);
+}
+
+/* Header structure for OUTPUT_RELOCATABLE. */
+
+struct
+{
+ struct mach_header header;
+ struct segment_command segment;
+ struct section text;
+ struct section data;
+ struct section bss;
+ struct symtab_command symtab;
+#ifdef LC_SYMSEG
+ struct symseg_command symseg;
+#endif
+} m_object;
+
+#ifdef NeXT
+#define CPU_TYPE CPU_TYPE_MC68030
+#define CPU_SUBTYPE CPU_SUBTYPE_NeXT
+#define THREAD_FLAVOR NeXT_THREAD_STATE_REGS
+#define THREAD_COUNT NeXT_THREAD_STATE_REGS_COUNT
+typedef struct NeXT_thread_state_regs thread_state;
+#define thread_state_entry_field pc
+#endif
+
+/* Header structure for all executable output forms. */
+
+struct
+{
+ struct mach_header header;
+ struct segment_command pagezero;
+ struct segment_command text_segment;
+ struct section text;
+ struct segment_command data_segment;
+ struct section data;
+ struct section bss;
+ struct thread_command unixthread;
+ unsigned long int flavor;
+ unsigned long int count;
+ thread_state state;
+ struct symtab_command symtab;
+#ifdef LC_SYMSEG
+ struct symseg_command symseg;
+#endif
+} m_exec;
+
+/* Compute text_start and text_header_size for an a.out file. */
+
+void
+initialize_mach_o_text_start ()
+{
+ if (output_style != OUTPUT_RELOCATABLE)
+ {
+ text_header_size = sizeof m_exec;
+ if (!T_flag_specified && output_style != OUTPUT_RELOCATABLE)
+ /* We reserve the first page of an executable to trap NULL dereferences. */
+ text_start = page_size;
+ }
+}
+
+/* Compute data_start once text_size is known. */
+
+void
+initialize_mach_o_data_start ()
+{
+ if (! Tdata_flag_specified)
+ data_start = text_start + text_size;
+}
+
+/* Compute offsets of various pieces of the Mach-O output file. */
+void
+compute_mach_o_section_offsets ()
+{
+ int header_size, trsize, drsize;
+
+ switch (output_style)
+ {
+ case OUTPUT_RELOCATABLE:
+ header_size = sizeof m_object;
+ break;
+ default:
+ header_size = sizeof m_exec;
+ break;
+ }
+
+ if (strip_symbols == STRIP_ALL)
+ nsyms = 0;
+ else
+ {
+ nsyms = (defined_global_sym_count
+ + undefined_global_sym_count);
+ if (discard_locals == DISCARD_L)
+ nsyms += non_L_local_sym_count;
+ else if (discard_locals == DISCARD_NONE)
+ nsyms += local_sym_count;
+ /* One extra for following reference on indirects */
+ if (output_style == OUTPUT_RELOCATABLE)
+#ifndef NeXT
+ nsyms += set_symbol_count + global_indirect_count;
+#else
+ nsyms += set_symbol_count;
+#endif
+ }
+
+ if (strip_symbols == STRIP_NONE)
+ nsyms += debugger_sym_count;
+
+ output_text_offset = header_size;
+ output_data_offset = output_text_offset + text_size;
+ output_trel_offset = output_data_offset + data_size;
+ if (output_style == OUTPUT_RELOCATABLE)
+ trsize = text_reloc_size, drsize = data_reloc_size;
+ else
+ trsize = drsize = 0;
+ output_drel_offset = output_trel_offset + trsize;
+ output_syms_offset = output_drel_offset + drsize;
+ output_strs_offset = output_syms_offset + nsyms * sizeof (struct nlist);
+}
+
+/* Compute more section offsets once the size of the string table is known. */
+void
+compute_more_mach_o_section_offsets ()
+{
+ output_symseg_offset = output_strs_offset + output_strs_size;
+}
+
+/* Write the Mach-O header once everything else is known. */
+
+void
+write_mach_o_header ()
+{
+ struct mach_header header;
+ struct section text, data, bss;
+ struct symtab_command symtab;
+#ifdef LC_SYMSEG
+ struct symseg_command symseg;
+#endif
+ thread_state state;
+
+ lseek (outdesc, 0L, 0);
+
+
+ header.magic = MH_MAGIC;
+ header.cputype = CPU_TYPE;
+ header.cpusubtype = CPU_SUBTYPE;
+ header.filetype = output_style == OUTPUT_RELOCATABLE ? MH_OBJECT : MH_EXECUTE;
+#ifdef LC_SYMSEG
+ switch (output_style)
+ {
+ case OUTPUT_RELOCATABLE:
+ header.ncmds = 3;
+ header.sizeofcmds = sizeof m_object - sizeof header;
+ break;
+ default:
+ header.ncmds = 6;
+ header.sizeofcmds = sizeof m_exec - sizeof header;
+ break;
+ }
+#else
+ switch (output_style)
+ {
+ case OUTPUT_RELOCATABLE:
+ header.ncmds = 2;
+ header.sizeofcmds = sizeof m_object - sizeof header;
+ break;
+ default:
+ header.ncmds = 5;
+ header.sizeofcmds = sizeof m_exec - sizeof header;
+ break;
+ }
+#endif
+ header.flags = undefined_global_sym_count ? 0 : MH_NOUNDEFS;
+
+ bzero((char *) &text, sizeof text);
+ strncpy(text.sectname, SECT_TEXT, sizeof text.sectname);
+ strncpy(text.segname, SEG_TEXT, sizeof text.segname);
+ text.addr = text_start;
+ text.size = text_size;
+ text.offset = output_text_offset;
+ text.align = text.addr % sizeof (double) ? sizeof (int) : sizeof (double);
+ text.reloff = output_trel_offset;
+ text.nreloc = output_style == OUTPUT_RELOCATABLE
+ ? text_reloc_size / sizeof (struct relocation_info) : 0;
+ text.flags = 0;
+
+ bzero((char *) &data, sizeof data);
+ strncpy(data.sectname, SECT_DATA, sizeof data.sectname);
+ strncpy(data.segname, output_style == OUTPUT_WRITABLE_TEXT ? SEG_TEXT : SEG_DATA,
+ sizeof data.segname);
+ data.addr = data_start;
+ data.size = data_size;
+ data.offset = output_data_offset;
+ data.align = data.addr % sizeof (double) ? sizeof (int) : sizeof (double);
+ data.reloff = output_drel_offset;
+ data.nreloc = output_style == OUTPUT_RELOCATABLE
+ ? data_reloc_size / sizeof (struct relocation_info) : 0;
+ data.flags = 0;
+
+ bzero((char *) &bss, sizeof bss);
+ strncpy(bss.sectname, SECT_BSS, sizeof data.sectname);
+ strncpy(bss.segname, output_style == OUTPUT_WRITABLE_TEXT ? SEG_TEXT : SEG_DATA,
+ sizeof bss.segname);
+ bss.addr = data_start + data_size;
+ bss.size = bss_size;
+ bss.align = bss.addr % sizeof (double) ? sizeof (int) : sizeof (double);
+ bss.reloff = 0;
+ bss.nreloc = 0;
+ bss.flags = S_ZEROFILL;
+
+ symtab.cmd = LC_SYMTAB;
+ symtab.cmdsize = sizeof symtab;
+ symtab.symoff = output_syms_offset;
+ symtab.nsyms = output_syms_size / sizeof (struct nlist);
+ symtab.stroff = output_strs_offset;
+ symtab.strsize = output_strs_size;
+
+#ifdef LC_SYMSEG
+ symseg.cmd = LC_SYMSEG;
+ symseg.cmdsize = sizeof symseg;
+ symseg.offset = output_symseg_offset;
+ symseg.size = output_symseg_size;
+#endif
+
+ switch (output_style)
+ {
+ case OUTPUT_RELOCATABLE:
+ m_object.header = header;
+ m_object.segment.cmd = LC_SEGMENT;
+ m_object.segment.cmdsize = sizeof (struct segment_command) + 3 * sizeof (struct section);
+ strncpy(m_object.segment.segname, SEG_TEXT, sizeof m_object.segment.segname);
+ m_object.segment.vmaddr = 0;
+ m_object.segment.vmsize = text.size + data.size + bss.size;
+ m_object.segment.fileoff = text.offset;
+ m_object.segment.filesize = text.size + data.size;
+ m_object.segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ m_object.segment.initprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ m_object.segment.nsects = 3;
+ m_object.segment.flags = 0;
+ m_object.text = text;
+ m_object.data = data;
+ m_object.bss = bss;
+ m_object.symtab = symtab;
+#ifdef LC_SYMSEG
+ m_object.symseg = symseg;
+#endif
+ mywrite((char *) &m_object, 1, sizeof m_object, outdesc);
+ break;
+
+ default:
+ m_exec.header = header;
+ m_exec.pagezero.cmd = LC_SEGMENT;
+ m_exec.pagezero.cmdsize = sizeof (struct segment_command);
+ strncpy(m_exec.pagezero.segname, SEG_PAGEZERO, sizeof m_exec.pagezero.segname);
+ m_exec.pagezero.vmaddr = 0;
+ m_exec.pagezero.vmsize = page_size;
+ m_exec.pagezero.fileoff = 0;
+ m_exec.pagezero.filesize = 0;
+ m_exec.pagezero.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ m_exec.pagezero.initprot = 0;
+ m_exec.pagezero.nsects = 0;
+ m_exec.pagezero.flags = 0;
+ m_exec.text_segment.cmd = LC_SEGMENT;
+ m_exec.text_segment.cmdsize = sizeof (struct segment_command) + sizeof (struct section);
+ strncpy(m_exec.text_segment.segname, SEG_TEXT, sizeof m_exec.text_segment.segname);
+ m_exec.text_segment.vmaddr = text_start;
+ m_exec.text_segment.vmsize = text_size;
+ m_exec.text_segment.fileoff = output_text_offset;
+ m_exec.text_segment.filesize = text_size;
+ m_exec.text_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ m_exec.text_segment.initprot = VM_PROT_READ | VM_PROT_EXECUTE;
+ if (output_style == OUTPUT_WRITABLE_TEXT)
+ m_exec.text_segment.initprot |= VM_PROT_WRITE;
+ m_exec.text_segment.nsects = 1;
+ m_exec.text_segment.flags = 0;
+ m_exec.text = text;
+ m_exec.data_segment.cmd = LC_SEGMENT;
+ m_exec.data_segment.cmdsize = sizeof (struct segment_command) + 2 * sizeof (struct section);
+ strncpy(m_exec.data_segment.segname, SEG_DATA, sizeof m_exec.data_segment.segname);
+ m_exec.data_segment.vmaddr = data_start;
+ m_exec.data_segment.vmsize = data_size + bss_size;
+ m_exec.data_segment.fileoff = output_data_offset;
+ m_exec.data_segment.filesize = data_size;
+ m_exec.data_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ m_exec.data_segment.initprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ m_exec.data_segment.nsects = 2;
+ m_exec.data_segment.flags = 0;
+ m_exec.data = data;
+ m_exec.bss = bss;
+ m_exec.unixthread.cmd = LC_UNIXTHREAD;
+ m_exec.unixthread.cmdsize
+ = sizeof (struct thread_command) + 2 * sizeof (long int) + sizeof (thread_state);
+ m_exec.flavor = THREAD_FLAVOR;
+ m_exec.count = THREAD_COUNT;
+ m_exec.state.thread_state_entry_field = entry_symbol
+ ? entry_symbol->value : text_start + text_header_size;
+ m_exec.symtab = symtab;
+#ifdef LC_SYMSEG
+ m_exec.symseg = symseg;
+#endif
+ mywrite((char *) &m_exec, 1, sizeof m_exec, outdesc);
+ break;
+ }
+}
+
+/* Translate a.out style symbols into Mach-O style symbols. */
+
+void
+generate_mach_o_symbols (syms, nsyms)
+ struct nlist *syms;
+ int nsyms;
+{
+ int i;
+
+ for (i = 0; i < nsyms; ++i)
+ switch (syms[i].n_type)
+ {
+ case N_TEXT:
+ case N_TEXT | N_EXT:
+ syms[i].n_type = syms[i].n_type & N_EXT | N_SECT;
+ syms[i].n_sect = 1; /* text section ordinal */
+ break;
+ case N_DATA:
+ case N_DATA | N_EXT:
+ syms[i].n_type = syms[i].n_type & N_EXT | N_SECT;
+ syms[i].n_sect = 2; /* data section ordinal */
+ break;
+ case N_BSS:
+ case N_BSS | N_EXT:
+ syms[i].n_type = syms[i].n_type & N_EXT | N_BSS;
+ syms[i].n_sect = 3; /* bss section ordinal */
+ break;
+ case N_SLINE:
+ syms[i].n_type = N_SLINE;
+ syms[i].n_sect = 1; /* text section ordinal */
+ break;
+ case N_DSLINE:
+ syms[i].n_type = N_SLINE;
+ syms[i].n_sect = 2; /* data section ordinal */
+ break;
+ case N_BSLINE:
+ syms[i].n_type = N_SLINE;
+ syms[i].n_sect = 3; /* bss section ordinal */
+ break;
+ }
+}
+
+/* Translate a.out style relocation info into Mach-O style relocation
+ info. */
+
+void
+generate_mach_o_relocations (reloc, nreloc)
+ struct relocation_info *reloc;
+ int nreloc;
+{
+ int i;
+
+ for (i = 0; i < nreloc; ++i)
+ if (!RELOC_EXTERN_P (&reloc[i]))
+ switch (RELOC_TYPE (&reloc[i]))
+ {
+ case N_ABS:
+ case N_ABS | N_EXT:
+ RELOC_TYPE (&reloc[i]) = R_ABS;
+ break;
+ case N_TEXT:
+ case N_TEXT | N_EXT:
+ RELOC_TYPE (&reloc[i]) = 1; /* output text section ordinal */
+ break;
+ case N_DATA:
+ case N_DATA | N_EXT:
+ RELOC_TYPE (&reloc[i]) = 2; /* output data section ordinal */
+ break;
+ case N_BSS:
+ case N_BSS | N_EXT:
+ RELOC_TYPE (&reloc[i]) = 3; /* output bss section ordinal */
+ break;
+ }
+}
+
+#endif
+
+/* The following functions are simple switches according to the
+ output style. */
+
+/* Compute text_start and text_header_size as appropriate for the
+ output format. */
+
+void
+initialize_text_start ()
+{
+#ifdef A_OUT
+ if (output_file_type == IS_A_OUT)
+ {
+ initialize_a_out_text_start ();
+ return;
+ }
+#endif
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ {
+ initialize_mach_o_text_start ();
+ return;
+ }
+#endif
+ fatal ("unknown output file type (enum file_type)", (char *) 0);
+}
+
+/* Initialize data_start as appropriate to the output format, once text_size
+ is known. */
+
+void
+initialize_data_start ()
+{
+#ifdef A_OUT
+ if (output_file_type == IS_A_OUT)
+ {
+ initialize_a_out_data_start ();
+ return;
+ }
+#endif
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ {
+ initialize_mach_o_data_start ();
+ return;
+ }
+#endif
+ fatal ("unknown output file type (enum file_type)", (char *) 0);
+}
+
+/* Compute offsets of the various sections within the output file. */
+
+void
+compute_section_offsets ()
+{
+#ifdef A_OUT
+ if (output_file_type == IS_A_OUT)
+ {
+ compute_a_out_section_offsets ();
+ return;
+ }
+#endif
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ {
+ compute_mach_o_section_offsets ();
+ return;
+ }
+#endif
+ fatal ("unknown output file type (enum file_type)", (char *) 0);
+}
+
+/* Compute more section offsets, once the size of the string table
+ is finalized. */
+void
+compute_more_section_offsets ()
+{
+#ifdef A_OUT
+ if (output_file_type == IS_A_OUT)
+ {
+ compute_more_a_out_section_offsets ();
+ return;
+ }
+#endif
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ {
+ compute_more_mach_o_section_offsets ();
+ return;
+ }
+#endif
+ fatal ("unknown output file type (enum file_type)", (char *) 0);
+}
+
+/* Write the output file header, once everything is known. */
+void
+write_header ()
+{
+#ifdef A_OUT
+ if (output_file_type == IS_A_OUT)
+ {
+ write_a_out_header ();
+ return;
+ }
+#endif
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ {
+ write_mach_o_header ();
+ return;
+ }
+#endif
+ fatal ("unknown output file type (enum file_type)", (char *) 0);
+}
+
+/* Write the output file */
+
+void
+write_output ()
+{
+ struct stat statbuf;
+ int filemode, mask;
+
+ /* Remove the old file in case it is owned by someone else.
+ This prevents spurious "not owner" error messages.
+ Don't check for errors from unlink; we don't really care
+ whether it worked.
+
+ Note that this means that if the output file is hard linked,
+ the other names will still have the old contents. This is
+ the way Unix ld works; I'm going to consider it a feature. */
+ (void) unlink (output_filename);
+
+ outdesc = open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (outdesc < 0) perror_name (output_filename);
+
+ if (fstat (outdesc, &statbuf) < 0)
+ perror_name (output_filename);
+
+ filemode = statbuf.st_mode;
+
+ chmod (output_filename, filemode & ~0111);
+
+ /* Calculate the offsets of the various pieces of the output file. */
+ compute_section_offsets ();
+
+ /* Output the text and data segments, relocating as we go. */
+ write_text ();
+ write_data ();
+
+ /* Output the merged relocation info, if requested with `-r'. */
+ if (output_style == OUTPUT_RELOCATABLE)
+ write_rel ();
+
+ /* Output the symbol table (both globals and locals). */
+ write_syms ();
+
+ /* At this point the total size of the symbol table and string table
+ are finalized. */
+ compute_more_section_offsets ();
+
+ /* Copy any GDB symbol segments from input files. */
+ write_symsegs ();
+
+ /* Now that everything is known about the output file, write its header. */
+ write_header ();
+
+ close (outdesc);
+
+ mask = umask (0);
+ umask (mask);
+
+ if (chmod (output_filename, filemode | (0111 & ~mask)) == -1)
+ perror_name (output_filename);
+}
+
+void modify_location (), perform_relocation (), copy_text (), copy_data ();
+
+/* Relocate the text segment of each input file
+ and write to the output file. */
+
+void
+write_text ()
+{
+ if (trace_files)
+ fprintf (stderr, "Copying and relocating text:\n\n");
+
+ lseek (outdesc, output_text_offset + text_header_size, 0);
+
+ each_full_file (copy_text, 0);
+ file_close ();
+
+ if (trace_files)
+ fprintf (stderr, "\n");
+
+ padfile (text_pad, outdesc);
+}
+
+/* Read in all of the relocation information */
+
+void
+read_relocation ()
+{
+ each_full_file (read_file_relocation, 0);
+}
+
+/* Read in the relocation sections of ENTRY if necessary */
+
+void
+read_file_relocation (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *reloc;
+ int desc;
+ int read_return;
+
+ desc = -1;
+ if (!entry->textrel)
+ {
+ reloc = (struct relocation_info *) xmalloc (entry->text_reloc_size);
+ desc = file_open (entry);
+ lseek (desc, entry->starting_offset + entry->text_reloc_offset, L_SET);
+ if (entry->text_reloc_size != (read_return = read (desc, reloc, entry->text_reloc_size)))
+ {
+ fprintf (stderr, "Return from read: %d\n", read_return);
+ fatal_with_file ("premature eof in text relocation of ", entry);
+ }
+ entry->textrel = reloc;
+ }
+
+ if (!entry->datarel)
+ {
+ reloc = (struct relocation_info *) xmalloc (entry->data_reloc_size);
+ if (desc == -1) desc = file_open (entry);
+ lseek (desc, entry->starting_offset + entry->data_reloc_offset, L_SET);
+ if (entry->data_reloc_size != read (desc, reloc, entry->data_reloc_size))
+ fatal_with_file ("premature eof in data relocation of ", entry);
+ entry->datarel = reloc;
+ }
+
+#ifdef MACH_O
+ if (entry->file_type == IS_MACH_O)
+ {
+ translate_mach_o_relocation (entry, entry->textrel,
+ entry->text_reloc_size / sizeof (struct relocation_info));
+ translate_mach_o_relocation (entry, entry->datarel,
+ entry->data_reloc_size / sizeof (struct relocation_info));
+ }
+#endif
+}
+
+/* Read the text segment contents of ENTRY, relocate them,
+ and write the result to the output file.
+ If `-r', save the text relocation for later reuse. */
+
+void
+copy_text (entry)
+ struct file_entry *entry;
+{
+ register char *bytes;
+ register int desc;
+ register struct relocation_info *reloc;
+
+ if (trace_files)
+ prline_file_name (entry, stderr);
+
+ desc = file_open (entry);
+
+ /* Allocate space for the file's text section */
+
+ bytes = (char *) alloca (entry->text_size);
+
+ /* Deal with relocation information however is appropriate */
+
+ if (entry->textrel) reloc = entry->textrel;
+ else if (output_style == OUTPUT_RELOCATABLE)
+ {
+ read_file_relocation (entry);
+ reloc = entry->textrel;
+ }
+ else
+ {
+ reloc = (struct relocation_info *) alloca (entry->text_reloc_size);
+ lseek (desc, entry->starting_offset + entry->text_reloc_offset, L_SET);
+ if (entry->text_reloc_size != read (desc, reloc, entry->text_reloc_size))
+ fatal_with_file ("premature eof in text relocation of ", entry);
+#ifdef MACH_O
+ if (entry->file_type == IS_MACH_O)
+ translate_mach_o_relocation (entry, reloc,
+ entry->text_reloc_size / sizeof (struct relocation_info));
+#endif
+ }
+
+ /* Read the text section into core. */
+
+ lseek (desc, entry->starting_offset + entry->text_offset, L_SET);
+ if (entry->text_size != read (desc, bytes, entry->text_size))
+ fatal_with_file ("premature eof in text section of ", entry);
+
+ /* Relocate the text according to the text relocation. */
+
+ perform_relocation (bytes, entry->text_start_address - entry->orig_text_address,
+ entry->text_size, reloc, entry->text_reloc_size, entry);
+
+ /* Write the relocated text to the output file. */
+
+ mywrite (bytes, 1, entry->text_size, outdesc);
+}
+
+/* Relocate the data segment of each input file
+ and write to the output file. */
+
+void
+write_data ()
+{
+ if (trace_files)
+ fprintf (stderr, "Copying and relocating data:\n\n");
+
+ lseek (outdesc, output_data_offset, 0);
+
+ each_full_file (copy_data, 0);
+ file_close ();
+
+ /* Write out the set element vectors. See digest symbols for
+ description of length of the set vector section. */
+
+ if (set_vector_count)
+ mywrite (set_vectors, 2 * set_symbol_count + set_vector_count,
+ sizeof (unsigned long), outdesc);
+
+ if (trace_files)
+ fprintf (stderr, "\n");
+
+ padfile (data_pad, outdesc);
+}
+
+/* Read the data segment contents of ENTRY, relocate them,
+ and write the result to the output file.
+ If `-r', save the data relocation for later reuse.
+ See comments in `copy_text'. */
+
+void
+copy_data (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *reloc;
+ register char *bytes;
+ register int desc;
+
+ if (trace_files)
+ prline_file_name (entry, stderr);
+
+ desc = file_open (entry);
+
+ bytes = (char *) alloca (entry->data_size);
+
+ if (entry->datarel) reloc = entry->datarel;
+ else if (output_style == OUTPUT_RELOCATABLE) /* Will need this again */
+ {
+ read_file_relocation (entry);
+ reloc = entry->datarel;
+ }
+ else
+ {
+ reloc = (struct relocation_info *) alloca (entry->data_reloc_size);
+ lseek (desc, entry->starting_offset + entry->data_reloc_offset, L_SET);
+ if (entry->data_reloc_size != read (desc, reloc, entry->data_reloc_size))
+ fatal_with_file ("premature eof in data relocation of ", entry);
+#ifdef MACH_O
+ if (entry->file_type == IS_MACH_O)
+ translate_mach_o_relocation (entry, reloc,
+ entry->data_reloc_size / sizeof (struct relocation_info));
+#endif
+ }
+
+ lseek (desc, entry->starting_offset + entry->data_offset, L_SET);
+ if (entry->data_size != read (desc, bytes, entry->data_size))
+ fatal_with_file ("premature eof in data section of ", entry);
+
+ perform_relocation (bytes, entry->data_start_address - entry->orig_data_address,
+ entry->data_size, reloc, entry->data_reloc_size, entry);
+
+ mywrite (bytes, 1, entry->data_size, outdesc);
+}
+
+/* Relocate ENTRY's text or data section contents.
+ DATA is the address of the contents, in core.
+ DATA_SIZE is the length of the contents.
+ PC_RELOCATION is the difference between the address of the contents
+ in the output file and its address in the input file.
+ RELOC_INFO is the address of the relocation info, in core.
+ RELOC_SIZE is its length in bytes. */
+/* This version is about to be severly hacked by Randy. Hope it
+ works afterwards. */
+void
+perform_relocation (data, pc_relocation, data_size, reloc_info, reloc_size, entry)
+ char *data;
+ struct relocation_info *reloc_info;
+ struct file_entry *entry;
+ int pc_relocation;
+ int data_size;
+ int reloc_size;
+{
+ register struct relocation_info *p = reloc_info;
+ struct relocation_info *end
+ = reloc_info + reloc_size / sizeof (struct relocation_info);
+ int text_relocation = entry->text_start_address - entry->orig_text_address;
+ int data_relocation = entry->data_start_address - entry->orig_data_address;
+ int bss_relocation = entry->bss_start_address - entry->orig_bss_address;
+
+ for (; p < end; p++)
+ {
+ register int relocation = 0;
+ register int addr = RELOC_ADDRESS(p);
+ register unsigned int mask = 0;
+
+ if (addr >= data_size)
+ fatal_with_file ("relocation address out of range in ", entry);
+
+ if (RELOC_EXTERN_P(p))
+ {
+ int symindex = RELOC_SYMBOL (p) * sizeof (struct nlist);
+ symbol *sp = ((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name));
+
+#ifdef N_INDR
+ /* Resolve indirection */
+ if ((sp->defined & ~N_EXT) == N_INDR)
+ sp = (symbol *) sp->value;
+#endif
+
+ if (symindex >= entry->syms_size)
+ fatal_with_file ("relocation symbolnum out of range in ", entry);
+
+ /* If the symbol is undefined, leave it at zero. */
+ if (! sp->defined)
+ relocation = 0;
+ else
+ relocation = sp->value;
+ }
+ else switch (RELOC_TYPE(p))
+ {
+ case N_TEXT:
+ case N_TEXT | N_EXT:
+ relocation = text_relocation;
+ break;
+
+ case N_DATA:
+ case N_DATA | N_EXT:
+ relocation = data_relocation;
+ break;
+
+ case N_BSS:
+ case N_BSS | N_EXT:
+ relocation = bss_relocation;
+ break;
+
+ case N_ABS:
+ case N_ABS | N_EXT:
+ /* Don't know why this code would occur, but apparently it does. */
+ break;
+
+ default:
+ fatal_with_file ("nonexternal relocation code invalid in ", entry);
+ }
+
+ if (RELOC_PCREL_P(p))
+ relocation -= pc_relocation;
+
+#ifdef RELOC_ADD_EXTRA
+ relocation += RELOC_ADD_EXTRA(p);
+ if (output_style == OUTPUT_RELOCATABLE)
+ {
+ /* If this RELOC_ADD_EXTRA is 0, it means that the
+ symbol was external and the relocation does not
+ need a fixup here. */
+ if (RELOC_ADD_EXTRA (p))
+ {
+ if (! RELOC_PCREL_P (p))
+ RELOC_ADD_EXTRA (p) = relocation;
+ else
+ RELOC_ADD_EXTRA (p) -= pc_relocation;
+ }
+#if 0
+ if (! RELOC_PCREL_P (p))
+ {
+ if ((int)p->r_type <= RELOC_32
+ || RELOC_EXTERN_P (p) == 0)
+ RELOC_ADD_EXTRA (p) = relocation;
+ }
+ else if (RELOC_EXTERN_P (p))
+ RELOC_ADD_EXTRA (p) -= pc_relocation;
+#endif
+ continue;
+ }
+#endif
+
+ relocation >>= RELOC_VALUE_RIGHTSHIFT(p);
+
+ /* Unshifted mask for relocation */
+ mask = 1 << RELOC_TARGET_BITSIZE(p) - 1;
+ mask |= mask - 1;
+
+ /* Shift everything up to where it's going to be used */
+ relocation <<= RELOC_TARGET_BITPOS(p);
+ mask <<= RELOC_TARGET_BITPOS(p);
+
+#ifdef ns32000
+ /* This code by Ian Dall for the ns32k displacements */
+ {
+ char * loc = (data + addr);
+ int bytes = (1 << RELOC_TARGET_SIZE(p));
+ void put_num(), put_disp(), put_imm();
+ int get_num(), get_disp(), get_imm();
+ switch(p->r_disp)
+ {
+ case 0:
+ if (RELOC_MEMORY_SUB_P(p))
+ put_imm(loc, relocation - get_imm(loc, bytes), bytes);
+ else if (RELOC_MEMORY_ADD_P(p))
+ put_imm(loc, relocation + get_imm(loc, bytes), bytes);
+ break;
+ case 1:
+ if (RELOC_MEMORY_SUB_P(p))
+ put_disp(loc, relocation - get_disp(loc, bytes), bytes);
+ else if (RELOC_MEMORY_ADD_P(p))
+ put_disp(loc, relocation + get_disp(loc, bytes), bytes);
+ break;
+ case 2:
+ if (RELOC_MEMORY_SUB_P(p))
+ put_num(loc, relocation - get_num(loc, bytes), bytes);
+ else if (RELOC_MEMORY_ADD_P(p))
+ put_num(loc, relocation + get_num(loc, bytes), bytes);
+ break;
+ }
+ }
+#else
+ switch (RELOC_TARGET_SIZE(p))
+ {
+ case 0:
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= *(char *) (data + addr);
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += *(char *) (data + addr);
+ *(char *) (data + addr) &= ~mask;
+ *(char *) (data + addr) |= relocation & mask;
+ break;
+
+ case 1:
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= *(short *) (data + addr);
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += *(short *) (data + addr);
+ *(short *) (data + addr) &= ~mask;
+ *(short *) (data + addr) |= relocation & mask;
+ break;
+
+ case 2:
+#ifdef CROSS_LINKER
+ /* This is necessary if the host has stricter alignment
+ than the target. Too slow to use all the time.
+ Also doesn't deal with differing byte-order. */
+ {
+ /* Thing to relocate. */
+ long thing;
+ bcopy (data + addr, &thing, sizeof (thing));
+ if (RELOC_MEMORY_SUB_P (p))
+ relocation -= thing;
+ else if (RELOC_MEMORY_ADD_P (p))
+ relocation += thing;
+ thing = (thing & ~mask) | relocation & mask;
+ bcopy (&thing, data + addr, sizeof (thing));
+ }
+#else /* not CROSS_LINKER */
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= *(long *) (data + addr);
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += *(long *) (data + addr);
+ *(long *) (data + addr) &= ~mask;
+ *(long *) (data + addr) |= relocation & mask;
+#endif /* not CROSS_LINKER */
+ break;
+
+ default:
+ fatal_with_file ("Unimplemented relocation field length in ", entry);
+ }
+#endif /* MINIX */
+ }
+}
+
+/* For OUTPUT_RELOCATABLE only: write out the relocation,
+ relocating the addresses-to-be-relocated. */
+
+void coptxtrel (), copdatrel ();
+
+void
+write_rel ()
+{
+ register int i;
+ register int count = 0;
+
+ if (trace_files)
+ fprintf (stderr, "Writing text relocation:\n\n");
+
+ /* Assign each global symbol a sequence number, giving the order
+ in which `write_syms' will write it.
+ This is so we can store the proper symbolnum fields
+ in relocation entries we write. */
+
+ for (i = 0; i < TABSIZE; i++)
+ {
+ symbol *sp;
+ for (sp = symtab[i]; sp; sp = sp->link)
+ if (sp->referenced || sp->defined)
+ {
+ sp->def_count = count++;
+#ifndef NeXT
+ /* Leave room for the reference required by N_INDR, if
+ necessary. */
+ if ((sp->defined & ~N_EXT) == N_INDR)
+ count++;
+#endif
+ }
+ }
+ /* Correct, because if (OUTPUT_RELOCATABLE), we will also be writing
+ whatever indirect blocks we have. */
+#ifndef NeXT
+ if (count != defined_global_sym_count
+ + undefined_global_sym_count + global_indirect_count)
+#else
+ if (count != defined_global_sym_count
+ + undefined_global_sym_count)
+#endif
+ fatal ("internal error");
+
+ /* Write out the relocations of all files, remembered from copy_text. */
+
+ lseek (outdesc, output_trel_offset, 0);
+ each_full_file (coptxtrel, 0);
+
+ if (trace_files)
+ fprintf (stderr, "\nWriting data relocation:\n\n");
+
+ lseek (outdesc, output_drel_offset, 0);
+ each_full_file (copdatrel, 0);
+
+ if (trace_files)
+ fprintf (stderr, "\n");
+}
+
+void
+coptxtrel (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *p, *end;
+ register int reloc = entry->text_start_address - text_start;
+
+ p = entry->textrel;
+ end = (struct relocation_info *) (entry->text_reloc_size + (char *) p);
+ while (p < end)
+ {
+ RELOC_ADDRESS(p) += reloc;
+ if (RELOC_EXTERN_P(p))
+ {
+ register int symindex = RELOC_SYMBOL(p) * sizeof (struct nlist);
+ symbol *symptr = ((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name));
+
+ if (symindex >= entry->syms_size)
+ fatal_with_file ("relocation symbolnum out of range in ", entry);
+
+#ifdef N_INDR
+ /* Resolve indirection. */
+ if ((symptr->defined & ~N_EXT) == N_INDR)
+ symptr = (symbol *) symptr->value;
+#endif
+
+ /* If the symbol is now defined, change the external relocation
+ to an internal one. */
+
+ if (symptr->defined)
+ {
+ RELOC_EXTERN_P(p) = 0;
+ RELOC_SYMBOL(p) = (symptr->defined & ~N_EXT);
+#ifdef RELOC_ADD_EXTRA
+ /* If we aren't going to be adding in the value in
+ memory on the next pass of the loader, then we need
+ to add it in from the relocation entry. Otherwise
+ the work we did in this pass is lost. */
+ if (!RELOC_MEMORY_ADD_P(p))
+ RELOC_ADD_EXTRA (p) += symptr->value;
+#endif
+ }
+ else
+ /* Debugger symbols come first, so have to start this
+ after them. */
+#ifndef NeXT
+ RELOC_SYMBOL(p) = (symptr->def_count + nsyms
+ - defined_global_sym_count
+ - undefined_global_sym_count
+ - global_indirect_count);
+#else
+ RELOC_SYMBOL(p) = (symptr->def_count + nsyms
+ - defined_global_sym_count
+ - undefined_global_sym_count);
+#endif
+ }
+ p++;
+ }
+
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ generate_mach_o_relocations(entry->textrel,
+ entry->text_reloc_size / sizeof (struct relocation_info));
+#endif
+
+ mywrite (entry->textrel, 1, entry->text_reloc_size, outdesc);
+}
+
+void
+copdatrel (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *p, *end;
+ /* Relocate the address of the relocation.
+ Old address is relative to start of the input file's data section.
+ New address is relative to start of the output file's data section.
+
+ So the amount we need to relocate it by is the offset of this
+ input file's data section within the output file's data section. */
+ register int reloc = entry->data_start_address - data_start;
+
+ p = entry->datarel;
+ end = (struct relocation_info *) (entry->data_reloc_size + (char *) p);
+ while (p < end)
+ {
+ RELOC_ADDRESS(p) += reloc;
+ if (RELOC_EXTERN_P(p))
+ {
+ register int symindex = RELOC_SYMBOL(p) * sizeof (struct nlist);
+ symbol *symptr = ((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name));
+ int symtype;
+
+ if (symindex >= entry->syms_size)
+ fatal_with_file ("relocation symbolnum out of range in ", entry);
+
+#ifdef N_INDR
+ /* Resolve indirection. */
+ if ((symptr->defined & ~N_EXT) == N_INDR)
+ symptr = (symbol *) symptr->value;
+#endif
+
+ symtype = symptr->defined & ~N_EXT;
+
+ if (force_common_definition
+ || symtype == N_DATA || symtype == N_TEXT || symtype == N_ABS)
+ {
+ RELOC_EXTERN_P(p) = 0;
+ RELOC_SYMBOL(p) = symtype;
+ }
+ else
+ /* Debugger symbols come first, so have to start this
+ after them. */
+#ifndef NeXT
+ RELOC_SYMBOL(p)
+ = (((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name))
+ ->def_count
+ + nsyms - defined_global_sym_count
+ - undefined_global_sym_count
+ - global_indirect_count);
+#else
+ RELOC_SYMBOL(p)
+ = (((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name))
+ ->def_count
+ + nsyms - defined_global_sym_count
+ - undefined_global_sym_count);
+#endif
+ }
+ p++;
+ }
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ generate_mach_o_relocations(entry->datarel,
+ entry->data_reloc_size / sizeof (struct relocation_info));
+#endif
+
+ mywrite (entry->datarel, 1, entry->data_reloc_size, outdesc);
+}
+
+void write_file_syms ();
+void write_string_table ();
+
+/* Total size of string table strings allocated so far,
+ including strings in `strtab_vector'. */
+int strtab_size;
+
+/* Vector whose elements are strings to be added to the string table. */
+char **strtab_vector;
+
+/* Vector whose elements are the lengths of those strings. */
+int *strtab_lens;
+
+/* Index in `strtab_vector' at which the next string will be stored. */
+int strtab_index;
+
+/* Add the string NAME to the output file string table.
+ Record it in `strtab_vector' to be output later.
+ Return the index within the string table that this string will have. */
+
+int
+assign_string_table_index (name)
+ char *name;
+{
+ register int index = strtab_size;
+ register int len = strlen (name) + 1;
+
+ strtab_size += len;
+ strtab_vector[strtab_index] = name;
+ strtab_lens[strtab_index++] = len;
+
+ return index;
+}
+
+FILE *outstream = (FILE *) 0;
+
+/* Write the contents of `strtab_vector' into the string table.
+ This is done once for each file's local&debugger symbols
+ and once for the global symbols. */
+
+void
+write_string_table ()
+{
+ register int i;
+
+ lseek (outdesc, output_strs_offset + output_strs_size, 0);
+
+ if (!outstream)
+ outstream = fdopen (outdesc, "w");
+
+ for (i = 0; i < strtab_index; i++)
+ {
+ fwrite (strtab_vector[i], 1, strtab_lens[i], outstream);
+ output_strs_size += strtab_lens[i];
+ }
+
+ fflush (outstream);
+
+ /* Report I/O error such as disk full. */
+ if (ferror (outstream))
+ perror_name (output_filename);
+}
+
+/* Write the symbol table and string table of the output file. */
+
+void
+write_syms ()
+{
+ /* Number of symbols written so far. */
+ int syms_written = 0;
+ register int i;
+ register symbol *sp;
+
+ /* Buffer big enough for all the global symbols. One
+ extra struct for each indirect symbol to hold the extra reference
+ following. */
+ struct nlist *buf
+#ifndef NeXT
+ = (struct nlist *) alloca ((defined_global_sym_count
+ + undefined_global_sym_count
+ + global_indirect_count)
+ * sizeof (struct nlist));
+#else
+ = (struct nlist *) alloca ((defined_global_sym_count
+ + undefined_global_sym_count)
+ * sizeof (struct nlist));
+#endif
+ /* Pointer for storing into BUF. */
+ register struct nlist *bufp = buf;
+
+ /* Size of string table includes the bytes that store the size. */
+ strtab_size = sizeof strtab_size;
+
+ output_syms_size = 0;
+ output_strs_size = strtab_size;
+
+ if (strip_symbols == STRIP_ALL)
+ return;
+
+ /* Write the local symbols defined by the various files. */
+
+ each_file (write_file_syms, &syms_written);
+ file_close ();
+
+ /* Now write out the global symbols. */
+
+ /* Allocate two vectors that record the data to generate the string
+ table from the global symbols written so far. This must include
+ extra space for the references following indirect outputs. */
+
+ strtab_vector = (char **) alloca ((num_hash_tab_syms
+ + global_indirect_count) * sizeof (char *));
+ strtab_lens = (int *) alloca ((num_hash_tab_syms
+ + global_indirect_count) * sizeof (int));
+ strtab_index = 0;
+
+ /* Scan the symbol hash table, bucket by bucket. */
+
+ for (i = 0; i < TABSIZE; i++)
+ for (sp = symtab[i]; sp; sp = sp->link)
+ {
+ struct nlist nl;
+
+#ifdef N_SECT
+ nl.n_sect = 0;
+#else
+ nl.n_other = 0;
+#endif
+ nl.n_desc = 0;
+
+ /* Compute a `struct nlist' for the symbol. */
+
+ if (sp->defined || sp->referenced)
+ {
+ /* common condition needs to be before undefined condition */
+ /* because unallocated commons are set undefined in */
+ /* digest_symbols */
+ if (sp->defined > 1) /* defined with known type */
+ {
+ /* If the target of an indirect symbol has been
+ defined and we are outputting an executable,
+ resolve the indirection; it's no longer needed */
+ if (output_style != OUTPUT_RELOCATABLE
+ && ((sp->defined & ~N_EXT) == N_INDR)
+ && (((symbol *) sp->value)->defined > 1))
+ {
+ symbol *newsp = (symbol *) sp->value;
+ nl.n_type = newsp->defined;
+ nl.n_value = newsp->value;
+ }
+ else
+ {
+ nl.n_type = sp->defined;
+ if (sp->defined != (N_INDR | N_EXT))
+ nl.n_value = sp->value;
+ else
+ nl.n_value = 0;
+ }
+ }
+ else if (sp->max_common_size) /* defined as common but not allocated. */
+ {
+ /* happens only with -r and not -d */
+ /* write out a common definition */
+ nl.n_type = N_UNDF | N_EXT;
+ nl.n_value = sp->max_common_size;
+ }
+ else if (!sp->defined) /* undefined -- legit only if -r */
+ {
+ nl.n_type = N_UNDF | N_EXT;
+ nl.n_value = 0;
+ }
+ else
+ fatal ("internal error: %s defined in mysterious way", sp->name);
+
+ /* Allocate string table space for the symbol name. */
+
+ nl.n_un.n_strx = assign_string_table_index (sp->name);
+
+ /* Output to the buffer and count it. */
+
+ *bufp++ = nl;
+ syms_written++;
+ if (nl.n_type == (N_INDR | N_EXT))
+#ifndef NeXT
+ {
+ struct nlist xtra_ref;
+ xtra_ref.n_type == N_EXT | N_UNDF;
+ xtra_ref.n_un.n_strx
+ = assign_string_table_index (((symbol *) sp->value)->name);
+#ifdef N_SECT
+ xtra_ref.n_sect = 0;
+#else
+ xtra_ref.n_other = 0;
+#endif
+ xtra_ref.n_desc = 0;
+ xtra_ref.n_value = 0;
+ *bufp++ = xtra_ref;
+ syms_written++;
+ }
+#else
+ nl.n_value = assign_string_table_index (((symbol *) sp->value)->name);
+#endif
+ }
+ }
+
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ generate_mach_o_symbols(buf, bufp - buf);
+#endif
+
+ /* Output the buffer full of `struct nlist's. */
+
+ lseek (outdesc, output_syms_offset + output_syms_size, 0);
+ mywrite (buf, sizeof (struct nlist), bufp - buf, outdesc);
+ output_syms_size += sizeof (struct nlist) * (bufp - buf);
+
+ if (syms_written != nsyms)
+ fatal ("internal error: wrong number of symbols written into output file", 0);
+
+ /* Now the total string table size is known, so write it into the
+ first word of the string table. */
+
+ lseek (outdesc, output_strs_offset, 0);
+ mywrite (&strtab_size, sizeof (int), 1, outdesc);
+
+ /* Write the strings for the global symbols. */
+
+ write_string_table ();
+}
+
+/* Write the local and debugger symbols of file ENTRY.
+ Increment *SYMS_WRITTEN_ADDR for each symbol that is written. */
+
+/* Note that we do not combine identical names of local symbols.
+ dbx or gdb would be confused if we did that. */
+
+void
+write_file_syms (entry, syms_written_addr)
+ struct file_entry *entry;
+ int *syms_written_addr;
+{
+ register struct nlist *p = entry->symbols;
+ register struct nlist *end = p + entry->syms_size / sizeof (struct nlist);
+
+ /* Buffer to accumulate all the syms before writing them.
+ It has one extra slot for the local symbol we generate here. */
+ struct nlist *buf
+ = (struct nlist *) alloca (entry->syms_size + sizeof (struct nlist));
+ register struct nlist *bufp = buf;
+
+ /* Upper bound on number of syms to be written here. */
+ int max_syms = (entry->syms_size / sizeof (struct nlist)) + 1;
+
+ /* Make tables that record, for each symbol, its name and its name's length.
+ The elements are filled in by `assign_string_table_index'. */
+
+ strtab_vector = (char **) alloca (max_syms * sizeof (char *));
+ strtab_lens = (int *) alloca (max_syms * sizeof (int));
+ strtab_index = 0;
+
+ /* Generate a local symbol for the start of this file's text. */
+
+#ifndef OFILE_FN_FLAGGED
+ if (discard_locals != DISCARD_ALL)
+#endif
+ {
+ struct nlist nl;
+
+#ifndef OFILE_FN_FLAGGED
+ nl.n_type = N_TEXT;
+#else
+ nl.n_type = N_FN | N_EXT;
+#endif
+ nl.n_un.n_strx = assign_string_table_index (entry->local_sym_name);
+ nl.n_value = entry->text_start_address;
+ nl.n_desc = 0;
+#ifdef N_SECT
+ nl.n_sect = 0;
+#else
+ nl.n_other = 0;
+#endif
+ *bufp++ = nl;
+ (*syms_written_addr)++;
+ entry->local_syms_offset = *syms_written_addr * sizeof (struct nlist);
+ }
+
+ /* Read the file's string table. */
+
+ entry->strings = (char *) alloca (entry->strs_size);
+ read_entry_strings (file_open (entry), entry);
+
+ for (; p < end; p++)
+ {
+ register int type = p->n_type;
+ register int write = 0;
+
+ /* WRITE gets 1 for a non-global symbol that should be written. */
+
+
+ if (SET_ELEMENT_P (type)) /* This occurs even if global. These */
+ /* types of symbols are never written */
+ /* globally, though they are stored */
+ /* globally. */
+ write = output_style == OUTPUT_RELOCATABLE;
+ else if (!(type & (N_STAB | N_EXT)))
+ /* ordinary local symbol */
+ write = ((discard_locals != DISCARD_ALL)
+ && !(discard_locals == DISCARD_L &&
+ (p->n_un.n_strx + entry->strings)[0] == LPREFIX)
+ && type != N_WARNING);
+ else if (!(type & N_EXT))
+ /* debugger symbol */
+ write = (strip_symbols == STRIP_NONE);
+
+ if (write)
+ {
+ /* If this symbol has a name,
+ allocate space for it in the output string table. */
+
+ if (p->n_un.n_strx)
+ p->n_un.n_strx = assign_string_table_index (p->n_un.n_strx
+ + entry->strings);
+
+ /* Output this symbol to the buffer and count it. */
+
+ *bufp++ = *p;
+ (*syms_written_addr)++;
+ }
+ }
+
+#ifdef MACH_O
+ if (output_file_type == IS_MACH_O)
+ generate_mach_o_symbols(buf, bufp - buf);
+#endif
+
+ /* All the symbols are now in BUF; write them. */
+
+ lseek (outdesc, output_syms_offset + output_syms_size, 0);
+ mywrite (buf, sizeof (struct nlist), bufp - buf, outdesc);
+ output_syms_size += sizeof (struct nlist) * (bufp - buf);
+
+ /* Write the string-table data for the symbols just written,
+ using the data in vectors `strtab_vector' and `strtab_lens'. */
+
+ write_string_table ();
+ entry->strings = 0; /* Since it will dissapear anyway. */
+}
+
+/* Copy any GDB symbol segments from the input files to the output file.
+ The contents of the symbol segment is copied without change
+ except that we store some information into the beginning of it. */
+
+void write_file_symseg ();
+
+void
+write_symsegs ()
+{
+ lseek (outdesc, output_symseg_offset, 0);
+ each_file (write_file_symseg, 0);
+}
+
+void
+write_file_symseg (entry)
+ struct file_entry *entry;
+{
+ char buffer[4096];
+ struct symbol_root root;
+ int indesc, len, total;
+
+ if (entry->symseg_size == 0)
+ return;
+
+ output_symseg_size += entry->symseg_size;
+
+ /* This entry has a symbol segment. Read the root of the segment. */
+
+ indesc = file_open (entry);
+ lseek (indesc, entry->symseg_offset + entry->starting_offset, 0);
+ if (sizeof root != read (indesc, &root, sizeof root))
+ fatal_with_file ("premature end of file in symbol segment of ", entry);
+
+ /* Store some relocation info into the root. */
+
+ root.ldsymoff = entry->local_syms_offset;
+ root.textrel = entry->text_start_address - entry->orig_text_address;
+ root.datarel = entry->data_start_address - entry->orig_data_address;
+ root.bssrel = entry->bss_start_address - entry->orig_bss_address;
+ root.databeg = entry->data_start_address - root.datarel;
+ root.bssbeg = entry->bss_start_address - root.bssrel;
+
+ /* Write the modified root into the output file. */
+
+ mywrite (&root, sizeof root, 1, outdesc);
+
+ /* Copy the rest of the symbol segment unchanged. */
+
+ total = entry->symseg_size - sizeof root;
+
+ while (total > 0)
+ {
+ len = read (indesc, buffer, min (sizeof buffer, total));
+
+ if (len != min (sizeof buffer, total))
+ fatal_with_file ("premature end of file in symbol segment of ", entry);
+ total -= len;
+ mywrite (buffer, len, 1, outdesc);
+ }
+
+ file_close ();
+}
+
+/* Define a special symbol (etext, edata, or end). NAME is the
+ name of the symbol, with a leading underscore (whether or not this
+ system uses such underscores). TYPE is its type (e.g. N_DATA | N_EXT).
+ Store a symbol * for the symbol in *SYM if SYM is non-NULL. */
+static void
+symbol_define (name, type, sym)
+ /* const */ char *name;
+ int type;
+ symbol **sym;
+{
+ symbol *thesym;
+
+#if defined(nounderscore)
+ /* Skip the leading underscore. */
+ name++;
+#endif
+
+ thesym = getsym (name);
+ if (thesym->defined)
+ {
+ /* The symbol is defined in some input file. Don't mess with it. */
+ if (sym)
+ *sym = 0;
+ }
+ else
+ {
+ if (thesym->referenced)
+ /* The symbol was not defined, and we are defining it now. */
+ undefined_global_sym_count--;
+ thesym->defined = type;
+ thesym->referenced = 1;
+ if (sym)
+ *sym = thesym;
+ }
+}
+
+/* Create the symbol table entries for `etext', `edata' and `end'. */
+
+void
+symtab_init ()
+{
+ symbol_define ("_edata", N_DATA | N_EXT, &edata_symbol);
+ symbol_define ("_etext", N_TEXT | N_EXT, &etext_symbol);
+ symbol_define ("_end", N_BSS | N_EXT, &end_symbol);
+
+ /* Either _edata or __edata (C names) is OK as far as ANSI is concerned
+ (see section 4.1.2.1). In general, it is best to use __foo and
+ not worry about the confusing rules for the _foo namespace.
+ But HPUX 7.0 uses _edata, so we might as weel be consistent. */
+ symbol_define ("__edata", N_DATA | N_EXT, &edata_symbol_alt);
+ symbol_define ("__etext", N_TEXT | N_EXT, &etext_symbol_alt);
+ symbol_define ("__end", N_BSS | N_EXT, &end_symbol_alt);
+
+#ifdef sun
+ {
+ symbol *dynamic_symbol;
+ symbol_define ("__DYNAMIC", N_ABS | N_EXT, &dynamic_symbol);
+ if (dynamic_symbol)
+ dynamic_symbol->value = 0;
+ }
+#endif
+#ifdef sequent
+ {
+ symbol *i387_flt_symbol;
+ symbol_define ("_387_flt", N_ABS | N_EXT, &i387_flt_symbol);
+ if (i387_flt_symbol)
+ i387_flt_symbol->value = 0;
+ }
+#endif
+#ifdef NeXT
+ {
+ symbol *shlib_init_symbol;
+ symbol_define ("__shared_library_initialization", N_UNDF | N_EXT, &shlib_init_symbol);
+ if (shlib_init_symbol)
+ shlib_init_symbol->max_common_size = sizeof (long int);
+ }
+#endif
+}
+
+/* Compute the hash code for symbol name KEY. */
+
+int
+hash_string (key)
+ char *key;
+{
+ register char *cp;
+ register int k;
+
+ cp = key;
+ k = 0;
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ return k;
+}
+
+/* Get the symbol table entry for the global symbol named KEY.
+ Create one if there is none. */
+
+symbol *
+getsym (key)
+ char *key;
+{
+ register int hashval;
+ register symbol *bp;
+
+ /* Determine the proper bucket. */
+
+ hashval = hash_string (key) % TABSIZE;
+
+ /* Search the bucket. */
+
+ for (bp = symtab[hashval]; bp; bp = bp->link)
+ if (! strcmp (key, bp->name))
+ return bp;
+
+ /* Nothing was found; create a new symbol table entry. */
+
+ bp = (symbol *) xmalloc (sizeof (symbol));
+ bp->refs = 0;
+ bp->name = (char *) xmalloc (strlen (key) + 1);
+ strcpy (bp->name, key);
+ bp->defined = 0;
+ bp->referenced = 0;
+ bp->trace = 0;
+ bp->value = 0;
+ bp->max_common_size = 0;
+ bp->warning = 0;
+ bp->undef_refs = 0;
+ bp->multiply_defined = 0;
+ bp->last_library_ref = 0;
+
+ /* Add the entry to the bucket. */
+
+ bp->link = symtab[hashval];
+ symtab[hashval] = bp;
+
+ ++num_hash_tab_syms;
+
+ return bp;
+}
+
+/* Like `getsym' but return 0 if the symbol is not already known. */
+
+symbol *
+getsym_soft (key)
+ char *key;
+{
+ register int hashval;
+ register symbol *bp;
+
+ /* Determine which bucket. */
+
+ hashval = hash_string (key) % TABSIZE;
+
+ /* Search the bucket. */
+
+ for (bp = symtab[hashval]; bp; bp = bp->link)
+ if (! strcmp (key, bp->name))
+ return bp;
+
+ return 0;
+}
+
+/* Report a usage error.
+ Like fatal except prints a usage summary. */
+
+void
+usage (string, arg)
+ char *string, *arg;
+{
+ if (string)
+ {
+ fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ }
+ fprintf (stderr, "\
+Usage: %s [-d] [-dc] [-dp] [-e symbol] [-l lib] [-n] [-noinhibit-exec]\n\
+ [-nostdlib] [-o file] [-r] [-s] [-t] [-u symbol] [-x] [-y symbol]\n\
+ [-z] [-A file] [-Bstatic] [-D size] [-L libdir] [-M] [-N]\n\
+ [-S] [-T[{text,data}] addr] [-V prefix] [-X] [file...]\n",
+ progname);
+ exit (1);
+}
+
+/* Report a fatal error.
+ STRING is a printf format string and ARG is one arg for it. */
+
+void
+fatal (string, arg)
+ char *string, *arg;
+{
+ fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Report a fatal error. The error message is STRING
+ followed by the filename of ENTRY. */
+
+void
+fatal_with_file (string, entry)
+ char *string;
+ struct file_entry *entry;
+{
+ fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, string);
+ print_file_name (entry, stderr);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Report a fatal error using the message for the last failed system call,
+ followed by the string NAME. */
+
+void
+perror_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "cannot open %s";
+ fatal (s, name);
+}
+
+/* Report a fatal error using the message for the last failed system call,
+ followed by the name of file ENTRY. */
+
+void
+perror_file (entry)
+ struct file_entry *entry;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for ");
+ else
+ s = "cannot open ";
+ fatal_with_file (s, entry);
+}
+
+/* Report a nonfatal error.
+ STRING is a format for printf, and ARG1 ... ARG3 are args for it. */
+
+void
+error (string, arg1, arg2, arg3)
+ char *string, *arg1, *arg2, *arg3;
+{
+ fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, string, arg1, arg2, arg3);
+ fprintf (stderr, "\n");
+}
+
+
+/* Output COUNT*ELTSIZE bytes of data at BUF
+ to the descriptor DESC. */
+
+void
+mywrite (buf, count, eltsize, desc)
+ char *buf;
+ int count;
+ int eltsize;
+ int desc;
+{
+ register int val;
+ register int bytes = count * eltsize;
+
+ while (bytes > 0)
+ {
+ val = write (desc, buf, bytes);
+ if (val <= 0)
+ perror_name (output_filename);
+ buf += val;
+ bytes -= val;
+ }
+}
+
+/* Output PADDING zero-bytes to descriptor OUTDESC.
+ PADDING may be negative; in that case, do nothing. */
+
+void
+padfile (padding, outdesc)
+ int padding;
+ int outdesc;
+{
+ register char *buf;
+ if (padding <= 0)
+ return;
+
+ buf = (char *) alloca (padding);
+ bzero (buf, padding);
+ mywrite (buf, padding, 1, outdesc);
+}
+
+/* Return a newly-allocated string
+ whose contents concatenate the strings S1, S2, S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ register char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ result[len1 + len2 + len3] = 0;
+
+ return result;
+}
+
+/* Parse the string ARG using scanf format FORMAT, and return the result.
+ If it does not parse, report fatal error
+ generating the error message using format string ERROR and ARG as arg. */
+
+int
+parse (arg, format, error)
+ char *arg, *format;
+{
+ int x;
+ if (1 != sscanf (arg, format, &x))
+ fatal (error, arg);
+ return x;
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+char *
+xmalloc (size)
+ int size;
+{
+ register char *result = malloc (size);
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+/* Like realloc but get fatal error if memory is exhausted. */
+
+char *
+xrealloc (ptr, size)
+ char *ptr;
+ int size;
+{
+ register char *result = realloc (ptr, size);
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+#ifdef USG
+
+void
+bzero (p, n)
+ char *p;
+{
+ memset (p, 0, n);
+}
+
+void
+bcopy (from, to, n)
+ char *from, *to;
+{
+ memcpy (to, from, n);
+}
+
+getpagesize ()
+{
+ return (4096);
+}
+
+#endif
+#ifdef ns32000
+/* code by Ian Dall for the ns32k */
+/* Just put out the twos complement value with arbitrary alignment could
+ * just do an assignment if we know we are on a little endian. */
+void put_num(buf,val,n)
+ char *buf;
+ long val;
+ char n;
+{
+ for (; n > 0; n--)
+ {
+ *buf++ = val & 0xff; val >>= 8;
+ }
+}
+
+int get_num(buf, n)
+ char *buf;
+ int n;
+{
+ int val = 0;
+ buf += (n - 1);
+ for (; n > 0; n--)
+ {
+ val = val * 256 + (*buf-- & 0xff);
+ }
+ return val;
+}
+
+/* Immediate operands are bigendian */
+void put_imm(buf,val,n)
+ char *buf;
+ long val;
+ char n;
+{
+ int i;
+ buf += (n - 1);
+ for (i = n - 1; i >= 0; i--)
+ {
+ *buf-- = (val & 0xff); val >>= 8;
+ }
+}
+
+int get_imm(buf, n)
+ char *buf;
+ int n;
+{
+ int val = 0;
+ for (; n > 0; n--)
+ {
+ val = (val * 256) + (*buf++ & 0xff);
+ }
+ return val;
+}
+
+/* This converts an integer "val" to a displacement. The reason for its'
+ existence is the fact that ns32k uses Huffman coded displacements.
+ This implies that the bit order is reversed in displacements and
+ that they are prefixed with a size-tag.
+
+ binary: msb -> lsb 0xxxxxxx byte
+ 10xxxxxx xxxxxxxx word
+ 11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx double word
+
+ This must be taken care of and we do it here!
+ */
+void put_disp(buf,val,n)
+ char *buf;
+ long val;
+ char n;
+{
+ switch(n) {
+ case 1:
+ if (val < -64 || val > 63)
+ fprintf(stderr,"Byte displacement %d, out of range.\n", val);
+ val&=0x7f;
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ case 2:
+ if (val < -8192 || val > 8191)
+ fprintf(stderr,"Word displacement %d, out of range.\n", val);
+ val&=0x3fff;
+ val|=0x8000;
+#ifdef SHOW_NUM
+ printf("%x ",val>>8 & 0xff);
+#endif
+ *buf++=(val>>8);
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ case 4:
+ if (val < -0x1f000000 || val >= 0x20000000)
+ /* if (val < -0x20000000 || val >= 0x20000000) */
+ fprintf(stderr,"Double word displacement %d, out of range\n", val);
+ val|=0xc0000000;
+#ifdef SHOW_NUM
+ printf("%x ",val>>24 & 0xff);
+#endif
+ *buf++=(val>>24);
+#ifdef SHOW_NUM
+ printf("%x ",val>>16 & 0xff);
+#endif
+ *buf++=(val>>16);
+#ifdef SHOW_NUM
+ printf("%x ",val>>8 & 0xff);
+#endif
+ *buf++=(val>>8);
+#ifdef SHOW_NUM
+ printf("%x ",val & 0xff);
+#endif
+ *buf++=val;
+ break;
+ default:
+ error("Internal logic error");
+ }
+}
+
+int sign_extend (value, bits)
+ int value, bits;
+{
+ value = value & ((1 << bits) - 1);
+ return (value & (1 << (bits-1))
+ ? value | (~((1 << bits) - 1))
+ : value);
+}
+
+int get_disp (buffer, n)
+ char *buffer;
+ int n;
+{
+ int Ivalue;
+
+ Ivalue = *buffer++ & 0xff;
+ if (n == 0)
+ if (Ivalue & 0x80)
+ if (Ivalue & 0x40)
+ n = 4;
+ else
+ n = 2;
+ else
+ n = 1;
+ switch (n)
+ {
+ case 1:
+ Ivalue = sign_extend (Ivalue, 7);
+ break;
+ case 2:
+ Ivalue = sign_extend (Ivalue, 6);
+ Ivalue = (Ivalue << 8) | (0xff & *buffer);
+ break;
+ case 4:
+ Ivalue = sign_extend (Ivalue, 6);
+ Ivalue = (Ivalue << 8) | (0xff & *buffer++);
+ Ivalue = (Ivalue << 8) | (0xff & *buffer++);
+ Ivalue = (Ivalue << 8) | (0xff & *buffer);
+ break;
+ default:
+ fprintf(stderr, "get_disp: invalid argument\n");
+ }
+ return Ivalue;
+}
+#endif
+
+#if defined(sun) && defined(sparc)
+int
+getpagesize ()
+{
+ return 8192;
+}
+#endif
diff --git a/binutils-1.9/libconvert b/binutils-1.9/libconvert
new file mode 100755
index 0000000..4b3bda9
--- /dev/null
+++ b/binutils-1.9/libconvert
@@ -0,0 +1,46 @@
+#! /bin/sh
+
+if [ $# != 2 ]
+then
+ echo 'usage: libconvert from.a to.a'
+ exit 1
+fi
+
+fromlib=$1
+tolib=$2
+
+#
+# Convert coff libc to a coff-encapsulated libc
+# suitable for linking with the GNU linker.
+#
+# Extract all members of /lib/libc.a (using coff ar).
+# Convert each using robotussin.
+# Create new libc (using gnu ar) with members in the same order as coff libc.
+
+# set -e makes this script exit if any command gets an error
+set -e
+
+case $fromlib in
+/*) rel_fromlib=$fromlib ;;
+*) rel_fromlib=../$fromlib ;;
+esac
+
+case $tolib in
+/*) rel_tolib=$tolib ;;
+*) rel_tolib=../$tolib ;;
+esac
+
+rm -rf libconvert-tmp
+mkdir libconvert-tmp
+cd libconvert-tmp
+/bin/ar x $rel_fromlib
+for i in *
+do
+ echo $i
+ ../robotussin $i x
+ mv x $i
+done
+rm -f $rel_tolib
+../ar rs $rel_tolib `/bin/ar t $rel_fromlib`
+cd ..
+rm -rf libconvert-tmp
diff --git a/binutils-1.9/nm.c b/binutils-1.9/nm.c
new file mode 100644
index 0000000..6ba3b66
--- /dev/null
+++ b/binutils-1.9/nm.c
@@ -0,0 +1,1204 @@
+/* Describe symbol table of a rel file.
+ Copyright (C) 1986, 1988, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <ar.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include "getopt.h"
+
+#if !defined(A_OUT) && !defined(MACH_O)
+#define A_OUT
+#endif
+
+#ifdef A_OUT
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+/* On native BSD systems, use the system's own a.out.h. */
+#include <a.out.h>
+#endif
+#endif
+
+#ifdef MACH_O
+#ifndef A_OUT
+#include <nlist.h>
+#ifndef N_TEXT
+#define N_TEXT 4
+#define N_DATA 6
+#define N_BSS 8
+#endif
+#ifndef N_FN
+#define N_FN 15
+#endif
+#endif
+#include <sys/loader.h>
+#endif
+
+/* Always use the GNU version of debugging symbol type codes, if possible. */
+#include "stab.h"
+
+/* Struct or union for header of object file. */
+
+#ifdef USG
+#include <string.h>
+/* You might need to compile with -I/usr/include/sys if your fcntl.h
+ isn't in /usr/include (which is where it should be according to POSIX). */
+#include <fcntl.h>
+#else
+#include <strings.h>
+#endif
+
+/* Alloca definitions and includes... */
+
+/* If compiled with GNU C, use the built-in alloca */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+/* If on a sun 4, make sure to include the right definition. */
+#if defined(sun) && defined(sparc)
+#include "alloca.h"
+#else
+char *alloca ();
+#endif
+#endif
+
+char *malloc (), *realloc ();
+
+char *xmalloc (), *xrealloc ();
+
+/* C++ demangler stuff. */
+char *cplus_demangle ();
+
+/* Print NAME on STREAM, demangling if necessary. */
+void
+fprint_name (stream, name)
+ FILE *stream;
+ char *name;
+{
+ char *demangled = cplus_demangle (name);
+ if (demangled == NULL)
+ fputs (name, stream);
+ else
+ {
+ fputs (demangled, stream);
+ free (demangled);
+ }
+}
+
+/* Special global symbol types understood by GNU LD. */
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* Warning message symbol. The name of this symbol will be printed if
+ any symbols from its file are required by the linker. */
+#ifndef N_WARNING
+#define N_WARNING 0x1e
+#endif
+
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+#ifndef N_SETA
+#define N_SETA 0x14 /* Absolute set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETT
+#define N_SETT 0x16 /* Text set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETD
+#define N_SETD 0x18 /* Data set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETB
+#define N_SETB 0x1A /* Bss set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+/* Macros dealing with the set element symbols defined in a.out.h */
+#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
+#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)
+
+#ifndef N_SETV
+#define N_SETV 0x1C /* Pointer to set vector in text area. */
+#endif /* This is output from LD. */
+
+#ifndef __GNU_STAB__
+
+/* Line number for the data section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_DSLINE
+#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
+#endif
+
+/* Line number for the bss section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_BSLINE
+#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
+#endif
+
+#endif /* not __GNU_STAB__ */
+
+/* Name of this program. */
+
+char *program_name;
+
+/* Number of input files specified. */
+
+int number_of_files;
+
+/* Current file's name. */
+
+char *input_name;
+
+/* Current member's name, or 0 if processing a non-library file. */
+
+char *input_member;
+
+#ifdef MACH_O
+/* Section ordinals for N_SECT references. */
+int text_section;
+int data_section;
+int bss_section;
+#endif
+
+/* Offset within archive of the current member,
+ if we are processing an archive. */
+
+int member_offset;
+
+/* Command options. */
+
+int external_only; /* nonzero means print external symbols only. */
+int sort_numerically; /* sort in numerical order rather than alphabetic */
+int reverse_sort; /* sort in downward (alphabetic or numeric) order. */
+int no_sort; /* don't sort; print symbols in order in the file. */
+int undefined_only; /* print undefined symbols only. */
+int file_on_each_line; /* print file name on each line. */
+int debugger_syms; /* print the debugger-only symbols. */
+int print_symdefs; /* describe the __.SYMDEF data in any archive file specified. */
+
+/* The __.SYMDEF member of an archive has the following format:
+ 1) A longword saying the size of the symdef data that follows
+ 2) Zero or more struct symdef filling that many bytes
+ 3) A longword saying how many bytes of strings follow
+ 4) That many bytes of string data.
+*/
+
+struct symdef
+ {
+ long stringoffset; /* Offset of this symbol's name in the string data */
+ long offset; /* Offset in the archive of the header-data for the member that
+ defines this symbol. */
+ };
+
+/* Create a table of debugging stab-codes and corresponding names. */
+#ifdef __GNU_STAB__
+#define __define_stab(NAME, CODE, STRING) {NAME, STRING},
+struct {enum __stab_debug_code code; char *string;} stab_names[]
+ = {
+#include "stab.def"
+ };
+#undef __define_stab
+#endif
+
+char *concat ();
+int decode_arg ();
+void decode_switch ();
+void do_one_file ();
+void do_one_rel_file ();
+void do_symdef_member ();
+void error ();
+void error_with_file ();
+void fatal ();
+void perror_name ();
+void print_file_name ();
+
+void
+main (argc, argv)
+ char **argv;
+ int argc;
+{
+ int i;
+ int c;
+ int ind;
+ static struct option long_options[] =
+ {
+ {"all", 0, &debugger_syms, 1},
+ {"extern-only", 0, &external_only, 1},
+ {"numeric-sort", 0, &sort_numerically, 1},
+ {"print-file-name", 0, &file_on_each_line,1},
+ {"no-sort", 0, &no_sort, 1},
+ {"reverse", 0, &reverse_sort, 1},
+ {"print-symdefs", 0, &print_symdefs, 1},
+ {"undefined-only",0, &undefined_only, 1},
+ {NULL, 0, NULL, 0}
+ };
+
+ program_name = argv[0];
+
+ number_of_files = 0;
+ external_only = 0;
+ sort_numerically = 0;
+ reverse_sort = 0;
+ no_sort = 0;
+ undefined_only = 0;
+ file_on_each_line = 0;
+ debugger_syms = 0;
+ print_symdefs = 0;
+
+ while ((c = getopt_long (argc, argv, "agnoprsu", long_options, &ind)) != EOF)
+ switch (c)
+ {
+ case 0:
+ break;
+
+ case 'a':
+ debugger_syms = 1;
+ break;
+
+ case 'g':
+ external_only = 1;
+ break;
+
+ case 'n':
+ sort_numerically = 1;
+ break;
+
+ case 'o':
+ file_on_each_line = 1;
+ break;
+
+ case 'p':
+ no_sort = 1;
+ break;
+
+ case 'r':
+ reverse_sort = 1;
+ break;
+
+ case 's':
+ print_symdefs = 1;
+ break;
+
+ case 'u':
+ undefined_only = 1;
+ break;
+
+ default:
+ fprintf (stderr, "\
+Usage: %s [-agnoprsu] [+all] [+extern-only] [+numeric-sort]\n\
+ [+print-file-name] [+no-sort] [+reverse] [+print-symdefs]\n\
+ [+undefined-only] [file...]\n", program_name);
+ exit (1);
+ break;
+ }
+
+ number_of_files = argc - optind;
+
+ /* Now scan again and print the files. */
+
+ if (argc == optind)
+ do_one_file ("a.out");
+ else
+ for (i = optind; i < argc; i++)
+ do_one_file (argv[i]);
+
+ exit (0);
+}
+
+/* Print the filename of the current file on 'outfile' (a stdio stream). */
+
+void
+print_file_name (outfile)
+ FILE *outfile;
+{
+ fprintf (outfile, "%s", input_name);
+ if (input_member)
+ fprintf (outfile, "(%s)", input_member);
+}
+
+/* process one input file */
+void scan_library ();
+
+void
+do_one_file (name)
+ char *name;
+{
+ int desc, nchars;
+ char armag[SARMAG];
+
+ desc = open (name, O_RDONLY, 0);
+
+ if (desc < 0)
+ {
+ perror_name (name);
+ return;
+ }
+
+ input_name = name;
+ input_member = 0;
+
+ nchars = read (desc, armag, SARMAG);
+ if (nchars == SARMAG && !strncmp(armag, ARMAG, SARMAG))
+ scan_library (desc);
+ else
+ do_one_rel_file (desc, 0);
+
+ close (desc);
+}
+
+/* Read in the archive data about one member.
+ SUBFILE_OFFSET is the address within the archive of the start of that data.
+
+ Return the length of the member's contents, which does
+ not include the archive data about the member.
+ A pointer to the member's name is stored into *MEMBER_NAME_PTR.
+ If there are no more valid members, return zero. */
+
+int
+decode_library_subfile (desc, subfile_offset, member_name_ptr)
+ int desc;
+ int subfile_offset;
+ char **member_name_ptr;
+{
+ int bytes_read;
+ int namelen;
+ int member_length;
+ char *name;
+ struct ar_hdr hdr1;
+
+ lseek (desc, subfile_offset, 0);
+
+ bytes_read = read (desc, &hdr1, sizeof hdr1);
+ if (!bytes_read)
+ ; /* end of archive */
+
+ else if (sizeof hdr1 != bytes_read)
+ error_with_file ("malformed library archive ");
+
+ else if (sscanf (hdr1.ar_size, "%d", &member_length) != 1)
+ error_with_file ("malformatted header of archive member in ");
+
+ else
+ {
+ for (namelen = 0; ; namelen++)
+ if (hdr1.ar_name[namelen] == 0 || hdr1.ar_name[namelen] == ' '
+ /* Some systems use a slash? Strange. */
+ || hdr1.ar_name[namelen] == '/')
+ break;
+
+ name = (char *) xmalloc (namelen+1);
+ strncpy (name, hdr1.ar_name, namelen);
+ name[namelen] = 0;
+
+ *member_name_ptr = name;
+
+ return member_length;
+ }
+ return 0; /* tell caller to exit loop */
+}
+
+/* Scan a library and describe each member. */
+
+void
+scan_library (desc)
+ int desc;
+{
+ int this_subfile_offset = SARMAG;
+ int member_length;
+
+ if (!file_on_each_line)
+ printf ("\n%s:\n", input_name);
+
+ while (1)
+ {
+ member_length
+ = decode_library_subfile (desc, this_subfile_offset, &input_member);
+ if (member_length == 0)
+ break;
+
+ /* Describe every member except the ranlib data if any. */
+
+ if (strcmp (input_member, "__.SYMDEF"))
+ do_one_rel_file (desc, this_subfile_offset + sizeof (struct ar_hdr));
+ else if (print_symdefs)
+ do_symdef_member (desc, this_subfile_offset + sizeof (struct ar_hdr), member_length);
+
+ this_subfile_offset += ((member_length + sizeof (struct ar_hdr)) + 1) & -2;
+ }
+}
+
+/* Read a file's header and fill in various pieces of information.
+ Return 0 on failure. */
+
+int
+read_header_info (desc, offset, syms_offset, syms_size, strs_offset, strs_size)
+ int desc;
+ long int offset;
+ long int *syms_offset;
+ unsigned int *syms_size;
+ long int *strs_offset;
+ unsigned int *strs_size;
+{
+ int len;
+
+#ifdef A_OUT
+ {
+ struct exec hdr;
+
+ lseek (desc, offset, 0);
+#ifdef HEADER_SEEK_FD
+ /* Skip the headers that encapsulate our data in some other format
+ such as COFF. */
+ HEADER_SEEK_FD (desc);
+#endif
+ len = read (desc, (char *) &hdr, sizeof (struct exec));
+ if (len == sizeof (struct exec) && !N_BADMAG (hdr))
+ {
+ *syms_offset = N_SYMOFF(hdr);
+ *syms_size = hdr.a_syms;
+ *strs_offset = N_STROFF(hdr);
+ lseek(desc, N_STROFF(hdr) + offset, 0);
+ if (read (desc, (char *) strs_size, sizeof *strs_size) != sizeof *strs_size)
+ {
+ error_with_file ("cannot read string table size in ");
+ return 0;
+ }
+ return 1;
+ }
+ }
+#endif
+
+#ifdef MACH_O
+ {
+ struct mach_header mach_header;
+ char *hdrbuf;
+ struct load_command *load_command;
+ struct segment_command *segment_command;
+ struct section *section;
+ struct symtab_command *symtab_command;
+ int symtab_seen;
+ int len, cmd, seg, ordinal;
+
+ symtab_seen = 0;
+
+ lseek (desc, offset, 0);
+ len = read (desc, (char *) &mach_header, sizeof (struct mach_header));
+ if (len == sizeof (struct mach_header) && mach_header.magic == MH_MAGIC)
+ {
+ hdrbuf = xmalloc (mach_header.sizeofcmds);
+ len = read (desc, hdrbuf, mach_header.sizeofcmds);
+ if (len != mach_header.sizeofcmds)
+ {
+ error_with_file ("failure reading Mach-O load commands in ");
+ return 0;
+ }
+ load_command = (struct load_command *) hdrbuf;
+ ordinal = 1;
+ for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
+ {
+ switch (load_command->cmd)
+ {
+ case LC_SEGMENT:
+ segment_command = (struct segment_command *) load_command;
+ section = (struct section *) ((char *) (segment_command + 1));
+ for (seg = 0; seg < segment_command->nsects; ++seg, ++section, ++ordinal)
+ {
+ if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname))
+ text_section = ordinal;
+ else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname))
+ data_section = ordinal;
+ else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname))
+ bss_section = ordinal;
+ }
+ break;
+ case LC_SYMTAB:
+ if (symtab_seen)
+ error_with_file ("more than one LC_SYMTAB in ");
+ else
+ {
+ symtab_seen = 1;
+ symtab_command = (struct symtab_command *) load_command;
+ *syms_offset = symtab_command->symoff;
+ *syms_size = symtab_command->nsyms * sizeof (struct nlist);
+ *strs_offset = symtab_command->stroff;
+ *strs_size = symtab_command->strsize;
+ }
+ break;
+ }
+ load_command = (struct load_command *)
+ ((char *) load_command + load_command->cmdsize);
+ }
+ free (hdrbuf);
+ return 1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+void print_symbols ();
+void print_one_symbol ();
+void read_header ();
+int alphacompare ();
+int valuecompare ();
+int filter_symbols ();
+
+void
+do_one_rel_file (desc, offset)
+ int desc;
+ int offset;
+{
+ struct nlist *symbols_and_strings;
+ int symcount;
+ int totalsize;
+ char *strings;
+ long int syms_offset, strs_offset;
+ unsigned int syms_size, strs_size;
+
+ if (!read_header_info (desc, offset, &syms_offset, &syms_size, &strs_offset, &strs_size))
+ {
+ error_with_file ("malformed input (not a rel file or archive) in ");
+ return;
+ }
+
+ /* Number of symbol entries in the file. */
+ symcount = syms_size / sizeof (struct nlist);
+
+ totalsize = strs_size + syms_size;
+
+ /* Allocate space for symbol entries and string table. */
+ symbols_and_strings = (struct nlist *) xmalloc (totalsize);
+ strings = (char *) symbols_and_strings + syms_size;
+
+ /* Read them both in. */
+ lseek (desc, syms_offset + offset, 0);
+ if (syms_size != read (desc, (char *) symbols_and_strings, syms_size))
+ {
+ error_with_file ("premature end of file in symbols of ");
+ return;
+ }
+ lseek (desc, strs_offset + offset, 0);
+ if (strs_size != read (desc, (char *) strings, strs_size))
+ {
+ error_with_file ("premature end of file in strings of ");
+ return;
+ }
+
+ /* Identify this file, if desired. */
+
+ if (!file_on_each_line && (number_of_files > 1 || input_member))
+ printf ("\n%s:\n", input_member ? input_member : input_name);
+
+ /* Discard the symbols we don't want to print; compact the rest down. */
+
+ symcount = filter_symbols (symbols_and_strings, symcount, strings);
+
+ /* Modify each symbol entry to point directly at the symbol name.
+ This is so the sort routine does not need to be passed
+ the value of `strings' separately. */
+
+ {
+ struct nlist *p = symbols_and_strings;
+ struct nlist *end = symbols_and_strings + symcount;
+
+ for (; p < end; p++)
+ {
+ /* A zero index means there is no string. */
+ if (p->n_un.n_strx != 0)
+ {
+ if (p->n_un.n_strx > 0 && p->n_un.n_strx < strs_size)
+ p->n_un.n_name = strings + p->n_un.n_strx;
+ else
+ {
+ error_with_file ("invalid string table offset in ");
+ return;
+ }
+ }
+ }
+ }
+
+ /* Sort the symbols if desired. */
+
+ if (!no_sort)
+ qsort (symbols_and_strings, symcount, sizeof (struct nlist),
+ sort_numerically ? valuecompare : alphacompare);
+
+ /* Print the symbols in the order they are now in. */
+
+ print_symbols (symbols_and_strings, symcount);
+
+ free (symbols_and_strings);
+}
+
+/* Choose which symbol entries to print;
+ compact them downward to get rid of the rest.
+ Return the number of symbols to be printed. */
+
+int
+filter_symbols (syms, symcount, strings)
+ struct nlist *syms;
+ int symcount;
+ char *strings;
+{
+ struct nlist *from = syms, *to = syms;
+ struct nlist *end = syms + symcount;
+
+ while (from < end)
+ {
+ int keep = 0;
+
+ /* undefined sym or common sym */
+ if (from->n_type == N_EXT) keep = !undefined_only || !from->n_value;
+ /* global defined sym */
+ else if (from->n_type & N_EXT) keep = !undefined_only;
+ /* debugger sym: normally don't print */
+ else if (from->n_type & ~(N_TYPE | N_EXT)) keep = debugger_syms;
+ /* local sym */
+ else keep = !external_only && !undefined_only;
+
+ if (keep)
+ *to++ = *from;
+ from++;
+ }
+
+ return to - syms;
+}
+
+/* Comparison functions for sorting symbols. */
+
+int
+alphacompare (sym1, sym2)
+ struct nlist *sym1, *sym2;
+{
+ if (reverse_sort)
+ {
+ if (!sym2->n_un.n_name)
+ {
+ if (sym1->n_un.n_name) return -1;
+ else return 0;
+ }
+ if (!sym1->n_un.n_name) return 1;
+ return strcmp (sym2->n_un.n_name, sym1->n_un.n_name);
+ }
+ else
+ {
+ if (!sym1->n_un.n_name)
+ {
+ if (sym2->n_un.n_name) return -1;
+ else return 0;
+ }
+ if (!sym2->n_un.n_name) return 1;
+ return strcmp (sym1->n_un.n_name, sym2->n_un.n_name);
+ }
+}
+
+
+int
+valuecompare (sym1, sym2)
+ struct nlist *sym1, *sym2;
+{
+ if (reverse_sort)
+ return sym2->n_value - sym1->n_value;
+ else
+ return sym1->n_value - sym2->n_value;
+}
+
+void
+print_symbols (syms, symcount)
+ struct nlist *syms;
+ int symcount;
+{
+ int i;
+
+ for (i = 0; i < symcount; i++)
+ print_one_symbol (&syms[i]);
+}
+
+void
+print_one_symbol (sym)
+ struct nlist *sym;
+{
+ if (file_on_each_line)
+ {
+ print_file_name (stdout);
+ printf (":");
+ }
+
+ if (undefined_only)
+ {
+ if (sym->n_type == N_EXT && !sym->n_value)
+ {
+ fprint_name (stdout, sym->n_un.n_name);
+ printf ("\n");
+ }
+ return;
+ }
+
+ if (sym->n_type & ~N_EXT || sym->n_value)
+ printf ("%08x ", sym->n_value);
+ else printf (" ");
+
+ switch (sym->n_type)
+ {
+ case N_EXT:
+ if (sym->n_value) printf ("C");
+ else printf ("U");
+ break;
+
+ case 0:
+ if (sym->n_value) printf ("c");
+ else printf ("u");
+ break;
+
+ case N_ABS | N_EXT:
+ printf ("A");
+ break;
+
+ case N_ABS:
+ printf ("a");
+ break;
+
+ case N_TEXT | N_EXT:
+ printf ("T");
+ break;
+
+ case N_TEXT:
+ printf ("t");
+ break;
+
+ case N_DATA | N_EXT:
+ printf ("D");
+ break;
+
+ case N_DATA:
+ printf ("d");
+ break;
+
+ case N_BSS | N_EXT:
+ printf ("B");
+ break;
+
+ case N_BSS:
+ printf ("b");
+ break;
+
+ case N_SETV | N_EXT:
+ printf ("V");
+ break;
+
+ case N_SETV:
+ printf ("v");
+ break;
+
+ case N_SETA | N_EXT:
+ printf ("L");
+ break;
+
+ case N_SETA:
+ printf ("l");
+ break;
+
+ case N_SETT | N_EXT:
+ printf ("X");
+ break;
+
+ case N_SETT:
+ printf ("x");
+ break;
+
+ case N_SETD | N_EXT:
+ printf ("Z");
+ break;
+
+ case N_SETD:
+ printf ("z");
+ break;
+
+ case N_SETB | N_EXT:
+ printf ("S");
+ break;
+
+ case N_SETB:
+ printf ("s");
+ break;
+
+ case N_INDR | N_EXT:
+ printf ("I");
+ break;
+
+ case N_INDR:
+ printf ("i");
+ break;
+
+ case N_WARNING | N_EXT:
+ printf ("W");
+ break;
+
+ case N_WARNING:
+ printf ("w");
+ break;
+
+#ifdef N_SECT
+ case N_SECT:
+ if (sym->n_sect == text_section)
+ printf ("t");
+ else if (sym->n_sect == data_section)
+ printf ("d");
+ else if (sym->n_sect == bss_section)
+ printf ("b");
+ else
+ printf ("%d", sym->n_sect);
+ break;
+
+ case N_SECT | N_EXT:
+ if (sym->n_sect == text_section)
+ printf ("T");
+ else if (sym->n_sect == data_section)
+ printf ("D");
+ else if (sym->n_sect == bss_section)
+ printf ("B");
+ else
+ printf ("%d", sym->n_sect);
+ break;
+#endif
+
+ default:
+ {
+ char *s;
+ int i;
+#ifdef __GNU_STAB__
+ s = "";
+ for (i = sizeof (stab_names) / sizeof (stab_names[0]) - 1;
+ i >= 0; i--)
+ {
+ if (stab_names[i].code
+ == (enum __stab_debug_code) sym->n_type)
+ {
+ s = stab_names[i].string;
+ break;
+ }
+ }
+#else /* not __GNU_STAB__ */
+ switch (sym->n_type)
+ {
+ case N_GSYM:
+ s = "GSYM";
+ break;
+ case N_FNAME:
+ s = "FNAME";
+ break;
+ case N_FUN:
+ s = "FUN";
+ break;
+ case N_STSYM:
+ s = "STSYM";
+ break;
+ case N_LCSYM:
+ s = "LCSYM";
+ break;
+ case N_RSYM:
+ s = "RSYM";
+ break;
+ case N_SLINE:
+ s = "SLINE";
+ break;
+ case N_DSLINE:
+ s = "DSLINE";
+ break;
+ case N_BSLINE:
+ s = "BSLINE";
+ break;
+ case N_SSYM:
+ s = "SSYM";
+ break;
+ case N_SO:
+ s = "SO";
+ break;
+ case N_LSYM:
+ s = "LSYM";
+ break;
+ case N_SOL:
+ s = "SOL";
+ break;
+ case N_PSYM:
+ s = "PSYM";
+ break;
+ case N_ENTRY:
+ s = "ENTRY";
+ break;
+ case N_LBRAC:
+ s = "LBRAC";
+ break;
+ case N_RBRAC:
+ s = "RBRAC";
+ break;
+ case N_BCOMM:
+ s = "BCOMM";
+ break;
+ case N_ECOMM:
+ s = "ECOMM";
+ break;
+ case N_ECOML:
+ s = "ECOML";
+ break;
+ case N_LENG:
+ s = "LENG";
+ break;
+ default:
+ s = "";
+ }
+#endif /* not __GNU_STAB__ */
+ /* %x treats them as unsigned anyway, so if we didn't cast
+ them we'd get 0xffffffff for all 1's instead of 0xff
+ or 0xffff. */
+ printf ("- %02x %04x %5s",
+#ifdef N_SECT
+ (unsigned char) sym->n_sect,
+#else
+ (unsigned char) sym->n_other,
+#endif
+ (unsigned short) sym->n_desc, s);
+ }
+ }
+
+ printf (" ");
+
+ if (sym->n_un.n_name)
+ fprint_name (stdout, sym->n_un.n_name);
+
+ printf ("\n");
+}
+
+void
+do_symdef_member (desc, offset, member_length)
+ int desc;
+ int offset;
+ int member_length;
+{
+ int symdef_size;
+ int nsymdefs;
+ struct symdef *symdefs;
+ int stringsize;
+ char *strings;
+ int i;
+ char *member_name;
+ int member_offset;
+
+ /* read the string-table-length out of the file */
+
+ lseek (desc, offset, 0);
+ if (sizeof symdef_size != read (desc, &symdef_size, sizeof symdef_size))
+ {
+ error_with_file ("premature eof in ");
+ return;
+ }
+
+ if (symdef_size < 0)
+ {
+ error_with_file ("invalid size value in ");
+ return;
+ }
+
+ nsymdefs = symdef_size / sizeof (struct symdef);
+ symdefs = (struct symdef *) alloca (symdef_size);
+ if (symdef_size != read (desc, symdefs, symdef_size))
+ {
+ error_with_file ("premature eof in ");
+ return;
+ }
+
+ if (stringsize < 0)
+ {
+ error_with_file ("invalid size value in ");
+ return;
+ }
+
+ if (sizeof stringsize != read (desc, &stringsize, sizeof stringsize))
+ {
+ error_with_file ("premature eof in ");
+ return;
+ }
+
+ strings = (char *) alloca (stringsize);
+ if (stringsize != read (desc, strings, stringsize))
+ {
+ error_with_file ("premature eof in ");
+ return;
+ }
+
+ if (stringsize + symdef_size + sizeof stringsize + sizeof symdef_size != member_length)
+ {
+ error_with_file ("size of data isn't what the data calls for in ");
+ return;
+ }
+
+ if (!file_on_each_line && (number_of_files > 1 || input_member))
+ printf ("\n%s:\n", input_member ? input_member : input_name);
+
+ member_offset = -1;
+ for (i = 0; i < nsymdefs; i++)
+ {
+ if (symdefs[i].stringoffset < 0 || symdefs[i].stringoffset >= stringsize)
+ {
+ error_with_file ("invalid entry in ");
+ return;
+ }
+ if (member_offset != symdefs[i].offset)
+ {
+ member_offset = symdefs[i].offset;
+ decode_library_subfile (desc, member_offset, &member_name);
+ }
+ if (file_on_each_line)
+ {
+ print_file_name (stdout);
+ printf (":");
+ }
+ printf ("%s in %s\n", symdefs[i].stringoffset + strings, member_name);
+ }
+}
+
+/* Report a fatal error.
+ STRING is a printf format string and ARG is one arg for it. */
+
+void
+fatal (string, arg)
+ char *string, *arg;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Report a nonfatal error.
+ STRING is a printf format string and ARG is one arg for it. */
+
+void
+error (string, arg)
+ char *string, *arg;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+}
+
+/* Report a nonfatal error.
+ STRING is printed, followed by the current file name. */
+
+void
+error_with_file (string)
+ char *string;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, string);
+ print_file_name (stderr);
+ fprintf (stderr, "\n");
+}
+
+/* Report a fatal error using the message for the last failed system call,
+ followed by the string NAME. */
+
+void
+perror_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "cannot open %s";
+ error (s, name);
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+char *
+xmalloc (size)
+ unsigned size;
+{
+ char *result = malloc (size);
+
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+/* Like realloc but get fatal error if out of memory. */
+
+char *
+xrealloc (p, size)
+ char *p;
+ unsigned size;
+{
+ char *result = realloc(p, size);
+
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+/* Return a newly-allocated string
+ whose contents concatenate those of S1, S2, S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ result[len1 + len2 + len3] = 0;
+
+ return result;
+}
+
+#ifdef USG
+
+getpagesize ()
+{
+ return (4096);
+}
+
+#endif
diff --git a/binutils-1.9/objdump.c b/binutils-1.9/objdump.c
new file mode 100644
index 0000000..94c5303
--- /dev/null
+++ b/binutils-1.9/objdump.c
@@ -0,0 +1,418 @@
+/* objdump -- print information about an object file.
+ Copyright (C) 1988, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <errno.h>
+extern int errno;
+#include "getopt.h"
+
+#ifndef COFF_ENCAPSULATE
+#include <a.out.h>
+/* Tell a.out.gnu.h not to try to redefine some things. */
+#define __STRUCT_EXEC_OVERRIDE__
+#define N_NLIST_DECLARED
+#define N_RELOCATION_INFO_DECLARED
+#define N_MAGIC(exec) ((exec).a_magic)
+#include "a.out.gnu.h"
+#else
+#include "a.out.encap.h"
+#endif
+
+char *malloc ();
+
+char *xmalloc ();
+void dump_file ();
+void dump_header ();
+void dump_nstuff ();
+void dump_reloc ();
+void dump_reloc1 ();
+void dump_sym ();
+void error ();
+void usage ();
+
+/* Symbol table. */
+struct nlist *symtbl;
+
+/* Number of elements in `symtbl'. */
+int nsyms;
+
+/* String table. */
+char *strtbl;
+
+/* Number of elements in `strtbl'. */
+int strsize;
+
+/* Name this program was run with. */
+char *program_name;
+
+/* Name of object file currently being processed. */
+char *filename;
+
+void
+read_symbols (execp, f)
+ struct exec *execp;
+ FILE *f;
+{
+ int i;
+ struct nlist *sp;
+
+ if (symtbl)
+ return;
+ nsyms = execp->a_syms / sizeof (struct nlist);
+ if (nsyms == 0)
+ return;
+
+ symtbl = (struct nlist *) xmalloc (nsyms * sizeof (struct nlist));
+
+ fseek (f, N_STROFF (*execp), 0);
+ if (fread ((char *) &strsize, sizeof strsize, 1, f) != 1)
+ error (1, errno, "%s: cannot read string table size", filename);
+ strtbl = xmalloc (strsize);
+ fseek (f, N_STROFF (*execp), 0);
+ if (fread (strtbl, 1, strsize, f) != strsize)
+ error (1, errno, "%s: cannot read string table", filename);
+
+ fseek (f, N_SYMOFF (*execp), 0);
+ if (fread ((char *) symtbl, sizeof (struct nlist), nsyms, f) != nsyms)
+ error (1, errno, "%s: cannot read symbol table", filename);
+
+ for (i = 0, sp = symtbl; i < nsyms; i++, sp++)
+ {
+ if (sp->n_un.n_strx == 0)
+ sp->n_un.n_name = "";
+ else if (sp->n_un.n_strx < 0 || sp->n_un.n_strx > strsize)
+ sp->n_un.n_name = "<bad string table index>";
+ else
+ sp->n_un.n_name = strtbl + sp->n_un.n_strx;
+ }
+}
+
+void
+free_symbols ()
+{
+ if (symtbl)
+ free (symtbl);
+ symtbl = NULL;
+ if (strtbl)
+ free (strtbl);
+ strtbl = NULL;
+}
+
+/* If nonzero, print header information. */
+int print_header = 0;
+
+/* If nonzero, print N_* information. */
+int print_nstuff = 0;
+
+/* If nonzero, print relocation information. */
+int print_relocation = 0;
+
+/* If nonzero, print symbol information. */
+int print_symbols = 0;
+
+/* Size of a page. Required by N_DATADDR in a.out.gnu.h [VAX]. */
+int page_size;
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int ind;
+ int option_given = 0;
+ static struct option long_options[] =
+ {
+ {"symbols", 0, &print_symbols, 1},
+ {"relocation", 0, &print_relocation, 1},
+ {"nstuff", 0, &print_nstuff, 1},
+ {"header", 0, &print_header, 1},
+ {NULL, 0, NULL, 0}
+ };
+
+ page_size = getpagesize ();
+
+ program_name = argv[0];
+
+ while ((c = getopt_long (argc, argv, "hnrt", long_options, &ind))
+ != EOF)
+ {
+ option_given = 1;
+ switch (c)
+ {
+ case 0:
+ break; /* we've been given a long option */
+ case 't':
+ print_symbols = 1;
+ break;
+ case 'r':
+ print_relocation = 1;
+ break;
+ case 'n':
+ print_nstuff = 1;
+ break;
+ case 'h':
+ print_header = 1;
+ break;
+ default:
+ usage ();
+ }
+ }
+
+ if (option_given == 0 || optind == argc)
+ usage ();
+
+ while (optind < argc)
+ dump_file (argv[optind++]);
+
+ exit (0);
+}
+
+void
+dump_file (name)
+ char *name;
+{
+ FILE *f;
+ struct exec exec;
+
+ printf ("%s:\n", name);
+ f = fopen (name, "r");
+ if (f == NULL)
+ {
+ error (0, errno, "%s", name);
+ return;
+ }
+ filename = name;
+
+#ifdef HEADER_SEEK
+ HEADER_SEEK (f);
+#endif
+ if (fread ((char *) &exec, sizeof exec, 1, f) != 1)
+ {
+ error (0, errno, "%s: cannot read header", filename);
+ return;
+ }
+
+ if (N_BADMAG (exec))
+ {
+ error (0, 0, "%s: Not an object file", filename);
+ return;
+ }
+
+ if (print_header)
+ dump_header (&exec);
+
+ if (print_nstuff)
+ dump_nstuff (&exec);
+
+ if (print_symbols)
+ dump_sym (&exec, f);
+
+ if (print_relocation)
+ dump_reloc (&exec, f);
+
+ free_symbols ();
+}
+
+void
+dump_header (execp)
+ struct exec *execp;
+{
+ int x;
+
+#if defined (__GNU_EXEC_MACROS__) && !defined (__STRUCT_EXEC_OVERRIDE__)
+ printf ("magic: 0x%x (%o)", N_MAGIC (*execp), N_MAGIC (*execp));
+ printf ("machine type: %d", N_MACHTYPE (*execp));
+ printf ("flags: 0x%x", N_FLAGS (*execp));
+#else /* non-gnu struct exec. */
+ printf ("magic: 0x%x (%o) ", execp->a_magic, execp->a_magic);
+#endif /* non-gnu struct exec. */
+ printf ("text 0x%x ", execp->a_text);
+ printf ("data 0x%x ", execp->a_data);
+ printf ("bss 0x%x\n", execp->a_bss);
+ printf ("nsyms %d", execp->a_syms / sizeof (struct nlist));
+ x = execp->a_syms % sizeof (struct nlist);
+ if (x)
+ printf (" (+ %d bytes)", x);
+ printf (" entry 0x%x ", execp->a_entry);
+ printf ("trsize 0x%x ", execp->a_trsize);
+ printf ("drsize 0x%x\n", execp->a_drsize);
+}
+
+void
+dump_nstuff (execp)
+ struct exec *execp;
+{
+ printf ("N_BADMAG %d\n", N_BADMAG (*execp));
+ printf ("N_TXTOFF 0x%x\n", N_TXTOFF (*execp));
+ printf ("N_SYMOFF 0x%x\n", N_SYMOFF (*execp));
+ printf ("N_STROFF 0x%x\n", N_STROFF (*execp));
+ printf ("N_TXTADDR 0x%x\n", N_TXTADDR (*execp));
+ printf ("N_DATADDR 0x%x\n", N_DATADDR (*execp));
+}
+
+void
+dump_sym (execp, f)
+ struct exec *execp;
+ FILE *f;
+{
+ int i;
+ struct nlist *sp;
+
+ read_symbols (execp, f);
+ if (nsyms == 0)
+ {
+ printf ("no symbols\n");
+ return;
+ }
+
+ printf ("%3s: %4s %5s %4s %8s\n",
+ "#", "type", "other", "desc", "val");
+ for (i = 0, sp = symtbl; i < nsyms; i++, sp++)
+ {
+ printf ("%3d: %4x %5x %4x %8x %s\n",
+ i,
+ sp->n_type & 0xff,
+ sp->n_other & 0xff,
+ sp->n_desc & 0xffff,
+ sp->n_value,
+ sp->n_un.n_name);
+ }
+}
+
+void
+dump_reloc (execp, f)
+ struct exec *execp;
+ FILE *f;
+{
+ read_symbols (execp, f);
+ if (execp->a_trsize)
+ {
+ printf ("text reloc\n");
+ dump_reloc1 (execp, f, N_TRELOFF (*execp), execp->a_trsize);
+ }
+ if (execp->a_drsize)
+ {
+ printf ("data reloc\n");
+ dump_reloc1 (execp, f, N_DRELOFF (*execp), execp->a_drsize);
+ }
+}
+
+void
+dump_reloc1 (execp, f, off, size)
+ struct exec *execp;
+ FILE *f;
+ int off;
+ int size;
+{
+#if !defined(sun) || !defined(sparc)
+ int nreloc;
+ struct relocation_info reloc;
+ int i;
+
+ nreloc = size / sizeof (struct relocation_info);
+
+ printf ("%3s: %3s %8s %4s\n", "#", "len", "adr", "sym");
+ fseek (f, off, 0);
+ for (i = 0; i < nreloc; i++)
+ {
+ if (fread ((char *) &reloc, sizeof reloc, 1, f) != 1)
+ {
+ error (0, errno, "%s: cannot read relocation information",
+ filename);
+ return;
+ }
+ printf ("%3d: %3d %8x ", i, 1 << reloc.r_length,
+ reloc.r_address);
+
+ if (reloc.r_extern)
+ {
+ printf ("%4d ", reloc.r_symbolnum);
+ if (reloc.r_symbolnum < nsyms)
+ printf ("%s ", symtbl[reloc.r_symbolnum].n_un.n_name);
+ }
+ else
+ {
+ printf (" ");
+ switch (reloc.r_symbolnum & ~N_EXT)
+ {
+ case N_TEXT:
+ printf (".text ");
+ break;
+ case N_DATA:
+ printf (".data ");
+ break;
+ case N_BSS:
+ printf (".bss ");
+ break;
+ case N_ABS:
+ printf (".abs ");
+ break;
+ default:
+ printf ("base %x ", reloc.r_symbolnum);
+ break;
+ }
+ }
+ if (reloc.r_pcrel)
+ printf ("PCREL ");
+#if 0
+ if (reloc.r_pad)
+ printf ("PAD %x ", reloc.r_pad);
+#endif
+ printf ("\n");
+ }
+#endif
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+char *
+xmalloc (n)
+ unsigned n;
+{
+ char *p;
+
+ p = malloc (n);
+ if (p == 0)
+ error (1, 0, "virtual memory exhausted");
+ return p;
+}
+
+#ifdef USG
+int
+getpagesize ()
+{
+ return 4096;
+}
+#endif
+
+#if defined(sun) && defined(sparc)
+int
+getpagesize ()
+{
+ return 8192;
+}
+#endif
+
+void
+usage ()
+{
+ fprintf (stderr, "\
+Usage: %s [-hnrt] [+header] [+nstuff] [+relocation] [+symbols] objfile...\n",
+ program_name);
+ exit (1);
+}
diff --git a/binutils-1.9/ranlib.c b/binutils-1.9/ranlib.c
new file mode 100644
index 0000000..91e72d1
--- /dev/null
+++ b/binutils-1.9/ranlib.c
@@ -0,0 +1,241 @@
+/* Dummy ranlib program for GNU.
+ All it does is `ar rs LIBRARY' for each library specified.
+
+ Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ar.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include "getopt.h"
+#include "signame.h"
+
+#ifndef L_SET
+#define L_SET 0
+#define L_INCR 1
+#endif
+
+#ifndef X_OK
+#define X_OK 1
+#endif
+
+#ifdef USG
+#define bzero(s, n) (memset ((s), 0, (n)))
+#define gettimeofday(TV,TZ) (time (TV))
+#define seconds(TV) TV
+long time();
+#else
+#define seconds(TV) TV.tv_sec
+#include <sys/time.h>
+#endif
+
+#ifdef USG
+#define vfork fork
+#endif
+
+void touch_symdefs ();
+void usage ();
+
+/* The makefile generates a -D switch to define AR_PROG
+ as the location of the GNU `ar' program. */
+char *prog = AR_PROG;
+
+/* The first place we look for `ar', before trying `prog'. */
+char *prog_pref = "/usr/local/gnubin/ar";
+
+/* The name this program was run with. */
+char *program_name;
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ static int touch = 0, verbose = 0;
+ static char short_opts[] = "tv";
+ static struct option long_opts[] =
+ {
+ { "touch", 0, &touch, 0 },
+ { "verbose", 0, &verbose, 0 },
+ { 0, 0, 0, 0 }
+ };
+ register int c;
+ char *args;
+ int longind;
+ char *ar_program;
+
+ program_name = argv[0];
+
+ while ((c = getopt_long (argc, argv, short_opts, long_opts, &longind))
+ != EOF)
+ switch (c)
+ {
+ case 't':
+ touch = 1;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ default:
+ usage ();
+ }
+
+ if (optind == argc)
+ usage ();
+
+ if (access (prog_pref, X_OK) == 0)
+ ar_program = prog_pref;
+ else
+ ar_program = prog;
+
+ args = verbose ? "rsv" : "rs";
+
+ if (touch)
+ touch_symdefs (argc - optind, argv + optind);
+ else
+ {
+ register int i;
+ for (i = optind; i < argc; ++i)
+ {
+ int pid;
+
+ if (verbose)
+ printf ("%s %s %s\n", ar_program, args, argv[i]);
+
+ fflush (stdout);
+ fflush (stderr);
+
+ pid = vfork ();
+ if (pid < 0)
+ {
+ fprintf (stderr, "%s: can not ", program_name);
+ perror ("vfork");
+ }
+ else if (pid == 0)
+ {
+ /* Child side. */
+ execl (ar_program, ar_program, args, argv[i], 0);
+ fprintf (stderr, "%s: can not run ", program_name);
+ perror (ar_program);
+ exit (1);
+ }
+ else
+ {
+ /* Parent side. */
+ int status;
+ if (wait (&status) != pid)
+ {
+ fprintf (stderr, "%s: interrupted during ", program_name);
+ perror ("wait");
+ }
+ if ((status & 0x7f) != 0)
+ {
+ psignal (status & 0x7f, ar_program);
+ exit (1);
+ }
+ else if (((status & 0xff00) >> 8) != 0)
+ exit ((status & 0xff00) >> 8);
+ }
+ }
+ }
+
+ exit (0);
+}
+
+/* "touch" the archive files listed in LARGV, containing LARGC elements.
+ Find the first symdef member in them and update the date to the
+ current one. */
+
+void
+touch_symdefs (largc, largv)
+ int largc;
+ char **largv;
+{
+#ifdef USG
+ long tv;
+#else
+ struct timeval tv;
+ struct timezone tz;
+#endif
+ struct ar_hdr archive_header;
+ int i, rr;
+
+ gettimeofday (&tv, &tz);
+
+ while (largc--)
+ {
+ int fd = open (*largv, O_RDWR);
+
+ if (fd < 0)
+ {
+ fprintf (stderr, "%s: can not open `%s' for ", program_name, *largv);
+ perror ("read/write");
+ largv++;
+ continue;
+ }
+
+ lseek (fd, SARMAG, L_SET);
+
+ rr = read (fd, &archive_header, sizeof (archive_header));
+
+ /* In the general case this loop would be sped up by buffering,
+ but in almost all cases the symdef will be the first member, so
+ I'm not going to bother. */
+
+ while (rr == sizeof (archive_header))
+ {
+ if (!strncmp ("__.SYMDEF", archive_header.ar_name,
+ sizeof ("__.SYMDEF") - 1))
+ {
+ bzero ((char *) archive_header.ar_date,
+ sizeof (archive_header.ar_date));
+
+ sprintf (archive_header.ar_date, "%d", seconds (tv));
+
+ for (i = 0; i < sizeof archive_header.ar_date; i++)
+ if (archive_header.ar_date[i] == '\0')
+ archive_header.ar_date[i] = ' ';
+
+ lseek (fd, - rr, L_INCR);
+ write (fd, &archive_header, sizeof (archive_header));
+ close (fd);
+ break;
+ }
+
+ lseek (fd, atoi (archive_header.ar_size), L_INCR);
+ rr = read (fd, &archive_header, sizeof (archive_header));
+ }
+
+ if (rr != sizeof (archive_header))
+ /* We reached the end of the file. */
+ fprintf (stderr, "%s: can not find `__.SYMDEF' member in `%s'\n",
+ program_name, *largv);
+
+ largv++;
+ }
+}
+
+void
+usage ()
+{
+ fprintf (stderr, "Usage: %s [-tv] [+touch] [+verbose] archive...\n",
+ program_name);
+ exit (1);
+}
diff --git a/binutils-1.9/ranlib.h b/binutils-1.9/ranlib.h
new file mode 100644
index 0000000..936ba34
--- /dev/null
+++ b/binutils-1.9/ranlib.h
@@ -0,0 +1,17 @@
+/* ranlib.h 4.1 83/05/03 */
+
+/*
+ * Structure of the __.SYMDEF table of contents for an archive.
+ * __.SYMDEF begins with a word giving the number of ranlib structures
+ * which immediately follow, and then continues with a string
+ * table consisting of a word giving the number of bytes of strings
+ * which follow and then the strings themselves.
+ * The ran_strx fields index the string table whose first byte is numbered 0.
+ */
+struct ranlib {
+ union {
+ off_t ran_strx; /* string table index of */
+ char *ran_name; /* symbol defined by */
+ } ran_un;
+ off_t ran_off; /* library member at this offset */
+};
diff --git a/binutils-1.9/robotussin.c b/binutils-1.9/robotussin.c
new file mode 100644
index 0000000..061dc41
--- /dev/null
+++ b/binutils-1.9/robotussin.c
@@ -0,0 +1,579 @@
+/* Convert COFF-format object file to BSD format.
+ Used for converting the system libraries so GNU ld can link them.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Jeff Lewis.
+
+ BUGS:
+
+ Should do more to verify that the input COFF file meets our
+ expectations.
+
+ On machines where the structure of the COFF data in the file does
+ not match the structure of the COFF data declared (when, for
+ example sizeof (struct filhdr) != FILHSZ), this program will fail.
+ (Don't ask me why this is ever allowed to come about). Accessor
+ functions/ macros that painstakingly extract the data out of the
+ file and stuff it in the memory struct should be written to fix
+ this on such machines.
+
+ CAVEATS:
+
+ This program cannot claim correctness, however, it does appear to
+ work on my fairly vanilla Sys5r2 machine. Someone with the time
+ and a fine tooth comb (not to mention some documentation on COFF)
+ should correct this! */
+
+#ifndef COFF_ENCAPSULATE
+#define COFF_ENCAPSULATE
+#endif
+
+/* Customization for particular machines. */
+
+#ifdef i386
+#define INPUT_MAGIC I386MAGIC
+#else /* not i386 */
+#if defined (m68k) || defined (mc68000)
+#define INPUT_MAGIC MC68MAGIC
+#endif
+#endif /* not i386 */
+
+#include <stdio.h>
+#include <varargs.h>
+#include <fcntl.h>
+
+#include "a.out.encap.h"
+#define N_ABSOLUTE N_ABS /* N_ABS will be redefined in syms.h */
+#undef N_ABS
+
+#include <filehdr.h>
+#include <aouthdr.h>
+#include <scnhdr.h>
+#include <syms.h>
+#include <reloc.h>
+/* Because of struct alignment on dwords sizeof (struct syment) is different
+ than the syments stored in the file. Therefore, we must kludge: */
+#define sizeof_syment (SYMESZ)
+#define sizeof_reloc (RELSZ)
+#define sizeof_section (SCNHSZ)
+#define sizeof_coff_header (FILHSZ)
+/* Without the following, compiling this is a pain on a BSD4.3 Vax.
+ Though that might not seem useful, the compatibility of byte order
+ between a Vax and a 386 can come in handy for cross-debugging. */
+#ifdef VPRINTF_MISSING
+#define vfprintf(fp, format, ap) _doprnt (format, ap, fp)
+#endif
+
+extern long lseek ();
+extern void exit ();
+extern char *memcpy ();
+extern int errno;
+
+void error (), sys_error ();
+static void reloc_segment ();
+char *mem_alloc ();
+
+int fd_in, fd_out; /* input and output file descriptors */
+
+struct filehdr coff_header; /* file header from the input file */
+struct exec bsd_header; /* file header for the output file */
+
+struct syment *coff_sym_listp; /* list of symbols from the input */
+int *symbol_map; /* mapping of input symbol #'s to
+ output symbol numbers */
+char *text_and_data; /* space for text & data section data */
+char *relocations; /* space for output reloc entries */
+int verbose_flag; /* flag for debugging */
+
+struct scnhdr coff_text_header; /* COFF text section header */
+struct scnhdr coff_data_header; /* COFF data section header */
+struct scnhdr coff_bss_header; /* COFF bss section header */
+int text_sect_num; /* COFF section # for text */
+int data_sect_num; /* COFF section # for data */
+int bss_sect_num; /* COFF section # for bss */
+
+char *program_name; /* Name this program was run with. */
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i, j;
+ char *coff_string_table, *bsd_string_table;
+ register char *pc, *pc2;
+ int string_table_len;
+ int symbol_count;
+ struct scnhdr section;
+ struct nlist name;
+
+ program_name = argv[0];
+
+ if (argc < 3)
+ error ("Usage: %s COFF-file BSD-file", argv[0]);
+ if (argc > 3)
+ verbose_flag = 1;
+
+ fd_in = open (argv[1], O_RDONLY);
+ if (fd_in < 0)
+ sys_error ("cannot open %s", argv[1]);
+
+ fd_out = open (argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd_out < 0)
+ sys_error ("cannot open %s", argv[2]);
+
+ /* Read in the file header and all section headers searching
+ for text, data and bss. We note the section #'s of these
+ sections for use when examining symbols. */
+
+ if (read (fd_in, &coff_header, sizeof_coff_header) != sizeof_coff_header)
+ error ("cannot read file header");
+
+ if (coff_header.f_magic != INPUT_MAGIC)
+ error ("bad magic number in coff file\n");
+
+ lseek (fd_in, sizeof_coff_header + coff_header.f_opthdr, 0);
+
+ for (i = 1; i <= coff_header.f_nscns; ++i)
+ {
+ if (read (fd_in, &section, sizeof_section) != sizeof_section)
+ error ("cannot read section header #%d", i);
+ if (strcmp (section.s_name, _TEXT) == 0)
+ {
+ text_sect_num = i;
+ memcpy (&coff_text_header, &section, sizeof section);
+ }
+ else if (strcmp (section.s_name, _DATA) == 0)
+ {
+ data_sect_num = i;
+ memcpy (&coff_data_header, &section, sizeof section);
+ }
+ else if (strcmp (section.s_name, _BSS) == 0)
+ {
+ bss_sect_num = i;
+ memcpy (&coff_bss_header, &section, sizeof section);
+ }
+ }
+
+#ifdef sun386
+/* The purpose of the following kludge is to cope with the discrepancy
+ between coff_data_header.s_vaddr and coff_text_header.s_size; in a BSD
+ object file, they are assumed equal. It should be ok to use
+ coff_data_header.s_paddr, since it has no other apparent use. */
+ coff_data_header.s_paddr = coff_text_header.s_size;
+ coff_bss_header.s_paddr = coff_data_header.s_size + coff_text_header.s_size;
+#endif
+
+ /* Pass1 thru the symbol table - count usable symbols and map
+ old symbol #'s into new ones (as used by relocation
+ info). We're only interested in keeping the kinds of symbols
+ we'd expect to find in a BSD library object file: no debug
+ symbols, file names, section definition symbols, etc.
+ Section definition symbols are referenced by reloc entries
+ in the COFF file, so we note their position with a negative
+ symbol number indicating the section. -1 is used to flag
+ symbols we're not interested in, yielding an unexpected error
+ if we find any reloc entries referencing them. */
+
+ coff_sym_listp =
+ (struct syment *) mem_alloc (coff_header.f_nsyms * sizeof (struct syment));
+ symbol_map = (int *) mem_alloc (coff_header.f_nsyms * sizeof *symbol_map);
+ if (lseek (fd_in, coff_header.f_symptr, 0) < 0L)
+ sys_error ("cannot seek to COFF symbols");
+ for (i = 0; i < coff_header.f_nsyms; ++i)
+ {
+ if (read (fd_in, coff_sym_listp + i, sizeof_syment) != sizeof_syment)
+ error ("cannot read COFF symbols");
+ }
+ symbol_count = 0;
+ for (i = 0; i < coff_header.f_nsyms; ++i)
+ {
+ if (coff_sym_listp[i].n_scnum != N_DEBUG
+ && coff_sym_listp[i].n_name[0] != '.'
+ && coff_sym_listp[i].n_scnum != -1)
+ {
+ if (verbose_flag)
+ printf ("map %d to %d\n", i, symbol_count);
+ symbol_map[i] = symbol_count++;
+#ifdef sun386
+ if (coff_sym_listp[i].n_scnum == data_sect_num)
+ coff_sym_listp[i].n_value -=
+ coff_data_header.s_vaddr - coff_data_header.s_paddr;
+ else if (coff_sym_listp[i].n_scnum == bss_sect_num)
+ coff_sym_listp[i].n_value -=
+ coff_bss_header.s_vaddr - coff_bss_header.s_paddr;
+#endif
+ }
+ else
+ {
+ if (coff_sym_listp[i].n_sclass == C_STAT)
+ {
+ if (strcmp (coff_sym_listp[i].n_name, _TEXT) == 0)
+ symbol_map[i] = -N_TEXT;
+ else if (strcmp (coff_sym_listp[i].n_name, _DATA) == 0)
+ symbol_map[i] = -N_DATA;
+ else if (strcmp (coff_sym_listp[i].n_name, _BSS) == 0)
+ symbol_map[i] = -N_BSS;
+ else
+ symbol_map[i] = -1;
+ }
+ else
+ {
+ symbol_map[i] = -1;
+ }
+ }
+ /* skip auxillary entries */
+ j = coff_sym_listp[i].n_numaux;
+ if (j != 0)
+ {
+ if (j < 0)
+ error ("invalid numaux");
+ if (j != 1)
+ fprintf (stderr, "unlikely numaux value\n");
+ while (--j >= 0)
+ ++i;
+ }
+ }
+
+ /* Now we know enough to write the output file header. */
+
+ N_SET_MAGIC (bsd_header, OMAGIC);
+ bsd_header.a_text = coff_text_header.s_size;
+ bsd_header.a_data = coff_data_header.s_size;
+ bsd_header.a_bss = coff_bss_header.s_size;
+ bsd_header.a_syms = symbol_count * sizeof (struct nlist);
+ bsd_header.a_entry = 0;
+ bsd_header.a_trsize = coff_text_header.s_nreloc * sizeof (struct relocation_info);
+ bsd_header.a_drsize = coff_data_header.s_nreloc * sizeof (struct relocation_info);
+ if (write (fd_out, &bsd_header, sizeof bsd_header) != sizeof bsd_header)
+ sys_error ("cannot write BSD header");
+
+ /* Read in and save text and data sections - some data in
+ these sections may need to be altered due to relocations. */
+
+ text_and_data = (char *) mem_alloc (coff_text_header.s_size + coff_data_header.s_size);
+ if (lseek (fd_in, coff_text_header.s_scnptr, 0) < 0L)
+ sys_error ("cannot seek to text section");
+ if (read (fd_in, text_and_data, coff_text_header.s_size) != coff_text_header.s_size)
+ error ("cannot read text section");
+ if (lseek (fd_in, coff_data_header.s_scnptr, 0) < 0L)
+ sys_error ("cannot seek to data section");
+ if (read (fd_in, text_and_data + coff_text_header.s_size, coff_data_header.s_size) != coff_data_header.s_size)
+ error ("cannot read data section");
+
+ /* Convert the relocation entries and do any text or data
+ modifications necessary. */
+
+ relocations = (char *) mem_alloc (bsd_header.a_trsize + bsd_header.a_drsize);
+ reloc_segment (&coff_text_header, relocations);
+ reloc_segment (&coff_data_header, relocations + bsd_header.a_trsize);
+
+ if (write (fd_out, text_and_data, coff_text_header.s_size + coff_data_header.s_size)
+ != coff_text_header.s_size + coff_data_header.s_size)
+ sys_error ("cannot write text and data sections");
+ /* ZZ - are there any alignment considerations?? */
+ if ((coff_text_header.s_size & 1) || (coff_data_header.s_size & 1))
+ fprintf (stderr, "non-aligned text or data section\n");
+ if (write (fd_out, relocations, bsd_header.a_trsize + bsd_header.a_drsize)
+ != bsd_header.a_trsize + bsd_header.a_drsize)
+ sys_error ("cannot write relocation entries");
+
+ /* Second pass thru the symbol table.
+ a COFF symbol entry may contain up to 8 chars of symbol name
+ in the entry itself - symbol names > 8 go into the string table,
+ whereas the BSD entry puts all symbol names into the string
+ table. */
+
+ if (lseek (fd_in, coff_header.f_symptr + coff_header.f_nsyms * sizeof_syment, 0) < 0L)
+ error ("cannot seek to string table");
+
+ i = read (fd_in, &string_table_len, sizeof string_table_len);
+ if (i == sizeof string_table_len)
+ {
+ coff_string_table = mem_alloc (string_table_len);
+ string_table_len -= sizeof string_table_len;
+ i = read (fd_in, coff_string_table + sizeof string_table_len, string_table_len);
+ if (i < 0)
+ error ("cannot read string table");
+ if (i != string_table_len)
+ error ("truncated string table - expected %d, got %d",
+ string_table_len, i);
+ }
+ else
+ {
+ string_table_len = 0;
+ }
+ bsd_string_table = mem_alloc (string_table_len + coff_header.f_nsyms * (SYMNMLEN + 1));
+ pc = bsd_string_table + sizeof string_table_len;
+ for (i = 0; i < coff_header.f_nsyms; ++i)
+ {
+ if (coff_sym_listp[i].n_scnum != N_DEBUG
+ && coff_sym_listp[i].n_name[0] != '.'
+ && coff_sym_listp[i].n_scnum != -1)
+ {
+ if (coff_sym_listp[i].n_zeroes == 0)
+ {
+ j = pc - bsd_string_table;
+#ifndef nounderscore
+ if (coff_sym_listp[i].n_sclass == C_EXT
+ || coff_sym_listp[i].n_sclass == C_STAT)
+ *pc++ = '_';
+#endif
+ pc2 = coff_string_table + coff_sym_listp[i].n_offset;
+ while (*pc++ = *pc2++)
+ /* null */ ;
+ name.n_un.n_strx = j;
+ }
+ else
+ {
+ pc2 = &coff_sym_listp[i].n_name[0];
+ j = pc - bsd_string_table;
+#ifndef nounderscore
+ if (coff_sym_listp[i].n_sclass == C_EXT
+ || coff_sym_listp[i].n_sclass == C_STAT)
+ *pc++ = '_';
+#endif
+ {
+ int x;
+ for (x = 0; x < SYMNMLEN; x++)
+ {
+ if (*pc2 == 0)
+ break;
+ *pc++ = *pc2++;
+ }
+ *pc++ = 0;
+ }
+ name.n_un.n_strx = j;
+ }
+ switch (coff_sym_listp[i].n_scnum)
+ {
+ case N_ABS:
+ name.n_type = N_ABSOLUTE;
+ break;
+ case N_UNDEF:
+ name.n_type = N_UNDF;
+ break;
+ default:
+ if (coff_sym_listp[i].n_scnum == text_sect_num)
+ name.n_type = N_TEXT;
+ else if (coff_sym_listp[i].n_scnum == data_sect_num)
+ name.n_type = N_DATA;
+ else if (coff_sym_listp[i].n_scnum == bss_sect_num)
+ name.n_type = N_BSS;
+ break;
+ }
+ if (coff_sym_listp[i].n_sclass == C_EXT)
+ name.n_type |= N_EXT;
+ name.n_other = 0;
+ name.n_desc = 0;
+ name.n_value = coff_sym_listp[i].n_value;
+
+ if (write (fd_out, &name, sizeof name) != sizeof name)
+ sys_error ("cannot write symbol");
+ }
+ /* skip auxillary entries */
+ j = coff_sym_listp[i].n_numaux;
+ if (j != 0)
+ {
+ while (--j >= 0)
+ ++i;
+ }
+ }
+ i = *((int *) bsd_string_table) = pc - bsd_string_table;
+ if (write (fd_out, bsd_string_table, i) != i)
+ error ("cannot write string table");
+
+ close (fd_in);
+ close (fd_out);
+ exit (0);
+}
+
+/* Convert the relocation entries and do any text or data
+ modifications necessary. */
+
+static void
+reloc_segment (section_headerp, reloc_infop)
+ struct scnhdr *section_headerp;
+ struct relocation_info *reloc_infop;
+{
+ struct reloc coff_reloc;
+ int i;
+
+ if (lseek (fd_in, section_headerp->s_relptr, 0) < 0L)
+ error ("cannot seek to relocation entries");
+ for (i = 0; i < section_headerp->s_nreloc; ++i)
+ {
+ if (read (fd_in, &coff_reloc, sizeof_reloc) != sizeof_reloc)
+ error ("cannot read relocation entry");
+#ifdef sun386
+ coff_reloc.r_vaddr -=
+ section_headerp->s_vaddr - section_headerp->s_paddr;
+#endif
+ if (verbose_flag)
+ printf ("vaddr = 0x%x, symndx = %d\n", coff_reloc.r_vaddr, coff_reloc.r_symndx);
+ /* The reloc references a symbol declared common, thus the
+ value of the symbol holds its size (in bytes). In COFF,
+ apparently this info is also put into the binary -
+ BSD doesn't like this, so we subtract it out. */
+ if (coff_sym_listp[coff_reloc.r_symndx].n_scnum == N_UNDEF)
+ {
+ if (coff_sym_listp[coff_reloc.r_symndx].n_value != 0)
+ {
+ if (verbose_flag)
+ printf ("adjust common 0x%x (%d)\n",
+ coff_sym_listp[coff_reloc.r_symndx].n_value,
+ coff_sym_listp[coff_reloc.r_symndx].n_value);
+ switch (coff_reloc.r_type)
+ {
+ case R_RELBYTE:
+ *((char *) (text_and_data + coff_reloc.r_vaddr))
+ -= coff_sym_listp[coff_reloc.r_symndx].n_value;
+ break;
+ case R_RELWORD:
+ *((short *) (text_and_data + coff_reloc.r_vaddr))
+ -= coff_sym_listp[coff_reloc.r_symndx].n_value;
+ break;
+ case R_RELLONG:
+ case R_DIR32: /* these are the only two that really show up */
+ case R_PCRLONG:
+ *((int *) (text_and_data + coff_reloc.r_vaddr))
+ -= coff_sym_listp[coff_reloc.r_symndx].n_value;
+ break;
+ default:
+ error ("unknown relocation type 0%o", coff_reloc.r_type);
+ }
+ }
+ }
+ /* >= 0 means its an extern - value is the output symbol #.
+ < 0 means its an intern - value is N_TEXT, N_DATA or N_BSS. */
+ if (symbol_map[coff_reloc.r_symndx] >= 0)
+ {
+ reloc_infop->r_symbolnum = symbol_map[coff_reloc.r_symndx];
+ reloc_infop->r_extern = 1;
+ }
+ else
+ {
+ if (symbol_map[coff_reloc.r_symndx] == -1)
+ error ("Oops! possible bug - reloc reference to ignored symbol");
+#ifdef sun386
+ {
+ int offset=0;
+ switch (-symbol_map[coff_reloc.r_symndx])
+ {
+ case N_DATA:
+ offset = coff_data_header.s_vaddr - coff_data_header.s_paddr;
+ break;
+ case N_BSS:
+ offset = coff_bss_header.s_vaddr - coff_bss_header.s_paddr;
+ break;
+ }
+ switch (coff_reloc.r_type)
+ {
+ case R_RELBYTE:
+ *((char *) (text_and_data + coff_reloc.r_vaddr)) -= offset;
+ break;
+ case R_RELWORD:
+ *((short *) (text_and_data + coff_reloc.r_vaddr)) -= offset;
+ break;
+ case R_RELLONG:
+ case R_DIR32:
+ case R_PCRLONG:
+ *((int *) (text_and_data + coff_reloc.r_vaddr)) -= offset;
+ break;
+ default:
+ error ("unknown relocation type 0%o", coff_reloc.r_type);
+ }
+ }
+#endif
+ reloc_infop->r_symbolnum = -symbol_map[coff_reloc.r_symndx];
+ reloc_infop->r_extern = 0;
+ }
+ /* COFF address includes the section address - BSD doesn't, so
+ subtract it out. */
+#ifdef sun386
+ coff_reloc.r_vaddr +=
+ section_headerp->s_vaddr - section_headerp->s_paddr;
+#endif
+ reloc_infop->r_address = coff_reloc.r_vaddr - section_headerp->s_vaddr;
+ switch (coff_reloc.r_type)
+ {
+ case R_PCRLONG:
+ reloc_infop->r_pcrel = 1;
+ reloc_infop->r_length = 2; /* 4 bytes */
+ break;
+ case R_DIR32:
+ case R_RELLONG:
+ reloc_infop->r_pcrel = 0;
+ reloc_infop->r_length = 2;
+ break;
+ default:
+ error ("cannot handle coff reloction type 0%o", coff_reloc.r_type);
+ }
+
+ if (verbose_flag)
+ printf ("reloc: addr = 0x%x, synum = %d\n",
+ reloc_infop->r_address, reloc_infop->r_symbolnum);
+ reloc_infop->r_pad = 0;
+ ++reloc_infop;
+ }
+}
+
+void
+error (format, va_alist)
+ char *format;
+ va_dcl
+{
+ va_list args;
+
+ va_start (args);
+ fprintf (stderr, "%s: ", program_name);
+ vfprintf (stderr, format, args);
+ putc ('\n', stderr);
+ va_end (args);
+ exit (1);
+}
+
+extern char *sys_errlist[];
+extern int errno;
+
+void
+sys_error (format, va_alist)
+ char *format;
+ va_dcl
+{
+ va_list args;
+
+ va_start (args);
+ fprintf (stderr, "%s: ", program_name);
+ vfprintf (stderr, format, args);
+ fprintf (stderr, ": %s\n", sys_errlist[errno]);
+ va_end (args);
+ exit (1);
+}
+
+extern char *malloc ();
+
+char *
+mem_alloc (size)
+ int size;
+{
+ char *pc;
+
+ if ((pc = malloc (size)) == NULL)
+ error ("memory exhausted!");
+ return pc;
+}
diff --git a/binutils-1.9/signame.c b/binutils-1.9/signame.c
new file mode 100644
index 0000000..d62fead
--- /dev/null
+++ b/binutils-1.9/signame.c
@@ -0,0 +1,248 @@
+/* Convert between signal names and numbers.
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <signal.h>
+#include "signame.h"
+
+#ifdef __STDC__
+#define CONST const
+#else
+#define CONST
+#endif
+
+#ifdef SYS_SIGLIST_MISSING
+/* There is too much variation in Sys V signal numbers and names, so
+ we must initialize them at runtime. */
+
+static CONST char undoc[] = "unknown signal";
+
+CONST char *sys_siglist[NSIG];
+#endif /* SYS_SIGLIST_MISSING */
+
+/* Table of abbreviations for signals. Note: A given number can
+ appear more than once with different abbreviations. */
+typedef struct
+ {
+ int number;
+ CONST char *abbrev;
+ } num_abbrev;
+static num_abbrev sig_table[NSIG*2];
+/* Number of elements of sig_table used. */
+static int sig_table_nelts = 0;
+
+/* Enter signal number NUMBER into the tables with ABBREV and NAME. */
+static void
+init_sig (number, abbrev, name)
+ int number;
+ CONST char *abbrev;
+ CONST char *name;
+{
+#ifdef SYS_SIGLIST_MISSING
+ sys_siglist[number] = name;
+#endif
+ sig_table[sig_table_nelts].number = number;
+ sig_table[sig_table_nelts++].abbrev = abbrev;
+}
+
+static void
+init_sigs ()
+{
+#ifdef SYS_SIGLIST_MISSING
+ int i;
+ /* Initialize signal names. */
+ for (i = 0; i < NSIG; i++)
+ sys_siglist[i] = undoc;
+#endif /* SYS_SIGLIST_MISSING */
+
+ /* Initialize signal names. */
+#if defined (SIGHUP)
+ init_sig (SIGHUP, "HUP", "Hangup");
+#endif
+#if defined (SIGINT)
+ init_sig (SIGINT, "INT", "Interrupt");
+#endif
+#if defined (SIGQUIT)
+ init_sig (SIGQUIT, "QUIT", "Quit");
+#endif
+#if defined (SIGILL)
+ init_sig (SIGILL, "ILL", "Illegal Instruction");
+#endif
+#if defined (SIGTRAP)
+ init_sig (SIGTRAP, "TRAP", "Trace/breakpoint trap");
+#endif
+ /* If SIGIOT == SIGABRT, we want to print it as SIGABRT because
+ SIGABRT is in ANSI and POSIX.1 and SIGIOT isn't. */
+#if defined (SIGABRT)
+ init_sig (SIGABRT, "ABRT", "Aborted");
+#endif
+#if defined (SIGIOT)
+ init_sig (SIGIOT, "IOT", "IOT trap");
+#endif
+#if defined (SIGEMT)
+ init_sig (SIGEMT, "EMT", "EMT trap");
+#endif
+#if defined (SIGFPE)
+ init_sig (SIGFPE, "FPE", "Floating point exception");
+#endif
+#if defined (SIGKILL)
+ init_sig (SIGKILL, "KILL", "Killed");
+#endif
+#if defined (SIGBUS)
+ init_sig (SIGBUS, "BUS", "Bus error");
+#endif
+#if defined (SIGSEGV)
+ init_sig (SIGSEGV, "SEGV", "Segmentation fault");
+#endif
+#if defined (SIGSYS)
+ init_sig (SIGSYS, "SYS", "Bad system call");
+#endif
+#if defined (SIGPIPE)
+ init_sig (SIGPIPE, "PIPE", "Broken pipe");
+#endif
+#if defined (SIGALRM)
+ init_sig (SIGALRM, "ALRM", "Alarm clock");
+#endif
+#if defined (SIGTERM)
+ init_sig (SIGTERM, "TERM", "Terminated");
+#endif
+#if defined (SIGUSR1)
+ init_sig (SIGUSR1, "USR1", "User defined signal 1");
+#endif
+#if defined (SIGUSR2)
+ init_sig (SIGUSR2, "USR2", "User defined signal 2");
+#endif
+ /* If SIGCLD == SIGCHLD, we want to print it as SIGCHLD because that
+ is what is in POSIX.1. */
+#if defined (SIGCHLD)
+ init_sig (SIGCHLD, "CHLD", "Child exited");
+#endif
+#if defined (SIGCLD)
+ init_sig (SIGCLD, "CLD", "Child exited");
+#endif
+#if defined (SIGPWR)
+ init_sig (SIGPWR, "PWR", "Power failure");
+#endif
+#if defined (SIGTSTP)
+ init_sig (SIGTSTP, "TSTP", "Stopped");
+#endif
+#if defined (SIGTTIN)
+ init_sig (SIGTTIN, "TTIN", "Stopped (tty input)");
+#endif
+#if defined (SIGTTOU)
+ init_sig (SIGTTOU, "TTOU", "Stopped (tty output)");
+#endif
+#if defined (SIGSTOP)
+ init_sig (SIGSTOP, "STOP", "Stopped (signal)");
+#endif
+#if defined (SIGXCPU)
+ init_sig (SIGXCPU, "XCPU", "CPU time limit exceeded");
+#endif
+#if defined (SIGXFSZ)
+ init_sig (SIGXFSZ, "XFSZ", "File size limit exceeded");
+#endif
+#if defined (SIGVTALRM)
+ init_sig (SIGVTALRM, "VTALRM", "Virtual timer expired");
+#endif
+#if defined (SIGPROF)
+ init_sig (SIGPROF, "PROF", "Profiling timer expired");
+#endif
+#if defined (SIGWINCH)
+ /* "Window size changed" might be more accurate, but even if that
+ is all that it means now, perhaps in the future it will be
+ extended to cover other kinds of window changes. */
+ init_sig (SIGWINCH, "WINCH", "Window changed");
+#endif
+#if defined (SIGCONT)
+ init_sig (SIGCONT, "CONT", "Continued");
+#endif
+#if defined (SIGURG)
+ init_sig (SIGURG, "URG", "Urgent I/O condition");
+#endif
+#if defined (SIGIO)
+ /* "I/O pending" has also been suggested. A disadvantage is
+ that signal only happens when the process has
+ asked for it, not everytime I/O is pending. Another disadvantage
+ is the confusion from giving it a different name than under Unix. */
+ init_sig (SIGIO, "IO", "I/O possible");
+#endif
+#if defined (SIGWIND)
+ init_sig (SIGWIND, "WIND", "SIGWIND");
+#endif
+#if defined (SIGPHONE)
+ init_sig (SIGPHONE, "PHONE", "SIGPHONE");
+#endif
+#if defined (SIGPOLL)
+ init_sig (SIGPOLL, "POLL", "I/O possible");
+#endif
+#if defined (SIGLOST)
+ init_sig (SIGLOST, "LOST", "Resource lost");
+#endif
+}
+
+/* Return the abbreviation for signal NUMBER. */
+char *
+sig_abbrev (number)
+ int number;
+{
+ int i;
+
+ if (sig_table_nelts == 0)
+ init_sigs ();
+
+ for (i = 0; i < sig_table_nelts; i++)
+ if (sig_table[i].number == number)
+ return (char *)sig_table[i].abbrev;
+ return NULL;
+}
+
+/* Return the signal number for an ABBREV, or -1 if there is no
+ signal by that name. */
+int
+sig_number (abbrev)
+ CONST char *abbrev;
+{
+ int i;
+
+ if (sig_table_nelts == 0)
+ init_sigs ();
+
+ /* Skip over "SIG" if present. */
+ if (abbrev[0] == 'S' && abbrev[1] == 'I' && abbrev[2] == 'G')
+ abbrev += 3;
+
+ for (i = 0; i < sig_table_nelts; i++)
+ if (abbrev[0] == sig_table[i].abbrev[0]
+ && strcmp (abbrev, sig_table[i].abbrev) == 0)
+ return sig_table[i].number;
+ return -1;
+}
+
+#if defined (SYS_SIGLIST_MISSING)
+/* Print to standard error the name of SIGNAL, preceded by MESSAGE and
+ a colon, and followed by a newline. */
+void
+psignal (signal, message)
+ int signal;
+ CONST char *message;
+{
+ if (signal <= 0 || signal >= NSIG)
+ fprintf (stderr, "%s: unknown signal", message);
+ else
+ fprintf (stderr, "%s: %s\n", message, sys_siglist[signal]);
+}
+#endif
diff --git a/binutils-1.9/signame.h b/binutils-1.9/signame.h
new file mode 100644
index 0000000..d4dc211
--- /dev/null
+++ b/binutils-1.9/signame.h
@@ -0,0 +1,42 @@
+/* Convert between signal names and numbers.
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef __STDC__
+/* Return the abbreviation (e.g. ABRT, FPE, etc.) for signal NUMBER.
+ Do not return this as a const char *. The caller might want to
+ assign it to a char *. */
+char *sig_abbrev (int number);
+
+/* Return the signal number for an ABBREV, or -1 if there is no
+ signal by that name. */
+int sig_number (const char *abbrev);
+
+/* Print to standard error the name of SIGNAL, preceded by MESSAGE and
+ a colon, and followed by a newline. */
+void psignal (int signal, const char *message);
+
+/* Names for signals from 0 to NSIG-1. */
+extern const char *sys_siglist[];
+
+#else
+
+char *sig_abbrev ();
+int sig_number ();
+void psignal ();
+extern char *sys_siglist[];
+
+#endif
diff --git a/binutils-1.9/size.c b/binutils-1.9/size.c
new file mode 100644
index 0000000..8c000f7
--- /dev/null
+++ b/binutils-1.9/size.c
@@ -0,0 +1,400 @@
+/* Size of rel file utility (`size') for GNU.
+ Copyright (C) 1986 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <ar.h>
+#include <sys/types.h>
+#include <sys/file.h>
+
+#if !defined(A_OUT) && !defined(MACH_O)
+#define A_OUT
+#endif
+
+#ifdef A_OUT
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+/* On native BSD systems, use the system's own a.out.h. */
+#include <a.out.h>
+#endif
+#endif
+
+#ifdef MACH_O
+#include <sys/loader.h>
+#endif
+
+#ifdef USG
+#include <fcntl.h>
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* Number of input file names specified. */
+int number_of_files;
+
+/* Current file's name */
+char *input_name;
+
+/* Current member's name, or 0 if processing a non-library file. */
+char *input_member;
+
+/* Offset within archive of the current member,
+ if we are processing an archive. */
+int member_offset;
+
+/* The name this program was run with. */
+char *program_name;
+
+char *malloc ();
+
+void do_one_file ();
+void do_one_rel_file ();
+void error_with_file ();
+void fatal ();
+void perror_name ();
+void print_file_name ();
+char *xmalloc ();
+char *concat ();
+
+void
+main (argc, argv)
+ char **argv;
+ int argc;
+{
+ int i;
+
+ program_name = argv[0];
+
+ number_of_files = argc - 1;
+
+ printf ("text\tdata\tbss\tdec\thex\n");
+
+ /* Now scan and describe the files. */
+
+ if (number_of_files == 0)
+ do_one_file ("a.out");
+ else
+ for (i = 1; i < argc; i++)
+ do_one_file (argv[i]);
+ exit (0);
+}
+
+/* Print the filename of the current file on 'outfile' (a stdio stream). */
+
+void
+print_file_name (outfile)
+ FILE *outfile;
+{
+ fprintf (outfile, "%s", input_name);
+ if (input_member)
+ fprintf (outfile, "(%s)", input_member);
+}
+
+/* process one input file */
+void scan_library ();
+
+void
+do_one_file (name)
+ char *name;
+{
+ int desc;
+ char armag[SARMAG];
+
+ desc = open (name, O_RDONLY, 0);
+
+ if (desc < 0)
+ {
+ perror_name (name);
+ return;
+ }
+
+ input_name = name;
+ input_member = 0;
+
+ if (SARMAG != read (desc, armag, SARMAG) || strncmp (armag, ARMAG, SARMAG))
+ do_one_rel_file (desc, 0L);
+ else
+ scan_library (desc);
+
+ close (desc);
+}
+
+/* Read in the archive data about one member.
+ SUBFILE_OFFSET is the address within the archive of the start of that data.
+
+ Return the length of the member's contents, which does
+ not include the archive data about the member.
+ If there are no more valid members, return zero. */
+
+int
+decode_library_subfile (desc, subfile_offset)
+ int desc;
+ int subfile_offset;
+{
+ int bytes_read;
+ int namelen;
+ int member_length;
+ char *name;
+ struct ar_hdr hdr1;
+
+ lseek (desc, subfile_offset, 0);
+
+ bytes_read = read (desc, &hdr1, sizeof hdr1);
+ if (!bytes_read)
+ ; /* end of archive */
+
+ else if (sizeof hdr1 != bytes_read)
+ error_with_file ("malformed library archive");
+
+ else if (sscanf (hdr1.ar_size, "%d", &member_length) != 1)
+ error_with_file ("malformatted header of archive member");
+
+ else
+ {
+ for (namelen = 0;
+ hdr1.ar_name[namelen] != 0
+ && hdr1.ar_name[namelen] != ' '
+ && hdr1.ar_name[namelen] != '/';
+ namelen++)
+ ;
+ name = (char *) xmalloc (namelen+1);
+ strncpy (name, hdr1.ar_name, namelen);
+ *(name + namelen) = 0;
+
+ input_member = name;
+
+ return member_length;
+ }
+ return 0; /* tell caller to exit loop */
+}
+
+/* Scan a library and describe each member. */
+
+void
+scan_library (desc)
+ int desc;
+{
+ int this_subfile_offset = SARMAG;
+ int member_length;
+
+ while (member_length = decode_library_subfile (desc, this_subfile_offset))
+ {
+ /* describe every member except the ranlib data if any */
+ if (strcmp (input_member, "__.SYMDEF"))
+ do_one_rel_file (desc, this_subfile_offset + sizeof (struct ar_hdr));
+
+ this_subfile_offset += ((member_length + sizeof (struct ar_hdr)) + 1) & -2;
+ }
+}
+
+/* Read a file's header and fill in various pieces of information.
+ Return 0 on failure, 1 on success. */
+
+int
+read_header_info (desc, offset, tsize, dsize, bsize)
+ int desc;
+ long int offset;
+ unsigned int *tsize;
+ unsigned int *dsize;
+ unsigned int *bsize;
+{
+ int len;
+
+#ifdef A_OUT
+ {
+ struct exec hdr;
+
+ lseek (desc, offset, 0);
+#ifdef HEADER_SEEK_FD
+ /* Skip the headers that encapsulate our data in some other format
+ such as COFF. */
+ HEADER_SEEK_FD (desc);
+#endif
+ len = read (desc, (char *) &hdr, sizeof (struct exec));
+ if (len == sizeof (struct exec) && !N_BADMAG (hdr))
+ {
+ *tsize = hdr.a_text;
+ *dsize = hdr.a_data;
+ *bsize = hdr.a_bss;
+ return 1;
+ }
+ }
+#endif
+
+#ifdef MACH_O
+ {
+ struct mach_header mach_header;
+ char *hdrbuf;
+ struct load_command *load_command;
+ struct segment_command *segment_command;
+ struct section *section;
+ int len, cmd, seg;
+
+ lseek (desc, offset, 0);
+ len = read (desc, (char *) &mach_header, sizeof (struct mach_header));
+ if (len == sizeof (struct mach_header) && mach_header.magic == MH_MAGIC)
+ {
+ hdrbuf = xmalloc (mach_header.sizeofcmds);
+ len = read (desc, hdrbuf, mach_header.sizeofcmds);
+ if (len != mach_header.sizeofcmds)
+ {
+ error_with_file ("failure reading Mach-O load commands");
+ return 0;
+ }
+ load_command = (struct load_command *) hdrbuf;
+ for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
+ {
+ if (load_command->cmd == LC_SEGMENT)
+ {
+ segment_command = (struct segment_command *) load_command;
+ section = (struct section *) ((char *) (segment_command + 1));
+ for (seg = 0; seg < segment_command->nsects; ++seg, ++section)
+ {
+ if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname))
+ *tsize = section->size;
+ else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname))
+ *dsize = section->size;
+ else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname))
+ *bsize = section->size;
+ }
+ }
+ load_command = (struct load_command *)
+ ((char *) load_command + load_command->cmdsize);
+ }
+ free (hdrbuf);
+ return 1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+void
+do_one_rel_file (desc, offset)
+ int desc;
+ long int offset;
+{
+ unsigned int tsize, dsize, bsize, total;
+
+ if (read_header_info (desc, offset, &tsize, &dsize, &bsize))
+ {
+ total = tsize + dsize + bsize;
+ printf ("%u\t%u\t%u\t%u\t%x", tsize, dsize, bsize, total, total);
+ }
+ else
+ {
+ error_with_file ("malformed input file (not rel or archive)");
+ return;
+ }
+
+ if (number_of_files > 1 || input_member)
+ {
+ printf ("\t");
+ print_file_name (stdout);
+ }
+ printf ("\n");
+}
+
+/* Report a fatal error.
+ STRING is a printf format string and ARG is one arg for it. */
+
+void
+fatal (string, arg)
+ char *string, *arg;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Report a nonfatal error.
+ STRING is a printf format string and ARG is one arg for it. */
+
+void
+error (string, arg)
+ char *string, *arg;
+{
+ fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+}
+
+/* Report a nonfatal error.
+ STRING is printed, followed by the current file name. */
+
+void
+error_with_file (string)
+ char *string;
+{
+ fprintf (stderr, "%s: ", program_name);
+ print_file_name (stderr);
+ fprintf (stderr, ": ");
+ fprintf (stderr, string);
+ fprintf (stderr, "\n");
+}
+
+/* Report an error using the message for the last failed system call,
+ followed by the string NAME. */
+
+void
+perror_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat (name, ": ", sys_errlist[errno]);
+ else
+ s = concat (name, ": ", "unknown error");
+ error (s, name);
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+char *
+xmalloc (size)
+ unsigned size;
+{
+ char *result = malloc (size);
+
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+/* Return a newly-allocated string
+ whose contents concatenate those of S1, S2, S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ result[len1 + len2 + len3] = 0;
+
+ return result;
+}
diff --git a/binutils-1.9/stab.def b/binutils-1.9/stab.def
new file mode 100644
index 0000000..b81cda4
--- /dev/null
+++ b/binutils-1.9/stab.def
@@ -0,0 +1,115 @@
+/* Table of DBX symbol codes for the GNU system.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Global variable. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_GSYM, 0x20, "GSYM")
+
+/* Function name for BSD Fortran. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_FNAME, 0x22, "FNAME")
+
+/* Function name or text-segment variable for C. Value is its address.
+ Desc is supposedly starting line number, but GCC doesn't set it
+ and DBX seems not to miss it. */
+__define_stab (N_FUN, 0x24, "FUN")
+
+/* Data-segment variable with internal linkage. Value is its address. */
+__define_stab (N_STSYM, 0x26, "STSYM")
+
+/* BSS-segment variable with internal linkage. Value is its address. */
+__define_stab (N_LCSYM, 0x28, "LCSYM")
+
+/* Name of main routine. Only the name is significant.
+ This is not used in C. */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Register variable. Value is number of register. */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Structure or union element. Value is offset in the structure. */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* Parameter variable. Value is offset from argument pointer.
+ (On most machines the argument pointer is the same as the frame pointer. */
+__define_stab (N_PSYM, 0xa0, "PSYM")
+
+/* Automatic variable in the stack. Value is offset from frame pointer.
+ Also used for type descriptions. */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Alternate entry point. Value is its address. */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Name of main source file.
+ Value is starting text address of the compilation. */
+__define_stab (N_SO, 0x64, "SO")
+
+/* Name of sub-source file.
+ Value is starting text address of the compilation. */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Line number in text segment. Desc is the line number;
+ value is corresponding address. */
+__define_stab (N_SLINE, 0x44, "SLINE")
+/* Similar, for data segment. */
+__define_stab (N_DSLINE, 0x46, "DSLINE")
+/* Similar, for bss segment. */
+__define_stab (N_BSLINE, 0x48, "BSLINE")
+
+/* Beginning of an include file. Only Sun uses this.
+ In an object file, only the name is significant.
+ The Sun linker puts data into some of the other fields. */
+__define_stab (N_BINCL, 0x82, "BINCL")
+/* End of an include file. No name.
+ These two act as brackets around the file's output.
+ In an object file, there is no significant data in this entry.
+ The Sun linker puts data into some of the fields. */
+__define_stab (N_EINCL, 0xa2, "EINCL")
+/* Place holder for deleted include file.
+ This appears only in output from the Sun linker. */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* Beginning of lexical block.
+ The desc is the nesting level in lexical blocks.
+ The value is the address of the start of the text for the block.
+ The variables declared inside the block *precede* the N_LBRAC symbol. */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+/* End of a lexical block. Desc matches the N_LBRAC's desc.
+ The value is the address of the end of the text for the block. */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block. Only the name is significant. */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+/* Begin named common block. Only the name is significant
+ (and it should match the N_BCOMM). */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+/* End common (local name): value is address.
+ I'm not sure how this is used. */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+/* Second symbol entry containing a length-value for the preceding entry.
+ The value is the length. */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* Global symbol in Pascal.
+ Supposedly the value is its line number; I'm skeptical. */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Modula-2 compilation unit. Can someone say what info it contains? */
+__define_stab (N_M2C, 0x42, "M2C")
+/* Modula-2 scope information. Can someone say what info it contains? */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
diff --git a/binutils-1.9/stab.h b/binutils-1.9/stab.h
new file mode 100644
index 0000000..80bd594
--- /dev/null
+++ b/binutils-1.9/stab.h
@@ -0,0 +1,17 @@
+#ifndef __GNU_STAB__
+
+/* Indicate the GNU stab.h is in use. */
+
+#define __GNU_STAB__
+
+#define __define_stab(NAME, CODE, STRING) NAME=CODE,
+
+enum __stab_debug_code
+{
+#include "stab.def"
+LAST_UNUSED_STAB_CODE
+};
+
+#undef __define_stab
+
+#endif /* __GNU_STAB_ */
diff --git a/binutils-1.9/strip.c b/binutils-1.9/strip.c
new file mode 100644
index 0000000..6008382
--- /dev/null
+++ b/binutils-1.9/strip.c
@@ -0,0 +1,915 @@
+/* strip certain symbols from a rel file.
+ Copyright (C) 1986, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <errno.h>
+extern int errno;
+#include "getopt.h"
+
+#ifdef USG
+#include <fcntl.h>
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#if !defined(A_OUT) && !defined(MACH_O)
+#define A_OUT
+#endif
+
+#ifdef A_OUT
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+/* On native BSD systems, use the system's own a.out.h. */
+#include <a.out.h>
+#endif
+#endif
+
+#ifdef MACH_O
+#ifndef A_OUT
+#include <nlist.h>
+#include <reloc.h>
+#endif
+#include <sys/loader.h>
+#endif
+
+#ifdef nounderscore
+#define LPREFIX '.'
+#else
+#define LPREFIX 'L'
+#endif
+
+#if defined (sun) && defined (sparc)
+/* On the sparc, the name of the relocation info structure is
+ different (on SunOS4, "struct relocation_info" does not exist).
+ The meaning of the r_index field is the same as r_symbolnum
+ in normal relocation_info's for external symbols. Fortunately,
+ we only use the field for external symbols. */
+typedef struct reloc_info_sparc *relocation_info_ptr;
+#define RELOCATION_INFO_SYMBOL_NUM(ri) (ri)->r_index
+#else /* not Sun and sparc. */
+typedef struct relocation_info *relocation_info_ptr;
+#define RELOCATION_INFO_SYMBOL_NUM(ri) (ri)->r_symbolnum
+#endif /* not Sun and sparc. */
+
+/* If BSD or HP-UX, we can use `ftruncate' and `rename'. */
+
+#if !defined(USG) || defined(hpux)
+#define HAVE_FTRUNCATE
+#define HAVE_RENAME
+#endif /* !USG || hpux */
+
+/* Number of nlist entries that are for local symbols. */
+int local_sym_count;
+
+/* Number of nlist entries that are for local symbols
+ whose names don't start with L. */
+int non_L_local_sym_count;
+
+/* Number of nlist entries for debugger info. */
+int debugger_sym_count;
+
+/* Number of global symbols referenced or defined. */
+int global_sym_count;
+
+/* Total number of symbols to be preserved in the current file. */
+int nsyms;
+
+/* Number of files specified in the command line. */
+int number_of_files;
+
+/* Kinds of files understood. */
+enum file_type { IS_UNKNOWN, IS_A_OUT, IS_MACH_O };
+
+/* Each specified file has a file_entry structure for it.
+ These are contained in the vector which file_table points to. */
+
+struct file_entry
+{
+ char *filename;
+ enum file_type filetype; /* what kind of file it is */
+
+ /* Things obtained from the file's header. */
+ long int trel_offset; /* offset to text relocation */
+ unsigned int trel_size; /* size of text relocation */
+ long int drel_offset; /* offset to data relocation */
+ unsigned int drel_size; /* size of data relocation */
+ long int syms_offset; /* offset to the symbol table */
+ unsigned int syms_size; /* size of the symbol table */
+ long int strs_offset; /* offset to the string table */
+ unsigned int strs_size; /* size of the string table */
+
+ int ss_size; /* size, in bytes, of symbols_and_strings data */
+ struct nlist *symbols_and_strings;
+
+ /* offset of the symtab_command in a mach-O file's header */
+ long int symtab_cmd_offset;
+};
+
+struct file_entry *file_table;
+
+/* Descriptor on which current file is open. */
+int input_desc;
+
+/* Stream for writing that file using stdio. */
+FILE *outstream;
+
+enum strip_action
+{
+ strip_undef,
+ strip_all, /* strip all symbols */
+ strip_debug /* strip all debugger symbols */
+};
+
+/* Which symbols to remove. */
+enum strip_action strip_symbols;
+
+enum locals_action
+{
+ locals_undef,
+ locals_start_L, /* discard locals starting with L */
+ locals_all /* discard all locals */
+};
+
+/* Which local symbols to remove. */
+enum locals_action discard_locals;
+
+/* The name this program was run with. */
+char *program_name;
+
+char *malloc ();
+
+char *concat ();
+char *xmalloc ();
+int file_open ();
+int read_entry_symbols ();
+int read_file_symbols ();
+int read_header ();
+void count_file_symbols ();
+void error ();
+void file_close ();
+void rewrite_file_symbols ();
+void strip_file ();
+void usage ();
+
+struct option long_options[] =
+{
+ {"strip-all", 0, 0, 's'},
+ {"strip-debug", 0, 0, 'S'},
+ {"discard-all", 0, 0, 'x'},
+ {"discard-locals", 0, 0, 'X'},
+ {0, 0, 0, 0}
+};
+
+void
+main (argc, argv)
+ char **argv;
+ int argc;
+{
+ int c;
+ int ind;
+ int i;
+ struct file_entry *p;
+
+ program_name = argv[0];
+
+ strip_symbols = strip_undef; /* default is to strip everything. */
+ discard_locals = locals_undef;
+
+ while ((c = getopt_long (argc, argv, "gsSxX", long_options, &ind)) != EOF)
+ {
+ switch (c)
+ {
+ case 0 :
+ break;
+ case 's':
+ strip_symbols = strip_all;
+ break;
+ case 'g':
+ case 'S':
+ strip_symbols = strip_debug;
+ break;
+ case 'x':
+ discard_locals = locals_all;
+ break;
+ case 'X':
+ discard_locals = locals_start_L;
+ break;
+ default:
+ usage ();
+ }
+ }
+
+ /* Default is to strip all symbols. */
+ if (strip_symbols == strip_undef && discard_locals == locals_undef)
+ strip_symbols = strip_all;
+
+ number_of_files = argc - optind;
+
+ if (!number_of_files)
+ usage ();
+
+ p = file_table
+ = (struct file_entry *) xmalloc (number_of_files * sizeof (struct file_entry));
+
+ /* Now fill in file_table */
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ p->filename = argv[i + optind];
+ p->filetype = IS_UNKNOWN;
+ p->trel_offset = p->trel_size = p->drel_offset = p->drel_size = 0;
+ p->syms_offset = p->syms_size = p->strs_offset = p->strs_size = 0;
+ p->symbols_and_strings = 0;
+ p->symtab_cmd_offset = 0;
+ p++;
+ }
+
+ for (i = 0; i < number_of_files; i++)
+ strip_file (&file_table[i]);
+ exit (0);
+}
+
+int delayed_signal;
+
+void
+delay_signal (signo)
+ int signo;
+{
+ delayed_signal = signo;
+ signal (signo, delay_signal);
+}
+
+/* process one input file */
+
+void
+strip_file (entry)
+ struct file_entry *entry;
+{
+ int val;
+ int sigint_handled = 0;
+ int sighup_handled = 0;
+ int sigterm_handled = 0;
+
+ local_sym_count = 0;
+ non_L_local_sym_count = 0;
+ debugger_sym_count = 0;
+ global_sym_count = 0;
+
+ val = file_open (entry);
+ if (val < 0)
+ return;
+
+ if (strip_symbols != strip_all)
+ /* Read in the existing symbols unless we are discarding everything. */
+ {
+ if (read_file_symbols (entry) < 0)
+ return;
+ }
+
+ /* Effectively defer handling of asynchronous kill signals. */
+ delayed_signal = 0;
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ sigint_handled = 1, signal (SIGINT, delay_signal);
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ sighup_handled = 1, signal (SIGHUP, delay_signal);
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ sigterm_handled = 1, signal (SIGTERM, delay_signal);
+
+ /* Change the file. */
+
+ rewrite_file_symbols (entry);
+ if (strip_symbols != strip_all)
+ free (entry->symbols_and_strings);
+
+ file_close ();
+
+ /* Effectively undefer handling. */
+ if (sigint_handled)
+ signal (SIGINT, SIG_DFL);
+ if (sighup_handled)
+ signal (SIGHUP, SIG_DFL);
+ if (sigterm_handled)
+ signal (SIGTERM, SIG_DFL);
+
+ /* Handle any signal that came in while they were deferred. */
+ if (delayed_signal)
+ kill (getpid (), delayed_signal);
+}
+
+/** Convenient functions for operating on one or all files being processed. */
+
+/* Close the file that is now open. */
+
+void
+file_close ()
+{
+ if (input_desc != -1)
+ close (input_desc);
+ input_desc = -1;
+}
+
+/* Open the file specified by 'entry', and return a descriptor,
+ or -1 if the file cannot be opened or is not in rel format.
+ The descriptor is also saved in input_desc. */
+
+int
+file_open (entry)
+ struct file_entry *entry;
+{
+ int desc;
+
+ desc = open (entry->filename, O_RDWR, 0);
+
+ if (desc > 0)
+ {
+ input_desc = desc;
+ if (read_header (desc, entry) < 0)
+ {
+ close (desc);
+ return -1;
+ }
+ return desc;
+ }
+
+ error (0, errno, "%s", entry->filename);
+ return -1;
+}
+
+/* Validate file ENTRY and read its symbol and string sections into core.
+ Return 0 if ok, -1 if error. */
+
+int
+read_file_symbols (entry)
+ struct file_entry *entry;
+{
+ if (read_entry_symbols (input_desc, entry) < 0)
+ {
+ file_close ();
+ return -1;
+ }
+ count_file_symbols (entry);
+ return 0;
+}
+
+/* Read a file's header and fill in various fields of a file's entry.
+ Return -1 on failure, 0 if successful. */
+
+int
+read_header (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ int len;
+
+#ifdef A_OUT
+ {
+ struct exec hdr;
+
+ lseek (desc, 0, 0);
+#ifdef HEADER_SEEK_FD
+ /* Skip the headers that encapsulate our data in some other format
+ such as COFF. */
+ HEADER_SEEK_FD (desc);
+#endif
+ len = read (desc, (char *) &hdr, sizeof (struct exec));
+ if (len == sizeof (struct exec) && !N_BADMAG (hdr))
+ {
+ entry->filetype = IS_A_OUT;
+#ifdef N_TRELOFF
+ entry->trel_offset = N_TRELOFF (hdr);
+#else
+#ifdef N_DATOFF
+ entry->trel_offset = N_DATOFF (hdr) + hdr.a_data;
+#else
+ entry->trel_offset = N_TXTOFF (hdr) + hdr.a_text + hdr.a_data;
+#endif
+#endif
+ entry->trel_size = hdr.a_trsize;
+#ifdef N_DRELOFF
+ entry->drel_offset = N_DRELOFF (hdr);
+#else
+ entry->drel_offset = entry->trel_offset + entry->trel_size;
+#endif
+ entry->drel_size = hdr.a_drsize;
+ entry->syms_offset = N_SYMOFF(hdr);
+ entry->syms_size = hdr.a_syms;
+ entry->strs_offset = N_STROFF(hdr);
+ lseek(desc, entry->strs_offset, 0);
+ if (read (desc, (char *) &entry->strs_size, sizeof entry->strs_size)
+ != sizeof entry->strs_size)
+ {
+ error (0, errno, "%s: cannot read string table size",
+ entry->filename);
+ return -1;
+ }
+ return 0;
+ }
+ }
+#endif
+
+#ifdef MACH_O
+ {
+ struct mach_header mach_header;
+ char *hdrbuf;
+ struct load_command *load_command;
+ struct segment_command *segment_command;
+ struct section *section;
+ struct symtab_command *symtab_command;
+ int symtab_seen;
+ int len, cmd, seg;
+
+ symtab_seen = 0;
+
+ lseek (desc, 0L, 0);
+ len = read (desc, (char *) &mach_header, sizeof (struct mach_header));
+ if (len == sizeof (struct mach_header) && mach_header.magic == MH_MAGIC)
+ {
+ entry->filetype = IS_MACH_O;
+ hdrbuf = xmalloc (mach_header.sizeofcmds);
+ len = read (desc, hdrbuf, mach_header.sizeofcmds);
+ if (len != mach_header.sizeofcmds)
+ {
+ error (0, errno, "%s: cannot read Mach-O load commands",
+ entry->filename);
+ return -1;
+ }
+ load_command = (struct load_command *) hdrbuf;
+ for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
+ {
+ switch (load_command->cmd)
+ {
+ case LC_SEGMENT:
+ segment_command = (struct segment_command *) load_command;
+ section = (struct section *) ((char *) (segment_command + 1));
+ for (seg = 0; seg < segment_command->nsects; ++seg, ++section)
+ {
+ if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname))
+ {
+ entry->trel_offset = section->reloff;
+ entry->trel_size = section->nreloc * sizeof (struct relocation_info);
+ }
+ else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname))
+ {
+ entry->drel_offset = section->reloff;
+ entry->drel_size = section->nreloc * sizeof (struct relocation_info);
+ }
+ }
+ break;
+ case LC_SYMTAB:
+ if (symtab_seen)
+ error (0, 0, "%s: more than one LC_SYMTAB", entry->filename);
+ else
+ {
+ symtab_seen = 1;
+ symtab_command = (struct symtab_command *) load_command;
+ entry->syms_offset = symtab_command->symoff;
+ entry->syms_size = symtab_command->nsyms * sizeof (struct nlist);
+ entry->strs_offset = symtab_command->stroff;
+ entry->strs_size = symtab_command->strsize;
+ entry->symtab_cmd_offset = (char *) load_command - hdrbuf
+ + sizeof (struct mach_header);
+ }
+ break;
+ }
+ load_command = (struct load_command *)
+ ((char *) load_command + load_command->cmdsize);
+ }
+
+ free (hdrbuf);
+
+ if (!symtab_seen)
+ {
+ error (0, 0, "%s: no symbol table", entry->filename);
+ return -1;
+ }
+
+ return 0;
+ }
+ }
+#endif
+
+ error (0, 0, "%s: not an executable or object file", entry->filename);
+ return -1;
+}
+
+/* Read the symbols and strings of file ENTRY into core.
+ Assume it is already open, on descriptor DESC.
+ Return -1 on failure, 0 if successful. */
+
+int
+read_entry_symbols (desc, entry)
+ struct file_entry *entry;
+ int desc;
+{
+ entry->ss_size = entry->syms_size + entry->strs_size;
+ entry->symbols_and_strings = (struct nlist *) xmalloc (entry->ss_size);
+
+ lseek (desc, entry->syms_offset, 0);
+ if (entry->ss_size != read (desc, entry->symbols_and_strings, entry->ss_size))
+ {
+ error (0, errno, "%s: premature end of file in symbols/strings",
+ entry->filename);
+ return -1;
+ }
+ return 0;
+}
+
+/* Count the number of symbols of various categories in the file of ENTRY. */
+
+void
+count_file_symbols (entry)
+ struct file_entry *entry;
+{
+ struct nlist *p, *end = entry->symbols_and_strings + entry->syms_size / sizeof (struct nlist);
+ char *name_base = entry->syms_size + (char *) entry->symbols_and_strings;
+
+ for (p = entry->symbols_and_strings; p < end; p++)
+ if (p->n_type & N_EXT)
+ global_sym_count++;
+ else if (p->n_un.n_strx && !(p->n_type & (N_STAB | N_EXT)))
+ {
+ if ((p->n_un.n_strx + name_base)[0] != LPREFIX)
+ non_L_local_sym_count++;
+ local_sym_count++;
+ }
+ else
+ debugger_sym_count++;
+}
+
+void modify_relocation ();
+void write_file_syms ();
+
+/* Total size of string table strings allocated so far */
+int strtab_size;
+
+/* Vector whose elements are the strings to go in the string table */
+char **strtab_vector;
+
+/* Index in strtab_vector at which the next string will be stored */
+int strtab_index;
+
+int sym_written_count;
+
+int
+assign_string_table_index (name)
+ char *name;
+{
+ int index = strtab_size;
+
+ strtab_size += strlen (name) + 1;
+ strtab_vector[strtab_index++] = name;
+
+ return index;
+}
+
+void
+rewrite_file_symbols (entry)
+ struct file_entry *entry;
+{
+ int i;
+ struct nlist *newsyms;
+
+ /* Calculate number of symbols to be preserved. */
+
+ if (strip_symbols == strip_all)
+ nsyms = 0;
+ else
+ {
+ nsyms = global_sym_count;
+ if (discard_locals == locals_start_L)
+ nsyms += non_L_local_sym_count;
+ else if (discard_locals == locals_undef)
+ nsyms += local_sym_count;
+ }
+
+ if (strip_symbols == strip_undef)
+ nsyms += debugger_sym_count;
+
+ strtab_vector = (char **) xmalloc (nsyms * sizeof (char *));
+ strtab_index = 0;
+
+ strtab_size = 4;
+
+ /* Accumulate in 'newsyms' the symbol table to be written. */
+
+ newsyms = (struct nlist *) xmalloc (nsyms * sizeof (struct nlist));
+
+ sym_written_count = 0;
+
+ if (strip_symbols != strip_all)
+ /* Write into newsyms the symbols we want to keep. */
+ write_file_syms (entry, newsyms);
+
+ if (sym_written_count != nsyms)
+ {
+ fprintf (stderr, "written = %d, expected = %d\n",
+ sym_written_count, nsyms);
+ abort ();
+ }
+
+ /* Modify the symbol-numbers in the relocation in the file,
+ to preserve its meaning */
+ modify_relocation (input_desc, entry);
+
+#ifndef HAVE_FTRUNCATE
+ {
+ int size = entry->syms_offset, mode;
+ int old_desc;
+ char *renamed;
+ char *copy_buffer = (char *)xmalloc (size);
+ struct stat statbuf;
+
+ renamed = (char *) xmalloc(strlen(entry->filename) + 3);
+ strcpy(renamed, entry->filename);
+ {
+ char *file_p, *renamed_p;
+ file_p = strrchr(entry->filename, '/');
+ file_p = file_p ? ++file_p : entry->filename;
+ renamed_p = renamed + (file_p - entry->filename);
+ *renamed_p++ = '~';
+ while (*renamed_p++ = *file_p++)
+ ;
+ *renamed_p++ = '~';
+ *renamed_p = '\0';
+ }
+
+ lseek (input_desc, 0, 0);
+ if (read (input_desc, copy_buffer, size) != size)
+ {
+ error (0, errno, "%s: cannot read up to symbol table",
+ entry->filename);
+ return;
+ }
+ mode = fstat (input_desc, &statbuf) ? 0666 : statbuf.st_mode;
+ if (rename (entry->filename, renamed))
+ {
+ error (0, errno, "%s", entry->filename);
+ return;
+ }
+ old_desc = input_desc;
+ input_desc = open (entry->filename, O_RDWR | O_CREAT | O_TRUNC, mode);
+ if (input_desc < 0)
+ {
+ error (0, errno, "%s", entry->filename);
+ return;
+ }
+ if (write (input_desc, copy_buffer, size) != size)
+ error (0, errno, "%s", entry->filename);
+ if (unlink (renamed))
+ error (0, errno, "%s", renamed);
+ if (close (old_desc))
+ error (0, errno, "%s", renamed);
+ free (copy_buffer);
+ free (renamed);
+ }
+#endif /* not HAVE_FTRUNCATE */
+
+ /* Now write contents of NEWSYMS into the file. */
+
+ lseek (input_desc, entry->syms_offset, 0);
+ write (input_desc, newsyms, nsyms * sizeof (struct nlist));
+ free (newsyms);
+
+ /* Now write the string table. */
+
+ {
+ char *strvec = (char *) xmalloc (strtab_size);
+ char *p;
+
+ *((long *) strvec) = strtab_size;
+
+ p = strvec + sizeof (long);
+
+ for (i = 0; i < strtab_index; i++)
+ {
+ int len = strlen (strtab_vector[i]);
+ strcpy (p, strtab_vector[i]);
+ *(p+len) = 0;
+ p += len + 1;
+ }
+
+ write (input_desc, strvec, strtab_size);
+ free (strvec);
+ }
+
+ /* Adjust file to be smaller */
+
+#ifdef HAVE_FTRUNCATE
+ if (ftruncate (input_desc, lseek (input_desc, 0L, 1)) < 0)
+ error (0, errno, "%s", entry->filename);
+#endif
+
+ /* Write new symbol table size into file header. */
+
+#ifdef A_OUT
+ if (entry->filetype == IS_A_OUT)
+ {
+ struct exec hdr;
+
+ lseek (input_desc, 0L, 0);
+#ifdef HEADER_SEEK_FD
+ HEADER_SEEK_FD (input_desc);
+#endif
+ read (input_desc, (char *) &hdr, sizeof hdr);
+ hdr.a_syms = nsyms * sizeof (struct nlist);
+ lseek (input_desc, -(long) sizeof hdr, 1);
+ write (input_desc, (char *) &hdr, sizeof hdr);
+ }
+#endif
+
+#ifdef MACH_O
+ if (entry->filetype == IS_MACH_O)
+ {
+ struct symtab_command cmd;
+
+ lseek (input_desc, entry->symtab_cmd_offset, 0);
+ read (input_desc, (char *) &cmd, sizeof cmd);
+ cmd.nsyms = nsyms;
+ cmd.stroff = cmd.symoff + cmd.nsyms * sizeof (struct nlist);
+ cmd.strsize = strtab_size;
+ lseek (input_desc, entry->symtab_cmd_offset, 0);
+ write (input_desc, (char *) &cmd, sizeof cmd);
+ }
+#endif
+
+ free (strtab_vector);
+}
+
+/* Copy into NEWSYMS the symbol entries to be preserved.
+ Count them in sym_written_count.
+
+ We record, for each symbol written, its symbol number in the resulting file.
+ This is so that the relocation can be updated later.
+ Since the symbol names will not be needed again,
+ this index goes in the `n_strx' field.
+ If a symbol is not written, -1 is stored there. */
+
+void
+write_file_syms (entry, newsyms)
+ struct file_entry *entry;
+ struct nlist *newsyms;
+{
+ struct nlist *p = entry->symbols_and_strings;
+ struct nlist *end = p + entry->syms_size / sizeof (struct nlist);
+ char *string_base = (char *) end; /* address of start of file's string table */
+ struct nlist *outp = newsyms;
+
+ for (; p < end; p++)
+ {
+ int write;
+
+ if (p->n_type & N_EXT)
+ write = 1;
+ else if (p->n_un.n_strx && !(p->n_type & (N_STAB | N_EXT)))
+ /* ordinary local symbol */
+ write = (discard_locals != locals_all)
+ && !(discard_locals == locals_start_L &&
+ (p->n_un.n_strx + string_base)[0] == LPREFIX);
+ else
+ /* debugger symbol */
+ write = (strip_symbols == strip_undef);
+
+ if (write)
+ {
+ if (p->n_un.n_strx)
+ p->n_un.n_strx = assign_string_table_index (p->n_un.n_strx + string_base);
+
+ *outp++ = *p;
+
+ p->n_un.n_strx = sym_written_count++;
+ }
+ else p->n_un.n_strx = -1;
+ }
+}
+
+/* Read in ENTRY's relocation, alter the symbolnums in it,
+ and write it out again. */
+
+void
+modify_relocation (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ relocation_info_ptr reloc, p, end;
+ int size;
+ struct nlist *sym_base = (struct nlist *) entry->symbols_and_strings;
+ int losing = 0;
+ long int offsets[2];
+ unsigned int sizes[2];
+ int i;
+
+ offsets[0] = entry->trel_offset;
+ sizes[0] = entry->trel_size;
+ offsets[1] = entry->drel_offset;
+ sizes[1] = entry->drel_size;
+
+ for (i = 0; i < 2; ++i)
+ {
+ size = sizes[i];
+ reloc = (relocation_info_ptr) xmalloc (size);
+ lseek (desc, offsets[i], 0);
+ read (desc, reloc, size);
+
+ p = reloc;
+ end = (relocation_info_ptr) (size + (char *) reloc);
+ while (p < end)
+ {
+ if (p->r_extern)
+ {
+ int newnum = (sym_base == 0 ? -1
+ :((sym_base + RELOCATION_INFO_SYMBOL_NUM(p))
+ -> n_un.n_strx));
+ if (newnum < 0)
+ {
+ if (losing == 0)
+ error (0, 0, "%s: warning: file is now unlinkable",
+ entry->filename);
+ losing = 1;
+ }
+ RELOCATION_INFO_SYMBOL_NUM(p) = newnum;
+ }
+ p++;
+ }
+
+ lseek (desc, offsets[i], 0);
+ write (desc, reloc, size);
+ free ((char *) reloc);
+ }
+}
+
+/* Return a newly-allocated string whose contents
+ concatenate those of S1, S2, S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ *(result + len1 + len2 + len3) = 0;
+
+ return result;
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+char *
+xmalloc (size)
+ unsigned size;
+{
+ /* Some implementations of malloc get unhappy if size==0.
+ * Given that the code sometimes "wants" a 0-length array,
+ * it seems cleaner to put a work-around here
+ * than clutter up the code logic in various other places. */
+ char *result = malloc (size==0 ? 1 : size);
+
+ if (!result)
+ error (1, 0, "virtual memory exhausted");
+ return result;
+}
+
+#ifndef HAVE_RENAME
+int
+rename (from, to)
+ char *from, *to;
+{
+ unlink (to);
+ if (link (from, to) < 0 || unlink (from) < 0)
+ return -1;
+ else
+ return 0;
+}
+#endif
+
+void
+usage ()
+{
+ fprintf (stderr, "\
+Usage: %s [-gsxSX] [+strip-all] [+strip-debug] [+discard-all]\n\
+ [+discard-locals] file...\n", program_name);
+ exit (1);
+}
diff --git a/binutils-1.9/symseg.h b/binutils-1.9/symseg.h
new file mode 100644
index 0000000..43a8123
--- /dev/null
+++ b/binutils-1.9/symseg.h
@@ -0,0 +1,511 @@
+/* GDB symbol table format definitions.
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+ Hacked by Michael Tiemann (tiemann@mcc.com)
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Format of GDB symbol table data.
+ There is one symbol segment for each source file or
+ independant compilation. These segments are simply concatenated
+ to form the GDB symbol table. A zero word where the beginning
+ of a segment is expected indicates there are no more segments.
+
+Format of a symbol segment:
+
+ The symbol segment begins with a word containing 1
+ if it is in the format described here. Other formats may
+ be designed, with other code numbers.
+
+ The segment contains many objects which point at each other.
+ The pointers are offsets in bytes from the beginning of the segment.
+ Thus, each segment can be loaded into core and its pointers relocated
+ to make valid in-core pointers.
+
+ All the data objects in the segment can be found indirectly from
+ one of them, the root object, of type `struct symbol_root'.
+ It appears at the beginning of the segment.
+
+ The total size of the segment, in bytes, appears as the `length'
+ field of this object. This size includes the size of the
+ root object.
+
+ All the object data types are defined here to contain pointer types
+ appropriate for in-core use on a relocated symbol segment.
+ Casts to and from type int are required for working with
+ unrelocated symbol segments such as are found in the file.
+
+ The ldsymaddr word is filled in by the loader to contain
+ the offset (in bytes) within the ld symbol table
+ of the first nonglobal symbol from this compilation.
+ This makes it possible to match those symbols
+ (which contain line number information) reliably with
+ the segment they go with.
+
+ Core addresses within the program that appear in the symbol segment
+ are not relocated by the loader. They are inserted by the assembler
+ and apply to addresses as output by the assembler, so GDB must
+ relocate them when it loads the symbol segment. It gets the information
+ on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg
+ words of the root object.
+
+ The words textrel, datarel and bssrel
+ are filled in by ld with the amounts to relocate within-the-file
+ text, data and bss addresses by; databeg and bssbeg can be
+ used to tell which kind of relocation an address needs. */
+
+enum language {language_c};
+
+struct symbol_root
+{
+ int format; /* Data format version */
+ int length; /* # bytes in this symbol segment */
+ int ldsymoff; /* Offset in ld symtab of this file's syms */
+ int textrel; /* Relocation for text addresses */
+ int datarel; /* Relocation for data addresses */
+ int bssrel; /* Relocation for bss addresses */
+ char *filename; /* Name of main source file compiled */
+ char *filedir; /* Name of directory it was reached from */
+ struct blockvector *blockvector; /* Vector of all symbol-naming blocks */
+ struct typevector *typevector; /* Vector of all data types */
+ enum language language; /* Code identifying the language used */
+ char *version; /* Version info. Not fully specified */
+ char *compilation; /* Compilation info. Not fully specified */
+ int databeg; /* Address within the file of data start */
+ int bssbeg; /* Address within the file of bss start */
+ struct sourcevector *sourcevector; /* Vector of line-number info */
+};
+
+/* All data types of symbols in the compiled program
+ are represented by `struct type' objects.
+ All of these objects are pointed to by the typevector.
+ The type vector may have empty slots that contain zero. */
+
+struct typevector
+{
+ int length; /* Number of types described */
+ struct type *type[1];
+};
+
+/* Different kinds of data types are distinguished by the `code' field. */
+
+enum type_code
+{
+ TYPE_CODE_UNDEF, /* Not used; catches errors */
+ TYPE_CODE_PTR, /* Pointer type */
+ TYPE_CODE_ARRAY, /* Array type, lower bound zero */
+ TYPE_CODE_STRUCT, /* C struct or Pascal record */
+ TYPE_CODE_UNION, /* C union or Pascal variant part */
+ TYPE_CODE_ENUM, /* Enumeration type */
+ TYPE_CODE_FUNC, /* Function type */
+ TYPE_CODE_INT, /* Integer type */
+ TYPE_CODE_FLT, /* Floating type */
+ TYPE_CODE_VOID, /* Void type (values zero length) */
+ TYPE_CODE_SET, /* Pascal sets */
+ TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
+ TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */
+
+ /* C++ */
+ TYPE_CODE_MEMBER, /* Member type */
+ TYPE_CODE_METHOD, /* Method type */
+ TYPE_CODE_REF, /* C++ Reference types */
+};
+
+/* This appears in a type's flags word for an unsigned integer type. */
+#define TYPE_FLAG_UNSIGNED 1
+/* This appears in a type's flags word
+ if it is a (pointer to a|function returning a)* built in scalar type.
+ These types are never freed. */
+#define TYPE_FLAG_PERM 4
+/* This appears in a type's flags word if it is a stub type (eg. if
+ someone referenced a type that wasn't definined in a source file
+ via (struct sir_not_appearing_in_this_film *)). */
+#define TYPE_FLAG_STUB 8
+/* Set when a class has a constructor defined */
+#define TYPE_FLAG_HAS_CONSTRUCTOR 256
+/* Set when a class has a destructor defined */
+#define TYPE_FLAG_HAS_DESTRUCTOR 512
+/* Indicates that this type is a public baseclass of another class,
+ i.e. that all its public methods are available in the derived
+ class. */
+#define TYPE_FLAG_VIA_PUBLIC 1024
+/* Indicates that this type is a virtual baseclass of another class,
+ i.e. that if this class is inherited more than once by another
+ class, only one set of member variables will be included. */
+#define TYPE_FLAG_VIA_VIRTUAL 2048
+
+struct type
+{
+ /* Code for kind of type */
+ enum type_code code;
+ /* Name of this type, or zero if none.
+ This is used for printing only.
+ Type names specified as input are defined by symbols. */
+ char *name;
+ /* Length in bytes of storage for a value of this type */
+ int length;
+ /* For a pointer type, describes the type of object pointed to.
+ For an array type, describes the type of the elements.
+ For a function or method type, describes the type of the value.
+ For a range type, describes the type of the full range.
+ Unused otherwise. */
+ struct type *target_type;
+ /* Type that is a pointer to this type.
+ Zero if no such pointer-to type is known yet.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+ struct type *pointer_type;
+ /* C++: also need a reference type. */
+ struct type *reference_type;
+ struct type **arg_types;
+
+ /* Type that is a function returning this type.
+ Zero if no such function type is known here.
+ The debugger may add the address of such a type
+ if it has to construct one later. */
+ struct type *function_type;
+
+/* Handling of pointers to members:
+ TYPE_MAIN_VARIANT is used for pointer and pointer
+ to member types. Normally it the value of the address of its
+ containing type. However, for pointers to members, we must be
+ able to allocate pointer to member types and look them up
+ from some place of reference.
+ NEXT_VARIANT is the next element in the chain. */
+ struct type *main_variant, *next_variant;
+
+ /* Flags about this type. */
+ short flags;
+ /* Number of fields described for this type */
+ short nfields;
+ /* For structure and union types, a description of each field.
+ For set and pascal array types, there is one "field",
+ whose type is the domain type of the set or array.
+ For range types, there are two "fields",
+ the minimum and maximum values (both inclusive).
+ For enum types, each possible value is described by one "field".
+
+ Using a pointer to a separate array of fields
+ allows all types to have the same size, which is useful
+ because we can allocate the space for a type before
+ we know what to put in it. */
+ struct field
+ {
+ /* Position of this field, counting in bits from start of
+ containing structure. For a function type, this is the
+ position in the argument list of this argument.
+ For a range bound or enum value, this is the value itself. */
+ int bitpos;
+ /* Size of this field, in bits, or zero if not packed.
+ For an unpacked field, the field's type's length
+ says how many bytes the field occupies. */
+ int bitsize;
+ /* In a struct or enum type, type of this field.
+ In a function type, type of this argument.
+ In an array type, the domain-type of the array. */
+ struct type *type;
+ /* Name of field, value or argument.
+ Zero for range bounds and array domains. */
+ char *name;
+ } *fields;
+
+ /* C++ */
+ int *private_field_bits;
+ int *protected_field_bits;
+
+ /* Number of methods described for this type */
+ short nfn_fields;
+ /* Number of base classes this type derives from. */
+ short n_baseclasses;
+
+ /* Number of methods described for this type plus all the
+ methods that it derives from. */
+ int nfn_fields_total;
+
+ /* For classes, structures, and unions, a description of each field,
+ which consists of an overloaded name, followed by the types of
+ arguments that the method expects, and then the name after it
+ has been renamed to make it distinct. */
+ struct fn_fieldlist
+ {
+ /* The overloaded name. */
+ char *name;
+ /* The number of methods with this name. */
+ int length;
+ /* The list of methods. */
+ struct fn_field
+ {
+#if 0
+ /* The overloaded name */
+ char *name;
+#endif
+ /* The return value of the method */
+ struct type *type;
+ /* The argument list */
+ struct type **args;
+ /* The name after it has been processed */
+ char *physname;
+ /* If this is a virtual function, the offset into the vtbl-1,
+ else 0. */
+ int voffset;
+ } *fn_fields;
+
+ int *private_fn_field_bits;
+ int *protected_fn_field_bits;
+
+ } *fn_fieldlists;
+
+ unsigned char via_protected;
+ unsigned char via_public;
+
+ /* For types with virtual functions, VPTR_BASETYPE is the base class which
+ defined the virtual function table pointer. VPTR_FIELDNO is
+ the field number of that pointer in the structure.
+
+ For types that are pointer to member types, VPTR_BASETYPE
+ ifs the type that this pointer is a member of.
+
+ Unused otherwise. */
+ struct type *vptr_basetype;
+
+ int vptr_fieldno;
+
+ /* If this type has a base class, put it here.
+ If this type is a pointer type, the chain of member pointer
+ types goes here.
+ Unused otherwise.
+
+ Contrary to all maxims of C style and common sense, the baseclasses
+ are indexed from 1 to N_BASECLASSES rather than 0 to N_BASECLASSES-1
+ (i.e. BASECLASSES points to one *before* the first element of
+ the array). */
+ struct type **baseclasses;
+};
+
+/* All of the name-scope contours of the program
+ are represented by `struct block' objects.
+ All of these objects are pointed to by the blockvector.
+
+ Each block represents one name scope.
+ Each lexical context has its own block.
+
+ The first two blocks in the blockvector are special.
+ The first one contains all the symbols defined in this compilation
+ whose scope is the entire program linked together.
+ The second one contains all the symbols whose scope is the
+ entire compilation excluding other separate compilations.
+ In C, these correspond to global symbols and static symbols.
+
+ Each block records a range of core addresses for the code that
+ is in the scope of the block. The first two special blocks
+ give, for the range of code, the entire range of code produced
+ by the compilation that the symbol segment belongs to.
+
+ The blocks appear in the blockvector
+ in order of increasing starting-address,
+ and, within that, in order of decreasing ending-address.
+
+ This implies that within the body of one function
+ the blocks appear in the order of a depth-first tree walk. */
+
+struct blockvector
+{
+ /* Number of blocks in the list. */
+ int nblocks;
+ /* The blocks themselves. */
+ struct block *block[1];
+};
+
+struct block
+{
+ /* Addresses in the executable code that are in this block.
+ Note: in an unrelocated symbol segment in a file,
+ these are always zero. They can be filled in from the
+ N_LBRAC and N_RBRAC symbols in the loader symbol table. */
+ int startaddr, endaddr;
+ /* The symbol that names this block,
+ if the block is the body of a function;
+ otherwise, zero.
+ Note: In an unrelocated symbol segment in an object file,
+ this field may be zero even when the block has a name.
+ That is because the block is output before the name
+ (since the name resides in a higher block).
+ Since the symbol does point to the block (as its value),
+ it is possible to find the block and set its name properly. */
+ struct symbol *function;
+ /* The `struct block' for the containing block, or 0 if none. */
+ /* Note that in an unrelocated symbol segment in an object file
+ this pointer may be zero when the correct value should be
+ the second special block (for symbols whose scope is one compilation).
+ This is because the compiler ouptuts the special blocks at the
+ very end, after the other blocks. */
+ struct block *superblock;
+ /* A flag indicating whether or not the fucntion corresponding
+ to this block was compiled with gcc or not. If there is no
+ function corresponding to this block, this meaning of this flag
+ is undefined. (In practice it will be 1 if the block was created
+ while processing a file compiled with gcc and 0 when not). */
+ unsigned char gcc_compile_flag;
+ /* Number of local symbols. */
+ int nsyms;
+ /* The symbols. */
+ struct symbol *sym[1];
+};
+
+/* Represent one symbol name; a variable, constant, function or typedef. */
+
+/* Different name spaces for symbols. Looking up a symbol specifies
+ a namespace and ignores symbol definitions in other name spaces.
+
+ VAR_NAMESPACE is the usual namespace.
+ In C, this contains variables, function names, typedef names
+ and enum type values.
+
+ STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
+ Thus, if `struct foo' is used in a C program,
+ it produces a symbol named `foo' in the STRUCT_NAMESPACE.
+
+ LABEL_NAMESPACE may be used for names of labels (for gotos);
+ currently it is not used and labels are not recorded at all. */
+
+/* For a non-global symbol allocated statically,
+ the correct core address cannot be determined by the compiler.
+ The compiler puts an index number into the symbol's value field.
+ This index number can be matched with the "desc" field of
+ an entry in the loader symbol table. */
+
+enum namespace
+{
+ UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE,
+};
+
+/* An address-class says where to find the value of the symbol in core. */
+
+enum address_class
+{
+ LOC_UNDEF, /* Not used; catches errors */
+ LOC_CONST, /* Value is constant int */
+ LOC_STATIC, /* Value is at fixed address */
+ LOC_REGISTER, /* Value is in register */
+ LOC_ARG, /* Value is at spec'd position in arglist */
+ LOC_REF_ARG, /* Value address is at spec'd position in */
+ /* arglist. */
+ LOC_REGPARM, /* Value is at spec'd position in register window */
+ LOC_LOCAL, /* Value is at spec'd pos in stack frame */
+ LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE
+ Symbols in the namespace STRUCT_NAMESPACE
+ all have this class. */
+ LOC_LABEL, /* Value is address in the code */
+ LOC_BLOCK, /* Value is address of a `struct block'.
+ Function names have this class. */
+ LOC_EXTERNAL, /* Value is at address not in this compilation.
+ This is used for .comm symbols
+ and for extern symbols within functions.
+ Inside GDB, this is changed to LOC_STATIC once the
+ real address is obtained from a loader symbol. */
+ LOC_CONST_BYTES /* Value is a constant byte-sequence. */
+};
+
+struct symbol
+{
+ /* Symbol name */
+ char *name;
+ /* Name space code. */
+ enum namespace namespace;
+ /* Address class */
+ enum address_class class;
+ /* Data type of value */
+ struct type *type;
+ /* constant value, or address if static, or register number,
+ or offset in arguments, or offset in stack frame. */
+ union
+ {
+ long value;
+ struct block *block; /* for LOC_BLOCK */
+ char *bytes; /* for LOC_CONST_BYTES */
+ }
+ value;
+};
+
+struct partial_symbol
+{
+ /* Symbol name */
+ char *name;
+ /* Name space code. */
+ enum namespace namespace;
+ /* Address class (for info_symbols) */
+ enum address_class class;
+ /* Value (only used for static functions currently). Done this
+ way so that we can use the struct symbol macros.
+ Note that the address of a function is SYMBOL_VALUE (pst)
+ in a partial symbol table, but BLOCK_START (SYMBOL_BLOCK_VALUE (st))
+ in a symbol table. */
+ union
+ {
+ long value;
+ }
+ value;
+};
+
+/*
+ * Vectors of all partial symbols read in from file; actually declared
+ * and used in dbxread.c.
+ */
+extern struct psymbol_allocation_list {
+ struct partial_symbol *list, *next;
+ int size;
+} global_psymbols, static_psymbols;
+
+
+/* Source-file information.
+ This describes the relation between source files and line numbers
+ and addresses in the program text. */
+
+struct sourcevector
+{
+ int length; /* Number of source files described */
+ struct source *source[1]; /* Descriptions of the files */
+};
+
+/* Each item represents a line-->pc (or the reverse) mapping. This is
+ somewhat more wasteful of space than one might wish, but since only
+ the files which are actually debugged are read in to core, we don't
+ waste much space.
+
+ Each item used to be an int; either minus a line number, or a
+ program counter. If it represents a line number, that is the line
+ described by the next program counter value. If it is positive, it
+ is the program counter at which the code for the next line starts. */
+
+struct linetable_entry
+{
+ int line;
+ CORE_ADDR pc;
+};
+
+struct linetable
+{
+ int nitems;
+ struct linetable_entry item[1];
+};
+
+/* All the information on one source file. */
+
+struct source
+{
+ char *name; /* Name of file */
+ struct linetable contents;
+};
diff --git a/linux-0.01.tar.gz b/linux-0.01.tar.gz
new file mode 100644
index 0000000..ed6029b
--- /dev/null
+++ b/linux-0.01.tar.gz
Binary files differ
diff --git a/linux/Makefile b/linux/Makefile
new file mode 100644
index 0000000..d9d9fab
--- /dev/null
+++ b/linux/Makefile
@@ -0,0 +1,96 @@
+#
+# Makefile for linux.
+# If you don't have '-mstring-insns' in your gcc (and nobody but me has :-)
+# remove them from the CFLAGS defines.
+#
+
+AS86 =as -0 -a
+CC86 =cc -0
+LD86 =ld -0
+
+AS =gas
+LD =gld
+LDFLAGS =-s -x -M
+CC =gcc
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs
+CPP =gcc -E -nostdinc -Iinclude
+
+ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o
+LIBS =lib/lib.a
+
+.c.s:
+ $(CC) $(CFLAGS) \
+ -nostdinc -Iinclude -S -o $*.s $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) \
+ -nostdinc -Iinclude -c -o $*.o $<
+
+all: Image
+
+Image: boot/boot tools/system tools/build
+ tools/build boot/boot tools/system > Image
+ sync
+
+tools/build: tools/build.c
+ $(CC) $(CFLAGS) \
+ -o tools/build tools/build.c
+ chmem +65000 tools/build
+
+boot/head.o: boot/head.s
+
+tools/system: boot/head.o init/main.o \
+ $(ARCHIVES) $(LIBS)
+ $(LD) $(LDFLAGS) boot/head.o init/main.o \
+ $(ARCHIVES) \
+ $(LIBS) \
+ -o tools/system > System.map
+
+kernel/kernel.o:
+ (cd kernel; make)
+
+mm/mm.o:
+ (cd mm; make)
+
+fs/fs.o:
+ (cd fs; make)
+
+lib/lib.a:
+ (cd lib; make)
+
+boot/boot: boot/boot.s tools/system
+ (echo -n "SYSSIZE = (";ls -l tools/system | grep system \
+ | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
+ cat boot/boot.s >> tmp.s
+ $(AS86) -o boot/boot.o tmp.s
+ rm -f tmp.s
+ $(LD86) -s -o boot/boot boot/boot.o
+
+clean:
+ rm -f Image System.map tmp_make boot/boot core
+ rm -f init/*.o boot/*.o tools/system tools/build
+ (cd mm;make clean)
+ (cd fs;make clean)
+ (cd kernel;make clean)
+ (cd lib;make clean)
+
+backup: clean
+ (cd .. ; tar cf - linux | compress16 - > backup.Z)
+ sync
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+ (cd fs; make dep)
+ (cd kernel; make dep)
+ (cd mm; make dep)
+
+### Dependencies:
+init/main.o : init/main.c include/unistd.h include/sys/stat.h \
+ include/sys/types.h include/sys/times.h include/sys/utsname.h \
+ include/utime.h include/time.h include/linux/tty.h include/termios.h \
+ include/linux/sched.h include/linux/head.h include/linux/fs.h \
+ include/linux/mm.h include/asm/system.h include/asm/io.h include/stddef.h \
+ include/stdarg.h include/fcntl.h
diff --git a/linux/boot/boot.s b/linux/boot/boot.s
new file mode 100644
index 0000000..e19bbd2
--- /dev/null
+++ b/linux/boot/boot.s
@@ -0,0 +1,329 @@
+|
+| boot.s
+|
+| boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself
+| out of the way to address 0x90000, and jumps there.
+|
+| It then loads the system at 0x10000, using BIOS interrupts. Thereafter
+| it disables all interrupts, moves the system down to 0x0000, changes
+| to protected mode, and calls the start of system. System then must
+| RE-initialize the protected mode in it's own tables, and enable
+| interrupts as needed.
+|
+| NOTE! currently system is at most 8*65536 bytes long. This should be no
+| problem, even in the future. I want to keep it simple. This 512 kB
+| kernel size should be enough - in fact more would mean we'd have to move
+| not just these start-up routines, but also do something about the cache-
+| memory (block IO devices). The area left over in the lower 640 kB is meant
+| for these. No other memory is assumed to be "physical", ie all memory
+| over 1Mb is demand-paging. All addresses under 1Mb are guaranteed to match
+| their physical addresses.
+|
+| NOTE1 abouve is no longer valid in it's entirety. cache-memory is allocated
+| above the 1Mb mark as well as below. Otherwise it is mainly correct.
+|
+| NOTE 2! The boot disk type must be set at compile-time, by setting
+| the following equ. Having the boot-up procedure hunt for the right
+| disk type is severe brain-damage.
+| The loader has been made as simple as possible (had to, to get it
+| in 512 bytes with the code to move to protected mode), and continuos
+| read errors will result in a unbreakable loop. Reboot by hand. It
+| loads pretty fast by getting whole sectors at a time whenever possible.
+
+| 1.44Mb disks:
+sectors = 18
+| 1.2Mb disks:
+| sectors = 15
+| 720kB disks:
+| sectors = 9
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+BOOTSEG = 0x07c0
+INITSEG = 0x9000
+SYSSEG = 0x1000 | system loaded at 0x10000 (65536).
+ENDSEG = SYSSEG + SYSSIZE
+
+entry start
+start:
+ mov ax,#BOOTSEG
+ mov ds,ax
+ mov ax,#INITSEG
+ mov es,ax
+ mov cx,#256
+ sub si,si
+ sub di,di
+ rep
+ movw
+ jmpi go,INITSEG
+go: mov ax,cs
+ mov ds,ax
+ mov es,ax
+ mov ss,ax
+ mov sp,#0x400 | arbitrary value >>512
+
+ mov ah,#0x03 | read cursor pos
+ xor bh,bh
+ int 0x10
+
+ mov cx,#24
+ mov bx,#0x0007 | page 0, attribute 7 (normal)
+ mov bp,#msg1
+ mov ax,#0x1301 | write string, move cursor
+ int 0x10
+
+| ok, we've written the message, now
+| we want to load the system (at 0x10000)
+
+ mov ax,#SYSSEG
+ mov es,ax | segment of 0x010000
+ call read_it
+ call kill_motor
+
+| if the read went well we get current cursor position ans save it for
+| posterity.
+
+ mov ah,#0x03 | read cursor pos
+ xor bh,bh
+ int 0x10 | save it in known place, con_init fetches
+ mov [510],dx | it from 0x90510.
+
+| now we want to move to protected mode ...
+
+ cli | no interrupts allowed !
+
+| first we move the system to it's rightful place
+
+ mov ax,#0x0000
+ cld | 'direction'=0, movs moves forward
+do_move:
+ mov es,ax | destination segment
+ add ax,#0x1000
+ cmp ax,#0x9000
+ jz end_move
+ mov ds,ax | source segment
+ sub di,di
+ sub si,si
+ mov cx,#0x8000
+ rep
+ movsw
+ j do_move
+
+| then we load the segment descriptors
+
+end_move:
+
+ mov ax,cs | right, forgot this at first. didn't work :-)
+ mov ds,ax
+ lidt idt_48 | load idt with 0,0
+ lgdt gdt_48 | load gdt with whatever appropriate
+
+| that was painless, now we enable A20
+
+ call empty_8042
+ mov al,#0xD1 | command write
+ out #0x64,al
+ call empty_8042
+ mov al,#0xDF | A20 on
+ out #0x60,al
+ call empty_8042
+
+| well, that went ok, I hope. Now we have to reprogram the interrupts :-(
+| we put them right after the intel-reserved hardware interrupts, at
+| int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
+| messed this up with the original PC, and they haven't been able to
+| rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
+| which is used for the internal hardware interrupts as well. We just
+| have to reprogram the 8259's, and it isn't fun.
+
+ mov al,#0x11 | initialization sequence
+ out #0x20,al | send it to 8259A-1
+ .word 0x00eb,0x00eb | jmp $+2, jmp $+2
+ out #0xA0,al | and to 8259A-2
+ .word 0x00eb,0x00eb
+ mov al,#0x20 | start of hardware int's (0x20)
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ mov al,#0x28 | start of hardware int's 2 (0x28)
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0x04 | 8259-1 is master
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ mov al,#0x02 | 8259-2 is slave
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0x01 | 8086 mode for both
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0xFF | mask off all interrupts for now
+ out #0x21,al
+ .word 0x00eb,0x00eb
+ out #0xA1,al
+
+| well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+| need no steenking BIOS anyway (except for the initial loading :-).
+| The BIOS-routine wants lots of unnecessary data, and it's less
+| "interesting" anyway. This is how REAL programmers do it.
+|
+| Well, now's the time to actually move into protected mode. To make
+| things as simple as possible, we do no register set-up or anything,
+| we let the gnu-compiled 32-bit programs do that. We just jump to
+| absolute address 0x00000, in 32-bit protected mode.
+
+ mov ax,#0x0001 | protected mode (PE) bit
+ lmsw ax | This is it!
+ jmpi 0,8 | jmp offset 0 of segment 8 (cs)
+
+| This routine checks that the keyboard command queue is empty
+| No timeout is used - if this hangs there is something wrong with
+| the machine, and we probably couldn't proceed anyway.
+empty_8042:
+ .word 0x00eb,0x00eb
+ in al,#0x64 | 8042 status port
+ test al,#2 | is input buffer full?
+ jnz empty_8042 | yes - loop
+ ret
+
+| This routine loads the system at address 0x10000, making sure
+| no 64kB boundaries are crossed. We try to load it as fast as
+| possible, loading whole tracks whenever we can.
+|
+| in: es - starting address segment (normally 0x1000)
+|
+| This routine has to be recompiled to fit another drive type,
+| just change the "sectors" variable at the start of the file
+| (originally 18, for a 1.44Mb drive)
+|
+sread: .word 1 | sectors read of current track
+head: .word 0 | current head
+track: .word 0 | current track
+read_it:
+ mov ax,es
+ test ax,#0x0fff
+die: jne die | es must be at 64kB boundary
+ xor bx,bx | bx is starting address within segment
+rp_read:
+ mov ax,es
+ cmp ax,#ENDSEG | have we loaded all yet?
+ jb ok1_read
+ ret
+ok1_read:
+ mov ax,#sectors
+ sub ax,sread
+ mov cx,ax
+ shl cx,#9
+ add cx,bx
+ jnc ok2_read
+ je ok2_read
+ xor ax,ax
+ sub ax,bx
+ shr ax,#9
+ok2_read:
+ call read_track
+ mov cx,ax
+ add ax,sread
+ cmp ax,#sectors
+ jne ok3_read
+ mov ax,#1
+ sub ax,head
+ jne ok4_read
+ inc track
+ok4_read:
+ mov head,ax
+ xor ax,ax
+ok3_read:
+ mov sread,ax
+ shl cx,#9
+ add bx,cx
+ jnc rp_read
+ mov ax,es
+ add ax,#0x1000
+ mov es,ax
+ xor bx,bx
+ jmp rp_read
+
+read_track:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx,track
+ mov cx,sread
+ inc cx
+ mov ch,dl
+ mov dx,head
+ mov dh,dl
+ mov dl,#0
+ and dx,#0x0100
+ mov ah,#2
+ int 0x13
+ jc bad_rt
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+bad_rt: mov ax,#0
+ mov dx,#0
+ int 0x13
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ jmp read_track
+
+/*
+ * This procedure turns off the floppy drive motor, so
+ * that we enter the kernel in a known state, and
+ * don't have to worry about it later.
+ */
+kill_motor:
+ push dx
+ mov dx,#0x3f2
+ mov al,#0
+ outb
+ pop dx
+ ret
+
+gdt:
+ .word 0,0,0,0 | dummy
+
+ .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 | base address=0
+ .word 0x9A00 | code read/exec
+ .word 0x00C0 | granularity=4096, 386
+
+ .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 | base address=0
+ .word 0x9200 | data read/write
+ .word 0x00C0 | granularity=4096, 386
+
+idt_48:
+ .word 0 | idt limit=0
+ .word 0,0 | idt base=0L
+
+gdt_48:
+ .word 0x800 | gdt limit=2048, 256 GDT entries
+ .word gdt,0x9 | gdt base = 0X9xxxx
+
+msg1:
+ .byte 13,10
+ .ascii "Loading system ..."
+ .byte 13,10,13,10
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
diff --git a/linux/boot/head.s b/linux/boot/head.s
new file mode 100644
index 0000000..c008ba8
--- /dev/null
+++ b/linux/boot/head.s
@@ -0,0 +1,175 @@
+/*
+ * head.s contains the 32-bit startup code.
+ *
+ * NOTE!!! Startup happens at absolute address 0x00000000, which is also where
+ * the page directory will exist. The startup code will be overwritten by
+ * the page directory.
+ */
+.text
+.globl _idt,_gdt,_pg_dir
+_pg_dir:
+startup_32:
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ mov %ax,%gs
+ lss _stack_start,%esp
+ call setup_idt
+ call setup_gdt
+ movl $0x10,%eax # reload all the segment registers
+ mov %ax,%ds # after changing gdt. CS was already
+ mov %ax,%es # reloaded in 'setup_gdt'
+ mov %ax,%fs
+ mov %ax,%gs
+ lss _stack_start,%esp
+ xorl %eax,%eax
+1: incl %eax # check that A20 really IS enabled
+ movl %eax,0x000000
+ cmpl %eax,0x100000
+ je 1b
+ movl %cr0,%eax # check math chip
+ andl $0x80000011,%eax # Save PG,ET,PE
+ testl $0x10,%eax
+ jne 1f # ET is set - 387 is present
+ orl $4,%eax # else set emulate bit
+1: movl %eax,%cr0
+ jmp after_page_tables
+
+/*
+ * setup_idt
+ *
+ * sets up a idt with 256 entries pointing to
+ * ignore_int, interrupt gates. It then loads
+ * idt. Everything that wants to install itself
+ * in the idt-table may do so themselves. Interrupts
+ * are enabled elsewhere, when we can be relatively
+ * sure everything is ok. This routine will be over-
+ * written by the page tables.
+ */
+setup_idt:
+ lea ignore_int,%edx
+ movl $0x00080000,%eax
+ movw %dx,%ax /* selector = 0x0008 = cs */
+ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
+
+ lea _idt,%edi
+ mov $256,%ecx
+rp_sidt:
+ movl %eax,(%edi)
+ movl %edx,4(%edi)
+ addl $8,%edi
+ dec %ecx
+ jne rp_sidt
+ lidt idt_descr
+ ret
+
+/*
+ * setup_gdt
+ *
+ * This routines sets up a new gdt and loads it.
+ * Only two entries are currently built, the same
+ * ones that were built in init.s. The routine
+ * is VERY complicated at two whole lines, so this
+ * rather long comment is certainly needed :-).
+ * This routine will beoverwritten by the page tables.
+ */
+setup_gdt:
+ lgdt gdt_descr
+ ret
+
+.org 0x1000
+pg0:
+
+.org 0x2000
+pg1:
+
+.org 0x3000
+pg2: # This is not used yet, but if you
+ # want to expand past 8 Mb, you'll have
+ # to use it.
+
+.org 0x4000
+after_page_tables:
+ pushl $0 # These are the parameters to main :-)
+ pushl $0
+ pushl $0
+ pushl $L6 # return address for main, if it decides to.
+ pushl $_main
+ jmp setup_paging
+L6:
+ jmp L6 # main should never return here, but
+ # just in case, we know what happens.
+
+/* This is the default interrupt "handler" :-) */
+.align 2
+ignore_int:
+ incb 0xb8000+160 # put something on the screen
+ movb $2,0xb8000+161 # so that we know something
+ iret # happened
+
+
+/*
+ * Setup_paging
+ *
+ * This routine sets up paging by setting the page bit
+ * in cr0. The page tables are set up, identity-mapping
+ * the first 8MB. The pager assumes that no illegal
+ * addresses are produced (ie >4Mb on a 4Mb machine).
+ *
+ * NOTE! Although all physical memory should be identity
+ * mapped by this routine, only the kernel page functions
+ * use the >1Mb addresses directly. All "normal" functions
+ * use just the lower 1Mb, or the local data space, which
+ * will be mapped to some other place - mm keeps track of
+ * that.
+ *
+ * For those with more memory than 8 Mb - tough luck. I've
+ * not got it, why should you :-) The source is here. Change
+ * it. (Seriously - it shouldn't be too difficult. Mostly
+ * change some constants etc. I left it at 8Mb, as my machine
+ * even cannot be extended past that (ok, but it was cheap :-)
+ * I've tried to show which constants to change by having
+ * some kind of marker at them (search for "8Mb"), but I
+ * won't guarantee that's all :-( )
+ */
+.align 2
+setup_paging:
+ movl $1024*3,%ecx
+ xorl %eax,%eax
+ xorl %edi,%edi /* pg_dir is at 0x000 */
+ cld;rep;stosl
+ movl $pg0+7,_pg_dir /* set present bit/user r/w */
+ movl $pg1+7,_pg_dir+4 /* --------- " " --------- */
+ movl $pg1+4092,%edi
+ movl $0x7ff007,%eax /* 8Mb - 4096 + 7 (r/w user,p) */
+ std
+1: stosl /* fill pages backwards - more efficient :-) */
+ subl $0x1000,%eax
+ jge 1b
+ xorl %eax,%eax /* pg_dir is at 0x0000 */
+ movl %eax,%cr3 /* cr3 - page directory start */
+ movl %cr0,%eax
+ orl $0x80000000,%eax
+ movl %eax,%cr0 /* set paging (PG) bit */
+ ret /* this also flushes prefetch-queue */
+
+.align 2
+.word 0
+idt_descr:
+ .word 256*8-1 # idt contains 256 entries
+ .long _idt
+.align 2
+.word 0
+gdt_descr:
+ .word 256*8-1 # so does gdt (not that that's any
+ .long _gdt # magic number, but it works for me :^)
+
+ .align 3
+_idt: .fill 256,8,0 # idt is uninitialized
+
+_gdt: .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00c09a00000007ff /* 8Mb */
+ .quad 0x00c09200000007ff /* 8Mb */
+ .quad 0x0000000000000000 /* TEMPORARY - don't use */
+ .fill 252,8,0 /* space for LDT's and TSS's etc */
diff --git a/linux/fs/Makefile b/linux/fs/Makefile
new file mode 100644
index 0000000..24e7e4c
--- /dev/null
+++ b/linux/fs/Makefile
@@ -0,0 +1,95 @@
+AR =gar
+AS =gas
+CC =gcc
+LD =gld
+CFLAGS =-Wall -O -fstrength-reduce -fcombine-regs -fomit-frame-pointer \
+ -mstring-insns -nostdinc -I../include
+CPP =gcc -E -nostdinc -I../include
+
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+.c.o:
+ $(CC) $(CFLAGS) \
+ -c -o $*.o $<
+.s.o:
+ $(AS) -o $*.o $<
+
+OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
+ block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \
+ bitmap.o fcntl.o ioctl.o tty_ioctl.o truncate.o
+
+fs.o: $(OBJS)
+ $(LD) -r -o fs.o $(OBJS)
+
+clean:
+ rm -f core *.o *.a tmp_make
+ for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
+bitmap.o : bitmap.c ../include/string.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h
+block_dev.o : block_dev.c ../include/errno.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/linux/kernel.h ../include/asm/segment.h
+buffer.o : buffer.c ../include/linux/config.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
+char_dev.o : char_dev.c ../include/errno.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h
+exec.o : exec.c ../include/errno.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/a.out.h ../include/linux/fs.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/asm/segment.h
+fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
+ ../include/asm/segment.h ../include/fcntl.h ../include/sys/stat.h
+file_dev.o : file_dev.c ../include/errno.h ../include/fcntl.h \
+ ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/linux/mm.h ../include/linux/kernel.h \
+ ../include/asm/segment.h
+file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h
+inode.o : inode.c ../include/string.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h
+ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
+ ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h
+namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/asm/segment.h ../include/string.h \
+ ../include/fcntl.h ../include/errno.h ../include/const.h \
+ ../include/sys/stat.h
+open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
+ ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/linux/mm.h ../include/linux/tty.h ../include/termios.h \
+ ../include/linux/kernel.h ../include/asm/segment.h
+pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/linux/mm.h ../include/asm/segment.h
+read_write.o : read_write.c ../include/sys/stat.h ../include/sys/types.h \
+ ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
+ ../include/asm/segment.h
+stat.o : stat.c ../include/errno.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h \
+ ../include/asm/segment.h
+super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h
+truncate.o : truncate.c ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
+ ../include/sys/stat.h
+tty_ioctl.o : tty_ioctl.c ../include/errno.h ../include/termios.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/linux/mm.h ../include/linux/kernel.h \
+ ../include/linux/tty.h ../include/asm/segment.h ../include/asm/system.h
diff --git a/linux/fs/bitmap.c b/linux/fs/bitmap.c
new file mode 100644
index 0000000..49bb81b
--- /dev/null
+++ b/linux/fs/bitmap.c
@@ -0,0 +1,158 @@
+/* bitmap.c contains the code that handles the inode and block bitmaps */
+#include <string.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#define clear_block(addr) \
+__asm__("cld\n\t" \
+ "rep\n\t" \
+ "stosl" \
+ ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
+
+#define set_bit(nr,addr) ({\
+register int res __asm__("ax"); \
+__asm__("btsl %2,%3\n\tsetb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
+res;})
+
+#define clear_bit(nr,addr) ({\
+register int res __asm__("ax"); \
+__asm__("btrl %2,%3\n\tsetnb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
+res;})
+
+#define find_first_zero(addr) ({ \
+int __res; \
+__asm__("cld\n" \
+ "1:\tlodsl\n\t" \
+ "notl %%eax\n\t" \
+ "bsfl %%eax,%%edx\n\t" \
+ "je 2f\n\t" \
+ "addl %%edx,%%ecx\n\t" \
+ "jmp 3f\n" \
+ "2:\taddl $32,%%ecx\n\t" \
+ "cmpl $8192,%%ecx\n\t" \
+ "jl 1b\n" \
+ "3:" \
+ :"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
+__res;})
+
+void free_block(int dev, int block)
+{
+ struct super_block * sb;
+ struct buffer_head * bh;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to free block on nonexistent device");
+ if (block < sb->s_firstdatazone || block >= sb->s_nzones)
+ panic("trying to free block not in datazone");
+ bh = get_hash_table(dev,block);
+ if (bh) {
+ if (bh->b_count != 1) {
+ printk("trying to free block (%04x:%d), count=%d\n",
+ dev,block,bh->b_count);
+ return;
+ }
+ bh->b_dirt=0;
+ bh->b_uptodate=0;
+ brelse(bh);
+ }
+ block -= sb->s_firstdatazone - 1 ;
+ if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
+ printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
+ panic("free_block: bit already cleared");
+ }
+ sb->s_zmap[block/8192]->b_dirt = 1;
+}
+
+int new_block(int dev)
+{
+ struct buffer_head * bh;
+ struct super_block * sb;
+ int i,j;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to get new block from nonexistant device");
+ j = 8192;
+ for (i=0 ; i<8 ; i++)
+ if (bh=sb->s_zmap[i])
+ if ((j=find_first_zero(bh->b_data))<8192)
+ break;
+ if (i>=8 || !bh || j>=8192)
+ return 0;
+ if (set_bit(j,bh->b_data))
+ panic("new_block: bit already set");
+ bh->b_dirt = 1;
+ j += i*8192 + sb->s_firstdatazone-1;
+ if (j >= sb->s_nzones)
+ return 0;
+ if (!(bh=getblk(dev,j)))
+ panic("new_block: cannot get block");
+ if (bh->b_count != 1)
+ panic("new block: count is != 1");
+ clear_block(bh->b_data);
+ bh->b_uptodate = 1;
+ bh->b_dirt = 1;
+ brelse(bh);
+ return j;
+}
+
+void free_inode(struct m_inode * inode)
+{
+ struct super_block * sb;
+ struct buffer_head * bh;
+
+ if (!inode)
+ return;
+ if (!inode->i_dev) {
+ memset(inode,0,sizeof(*inode));
+ return;
+ }
+ if (inode->i_count>1) {
+ printk("trying to free inode with count=%d\n",inode->i_count);
+ panic("free_inode");
+ }
+ if (inode->i_nlinks)
+ panic("trying to free inode with links");
+ if (!(sb = get_super(inode->i_dev)))
+ panic("trying to free inode on nonexistent device");
+ if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)
+ panic("trying to free inode 0 or nonexistant inode");
+ if (!(bh=sb->s_imap[inode->i_num>>13]))
+ panic("nonexistent imap in superblock");
+ if (clear_bit(inode->i_num&8191,bh->b_data))
+ panic("free_inode: bit already cleared");
+ bh->b_dirt = 1;
+ memset(inode,0,sizeof(*inode));
+}
+
+struct m_inode * new_inode(int dev)
+{
+ struct m_inode * inode;
+ struct super_block * sb;
+ struct buffer_head * bh;
+ int i,j;
+
+ if (!(inode=get_empty_inode()))
+ return NULL;
+ if (!(sb = get_super(dev)))
+ panic("new_inode with unknown device");
+ j = 8192;
+ for (i=0 ; i<8 ; i++)
+ if (bh=sb->s_imap[i])
+ if ((j=find_first_zero(bh->b_data))<8192)
+ break;
+ if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) {
+ iput(inode);
+ return NULL;
+ }
+ if (set_bit(j,bh->b_data))
+ panic("new_inode: bit already set");
+ bh->b_dirt = 1;
+ inode->i_count=1;
+ inode->i_nlinks=1;
+ inode->i_dev=dev;
+ inode->i_dirt=1;
+ inode->i_num = j + i*8192;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ return inode;
+}
diff --git a/linux/fs/block_dev.c b/linux/fs/block_dev.c
new file mode 100644
index 0000000..7bbae6a
--- /dev/null
+++ b/linux/fs/block_dev.c
@@ -0,0 +1,86 @@
+#include <errno.h>
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#define NR_BLK_DEV ((sizeof (rd_blk))/(sizeof (rd_blk[0])))
+
+int block_write(int dev, long * pos, char * buf, int count)
+{
+ int block = *pos / BLOCK_SIZE;
+ int offset = *pos % BLOCK_SIZE;
+ int chars;
+ int written = 0;
+ struct buffer_head * bh;
+ register char * p;
+
+ while (count>0) {
+ bh = bread(dev,block);
+ if (!bh)
+ return written?written:-EIO;
+ chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
+ p = offset + bh->b_data;
+ offset = 0;
+ block++;
+ *pos += chars;
+ written += chars;
+ count -= chars;
+ while (chars-->0)
+ *(p++) = get_fs_byte(buf++);
+ bh->b_dirt = 1;
+ brelse(bh);
+ }
+ return written;
+}
+
+int block_read(int dev, unsigned long * pos, char * buf, int count)
+{
+ int block = *pos / BLOCK_SIZE;
+ int offset = *pos % BLOCK_SIZE;
+ int chars;
+ int read = 0;
+ struct buffer_head * bh;
+ register char * p;
+
+ while (count>0) {
+ bh = bread(dev,block);
+ if (!bh)
+ return read?read:-EIO;
+ chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
+ p = offset + bh->b_data;
+ offset = 0;
+ block++;
+ *pos += chars;
+ read += chars;
+ count -= chars;
+ while (chars-->0)
+ put_fs_byte(*(p++),buf++);
+ bh->b_dirt = 1;
+ brelse(bh);
+ }
+ return read;
+}
+
+extern void rw_hd(int rw, struct buffer_head * bh);
+
+typedef void (*blk_fn)(int rw, struct buffer_head * bh);
+
+static blk_fn rd_blk[]={
+ NULL, /* nodev */
+ NULL, /* dev mem */
+ NULL, /* dev fd */
+ rw_hd, /* dev hd */
+ NULL, /* dev ttyx */
+ NULL, /* dev tty */
+ NULL}; /* dev lp */
+
+void ll_rw_block(int rw, struct buffer_head * bh)
+{
+ blk_fn blk_addr;
+ unsigned int major;
+
+ if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_addr=rd_blk[major]))
+ panic("Trying to read nonexistent block-device");
+ blk_addr(rw, bh);
+}
diff --git a/linux/fs/buffer.c b/linux/fs/buffer.c
new file mode 100644
index 0000000..312ab17
--- /dev/null
+++ b/linux/fs/buffer.c
@@ -0,0 +1,254 @@
+/*
+ * 'buffer.c' implements the buffer-cache functions. Race-conditions have
+ * been avoided by NEVER letting a interrupt change a buffer (except for the
+ * data, of course), but instead letting the caller do it. NOTE! As interrupts
+ * can wake up a caller, some cli-sti sequences are needed to check for
+ * sleep-on-calls. These should be extremely quick, though (I hope).
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+#if (BUFFER_END & 0xfff)
+#error "Bad BUFFER_END value"
+#endif
+
+#if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
+#error "Bad BUFFER_END value"
+#endif
+
+extern int end;
+struct buffer_head * start_buffer = (struct buffer_head *) &end;
+struct buffer_head * hash_table[NR_HASH];
+static struct buffer_head * free_list;
+static struct task_struct * buffer_wait = NULL;
+int NR_BUFFERS = 0;
+
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+ cli();
+ while (bh->b_lock)
+ sleep_on(&bh->b_wait);
+ sti();
+}
+
+int sys_sync(void)
+{
+ int i;
+ struct buffer_head * bh;
+
+ sync_inodes(); /* write out inodes into buffers */
+ bh = start_buffer;
+ for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
+ wait_on_buffer(bh);
+ if (bh->b_dirt)
+ ll_rw_block(WRITE,bh);
+ }
+ return 0;
+}
+
+static int sync_dev(int dev)
+{
+ int i;
+ struct buffer_head * bh;
+
+ bh = start_buffer;
+ for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
+ if (bh->b_dev != dev)
+ continue;
+ wait_on_buffer(bh);
+ if (bh->b_dirt)
+ ll_rw_block(WRITE,bh);
+ }
+ return 0;
+}
+
+#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
+#define hash(dev,block) hash_table[_hashfn(dev,block)]
+
+static inline void remove_from_queues(struct buffer_head * bh)
+{
+/* remove from hash-queue */
+ if (bh->b_next)
+ bh->b_next->b_prev = bh->b_prev;
+ if (bh->b_prev)
+ bh->b_prev->b_next = bh->b_next;
+ if (hash(bh->b_dev,bh->b_blocknr) == bh)
+ hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
+/* remove from free list */
+ if (!(bh->b_prev_free) || !(bh->b_next_free))
+ panic("Free block list corrupted");
+ bh->b_prev_free->b_next_free = bh->b_next_free;
+ bh->b_next_free->b_prev_free = bh->b_prev_free;
+ if (free_list == bh)
+ free_list = bh->b_next_free;
+}
+
+static inline void insert_into_queues(struct buffer_head * bh)
+{
+/* put at end of free list */
+ bh->b_next_free = free_list;
+ bh->b_prev_free = free_list->b_prev_free;
+ free_list->b_prev_free->b_next_free = bh;
+ free_list->b_prev_free = bh;
+/* put the buffer in new hash-queue if it has a device */
+ bh->b_prev = NULL;
+ bh->b_next = NULL;
+ if (!bh->b_dev)
+ return;
+ bh->b_next = hash(bh->b_dev,bh->b_blocknr);
+ hash(bh->b_dev,bh->b_blocknr) = bh;
+ bh->b_next->b_prev = bh;
+}
+
+static struct buffer_head * find_buffer(int dev, int block)
+{
+ struct buffer_head * tmp;
+
+ for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
+ if (tmp->b_dev==dev && tmp->b_blocknr==block)
+ return tmp;
+ return NULL;
+}
+
+/*
+ * Why like this, I hear you say... The reason is race-conditions.
+ * As we don't lock buffers (unless we are readint them, that is),
+ * something might happen to it while we sleep (ie a read-error
+ * will force it bad). This shouldn't really happen currently, but
+ * the code is ready.
+ */
+struct buffer_head * get_hash_table(int dev, int block)
+{
+ struct buffer_head * bh;
+
+repeat:
+ if (!(bh=find_buffer(dev,block)))
+ return NULL;
+ bh->b_count++;
+ wait_on_buffer(bh);
+ if (bh->b_dev != dev || bh->b_blocknr != block) {
+ brelse(bh);
+ goto repeat;
+ }
+ return bh;
+}
+
+/*
+ * Ok, this is getblk, and it isn't very clear, again to hinder
+ * race-conditions. Most of the code is seldom used, (ie repeating),
+ * so it should be much more efficient than it looks.
+ */
+struct buffer_head * getblk(int dev,int block)
+{
+ struct buffer_head * tmp;
+
+repeat:
+ if (tmp=get_hash_table(dev,block))
+ return tmp;
+ tmp = free_list;
+ do {
+ if (!tmp->b_count) {
+ wait_on_buffer(tmp); /* we still have to wait */
+ if (!tmp->b_count) /* on it, it might be dirty */
+ break;
+ }
+ tmp = tmp->b_next_free;
+ } while (tmp != free_list || (tmp=NULL));
+ /* Kids, don't try THIS at home ^^^^^. Magic */
+ if (!tmp) {
+ printk("Sleeping on free buffer ..");
+ sleep_on(&buffer_wait);
+ printk("ok\n");
+ goto repeat;
+ }
+ tmp->b_count++;
+ remove_from_queues(tmp);
+/*
+ * Now, when we know nobody can get to this node (as it's removed from the
+ * free list), we write it out. We can sleep here without fear of race-
+ * conditions.
+ */
+ if (tmp->b_dirt)
+ sync_dev(tmp->b_dev);
+/* update buffer contents */
+ tmp->b_dev=dev;
+ tmp->b_blocknr=block;
+ tmp->b_dirt=0;
+ tmp->b_uptodate=0;
+/* NOTE!! While we possibly slept in sync_dev(), somebody else might have
+ * added "this" block already, so check for that. Thank God for goto's.
+ */
+ if (find_buffer(dev,block)) {
+ tmp->b_dev=0; /* ok, someone else has beaten us */
+ tmp->b_blocknr=0; /* to it - free this block and */
+ tmp->b_count=0; /* try again */
+ insert_into_queues(tmp);
+ goto repeat;
+ }
+/* and then insert into correct position */
+ insert_into_queues(tmp);
+ return tmp;
+}
+
+void brelse(struct buffer_head * buf)
+{
+ if (!buf)
+ return;
+ wait_on_buffer(buf);
+ if (!(buf->b_count--))
+ panic("Trying to free free buffer");
+ wake_up(&buffer_wait);
+}
+
+/*
+ * bread() reads a specified block and returns the buffer that contains
+ * it. It returns NULL if the block was unreadable.
+ */
+struct buffer_head * bread(int dev,int block)
+{
+ struct buffer_head * bh;
+
+ if (!(bh=getblk(dev,block)))
+ panic("bread: getblk returned NULL\n");
+ if (bh->b_uptodate)
+ return bh;
+ ll_rw_block(READ,bh);
+ if (bh->b_uptodate)
+ return bh;
+ brelse(bh);
+ return (NULL);
+}
+
+void buffer_init(void)
+{
+ struct buffer_head * h = start_buffer;
+ void * b = (void *) BUFFER_END;
+ int i;
+
+ while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
+ h->b_dev = 0;
+ h->b_dirt = 0;
+ h->b_count = 0;
+ h->b_lock = 0;
+ h->b_uptodate = 0;
+ h->b_wait = NULL;
+ h->b_next = NULL;
+ h->b_prev = NULL;
+ h->b_data = (char *) b;
+ h->b_prev_free = h-1;
+ h->b_next_free = h+1;
+ h++;
+ NR_BUFFERS++;
+ if (b == (void *) 0x100000)
+ b = (void *) 0xA0000;
+ }
+ h--;
+ free_list = start_buffer;
+ free_list->b_prev_free = h;
+ h->b_next_free = free_list;
+ for (i=0;i<NR_HASH;i++)
+ hash_table[i]=NULL;
+}
diff --git a/linux/fs/char_dev.c b/linux/fs/char_dev.c
new file mode 100644
index 0000000..e974242
--- /dev/null
+++ b/linux/fs/char_dev.c
@@ -0,0 +1,50 @@
+#include <errno.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+extern int tty_read(unsigned minor,char * buf,int count);
+extern int tty_write(unsigned minor,char * buf,int count);
+
+static int rw_ttyx(int rw,unsigned minor,char * buf,int count);
+static int rw_tty(int rw,unsigned minor,char * buf,int count);
+
+typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count);
+
+#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
+
+static crw_ptr crw_table[]={
+ NULL, /* nodev */
+ NULL, /* /dev/mem */
+ NULL, /* /dev/fd */
+ NULL, /* /dev/hd */
+ rw_ttyx, /* /dev/ttyx */
+ rw_tty, /* /dev/tty */
+ NULL, /* /dev/lp */
+ NULL}; /* unnamed pipes */
+
+static int rw_ttyx(int rw,unsigned minor,char * buf,int count)
+{
+ return ((rw==READ)?tty_read(minor,buf,count):
+ tty_write(minor,buf,count));
+}
+
+static int rw_tty(int rw,unsigned minor,char * buf,int count)
+{
+ if (current->tty<0)
+ return -EPERM;
+ return rw_ttyx(rw,current->tty,buf,count);
+}
+
+int rw_char(int rw,int dev, char * buf, int count)
+{
+ crw_ptr call_addr;
+
+ if (MAJOR(dev)>=NRDEVS)
+ panic("rw_char: dev>NRDEV");
+ if (!(call_addr=crw_table[MAJOR(dev)])) {
+ printk("dev: %04x\n",dev);
+ panic("Trying to r/w from/to nonexistent character device");
+ }
+ return call_addr(rw,MINOR(dev),buf,count);
+}
diff --git a/linux/fs/exec.c b/linux/fs/exec.c
new file mode 100644
index 0000000..e9d5058
--- /dev/null
+++ b/linux/fs/exec.c
@@ -0,0 +1,306 @@
+#include <errno.h>
+#include <sys/stat.h>
+#include <a.out.h>
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+
+extern int sys_exit(int exit_code);
+extern int sys_close(int fd);
+
+/*
+ * MAX_ARG_PAGES defines the number of pages allocated for arguments
+ * and envelope for the new program. 32 should suffice, this gives
+ * a maximum env+arg of 128kB !
+ */
+#define MAX_ARG_PAGES 32
+
+#define cp_block(from,to) \
+__asm__("pushl $0x10\n\t" \
+ "pushl $0x17\n\t" \
+ "pop %%es\n\t" \
+ "cld\n\t" \
+ "rep\n\t" \
+ "movsl\n\t" \
+ "pop %%es" \
+ ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
+ :"cx","di","si")
+
+/*
+ * read_head() reads blocks 1-6 (not 0). Block 0 has already been
+ * read for header information.
+ */
+int read_head(struct m_inode * inode,int blocks)
+{
+ struct buffer_head * bh;
+ int count;
+
+ if (blocks>6)
+ blocks=6;
+ for(count = 0 ; count<blocks ; count++) {
+ if (!inode->i_zone[count+1])
+ continue;
+ if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
+ return -1;
+ cp_block(bh->b_data,count*BLOCK_SIZE);
+ brelse(bh);
+ }
+ return 0;
+}
+
+int read_ind(int dev,int ind,long size,unsigned long offset)
+{
+ struct buffer_head * ih, * bh;
+ unsigned short * table,block;
+
+ if (size<=0)
+ panic("size<=0 in read_ind");
+ if (size>512*BLOCK_SIZE)
+ size=512*BLOCK_SIZE;
+ if (!ind)
+ return 0;
+ if (!(ih=bread(dev,ind)))
+ return -1;
+ table = (unsigned short *) ih->b_data;
+ while (size>0) {
+ if (block=*(table++))
+ if (!(bh=bread(dev,block))) {
+ brelse(ih);
+ return -1;
+ } else {
+ cp_block(bh->b_data,offset);
+ brelse(bh);
+ }
+ size -= BLOCK_SIZE;
+ offset += BLOCK_SIZE;
+ }
+ brelse(ih);
+ return 0;
+}
+
+/*
+ * read_area() reads an area into %fs:mem.
+ */
+int read_area(struct m_inode * inode,long size)
+{
+ struct buffer_head * dind;
+ unsigned short * table;
+ int i,count;
+
+ if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
+ (size -= BLOCK_SIZE*6)<=0)
+ return i;
+ if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
+ (size -= BLOCK_SIZE*512)<=0)
+ return i;
+ if (!(i=inode->i_zone[8]))
+ return 0;
+ if (!(dind = bread(inode->i_dev,i)))
+ return -1;
+ table = (unsigned short *) dind->b_data;
+ for(count=0 ; count<512 ; count++)
+ if ((i=read_ind(inode->i_dev,*(table++),size,
+ BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
+ return i;
+ panic("Impossibly long executable");
+}
+
+/*
+ * create_tables() parses the env- and arg-strings in new user
+ * memory and creates the pointer tables from them, and puts their
+ * addresses on the "stack", returning the new stack pointer value.
+ */
+static unsigned long * create_tables(char * p,int argc,int envc)
+{
+ unsigned long *argv,*envp;
+ unsigned long * sp;
+
+ sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
+ sp -= envc+1;
+ envp = sp;
+ sp -= argc+1;
+ argv = sp;
+ put_fs_long((unsigned long)envp,--sp);
+ put_fs_long((unsigned long)argv,--sp);
+ put_fs_long((unsigned long)argc,--sp);
+ while (argc-->0) {
+ put_fs_long((unsigned long) p,argv++);
+ while (get_fs_byte(p++)) /* nothing */ ;
+ }
+ put_fs_long(0,argv);
+ while (envc-->0) {
+ put_fs_long((unsigned long) p,envp++);
+ while (get_fs_byte(p++)) /* nothing */ ;
+ }
+ put_fs_long(0,envp);
+ return sp;
+}
+
+/*
+ * count() counts the number of arguments/envelopes
+ */
+static int count(char ** argv)
+{
+ int i=0;
+ char ** tmp;
+
+ if (tmp = argv)
+ while (get_fs_long((unsigned long *) (tmp++)))
+ i++;
+
+ return i;
+}
+
+/*
+ * 'copy_string()' copies argument/envelope strings from user
+ * memory to free pages in kernel mem. These are in a format ready
+ * to be put directly into the top of new user memory.
+ */
+static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
+ unsigned long p)
+{
+ int len,i;
+ char *tmp;
+
+ while (argc-- > 0) {
+ if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
+ panic("argc is wrong");
+ len=0; /* remember zero-padding */
+ do {
+ len++;
+ } while (get_fs_byte(tmp++));
+ if (p-len < 0) /* this shouldn't happen - 128kB */
+ return 0;
+ i = ((unsigned) (p-len)) >> 12;
+ while (i<MAX_ARG_PAGES && !page[i]) {
+ if (!(page[i]=get_free_page()))
+ return 0;
+ i++;
+ }
+ do {
+ --p;
+ if (!page[p/PAGE_SIZE])
+ panic("nonexistent page in exec.c");
+ ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
+ get_fs_byte(--tmp);
+ } while (--len);
+ }
+ return p;
+}
+
+static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
+{
+ unsigned long code_limit,data_limit,code_base,data_base;
+ int i;
+
+ code_limit = text_size+PAGE_SIZE -1;
+ code_limit &= 0xFFFFF000;
+ data_limit = 0x4000000;
+ code_base = get_base(current->ldt[1]);
+ data_base = code_base;
+ set_base(current->ldt[1],code_base);
+ set_limit(current->ldt[1],code_limit);
+ set_base(current->ldt[2],data_base);
+ set_limit(current->ldt[2],data_limit);
+/* make sure fs points to the NEW data segment */
+ __asm__("pushl $0x17\n\tpop %%fs"::);
+ data_base += data_limit;
+ for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
+ data_base -= PAGE_SIZE;
+ if (page[i])
+ put_page(page[i],data_base);
+ }
+ return data_limit;
+}
+
+/*
+ * 'do_execve()' executes a new program.
+ */
+int do_execve(unsigned long * eip,long tmp,char * filename,
+ char ** argv, char ** envp)
+{
+ struct m_inode * inode;
+ struct buffer_head * bh;
+ struct exec ex;
+ unsigned long page[MAX_ARG_PAGES];
+ int i,argc,envc;
+ unsigned long p;
+
+ if ((0xffff & eip[1]) != 0x000f)
+ panic("execve called from supervisor mode");
+ for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
+ page[i]=0;
+ if (!(inode=namei(filename))) /* get executables inode */
+ return -ENOENT;
+ if (!S_ISREG(inode->i_mode)) { /* must be regular file */
+ iput(inode);
+ return -EACCES;
+ }
+ i = inode->i_mode;
+ if (current->uid && current->euid) {
+ if (current->euid == inode->i_uid)
+ i >>= 6;
+ else if (current->egid == inode->i_gid)
+ i >>= 3;
+ } else if (i & 0111)
+ i=1;
+ if (!(i & 1)) {
+ iput(inode);
+ return -ENOEXEC;
+ }
+ if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
+ iput(inode);
+ return -EACCES;
+ }
+ ex = *((struct exec *) bh->b_data); /* read exec-header */
+ brelse(bh);
+ if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
+ ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
+ inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
+ iput(inode);
+ return -ENOEXEC;
+ }
+ if (N_TXTOFF(ex) != BLOCK_SIZE)
+ panic("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
+ argc = count(argv);
+ envc = count(envp);
+ p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
+ p = copy_strings(argc,argv,page,p);
+ if (!p) {
+ for (i=0 ; i<MAX_ARG_PAGES ; i++)
+ free_page(page[i]);
+ iput(inode);
+ return -1;
+ }
+/* OK, This is the point of no return */
+ for (i=0 ; i<32 ; i++)
+ current->sig_fn[i] = NULL;
+ for (i=0 ; i<NR_OPEN ; i++)
+ if ((current->close_on_exec>>i)&1)
+ sys_close(i);
+ current->close_on_exec = 0;
+ free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
+ free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
+ current->used_math = 0;
+ p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
+ p = (unsigned long) create_tables((char *)p,argc,envc);
+ current->brk = ex.a_bss +
+ (current->end_data = ex.a_data +
+ (current->end_code = ex.a_text));
+ current->start_stack = p & 0xfffff000;
+ i = read_area(inode,ex.a_text+ex.a_data);
+ iput(inode);
+ if (i<0)
+ sys_exit(-1);
+ i = ex.a_text+ex.a_data;
+ while (i&0xfff)
+ put_fs_byte(0,(char *) (i++));
+ eip[0] = ex.a_entry; /* eip, magic happens :-) */
+ eip[3] = p; /* stack pointer */
+ return 0;
+}
diff --git a/linux/fs/fcntl.c b/linux/fs/fcntl.c
new file mode 100644
index 0000000..169f376
--- /dev/null
+++ b/linux/fs/fcntl.c
@@ -0,0 +1,69 @@
+#include <string.h>
+#include <errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+extern int sys_close(int fd);
+
+static int dupfd(unsigned int fd, unsigned int arg)
+{
+ if (fd >= NR_OPEN || !current->filp[fd])
+ return -EBADF;
+ if (arg >= NR_OPEN)
+ return -EINVAL;
+ while (arg < NR_OPEN)
+ if (current->filp[arg])
+ arg++;
+ else
+ break;
+ if (arg >= NR_OPEN)
+ return -EMFILE;
+ current->close_on_exec &= ~(1<<arg);
+ (current->filp[arg] = current->filp[fd])->f_count++;
+ return arg;
+}
+
+int sys_dup2(unsigned int oldfd, unsigned int newfd)
+{
+ sys_close(newfd);
+ return dupfd(oldfd,newfd);
+}
+
+int sys_dup(unsigned int fildes)
+{
+ return dupfd(fildes,0);
+}
+
+int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct file * filp;
+
+ if (fd >= NR_OPEN || !(filp = current->filp[fd]))
+ return -EBADF;
+ switch (cmd) {
+ case F_DUPFD:
+ return dupfd(fd,arg);
+ case F_GETFD:
+ return (current->close_on_exec>>fd)&1;
+ case F_SETFD:
+ if (arg&1)
+ current->close_on_exec |= (1<<fd);
+ else
+ current->close_on_exec &= ~(1<<fd);
+ return 0;
+ case F_GETFL:
+ return filp->f_flags;
+ case F_SETFL:
+ filp->f_flags &= ~(O_APPEND | O_NONBLOCK);
+ filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
+ return 0;
+ case F_GETLK: case F_SETLK: case F_SETLKW:
+ return -1;
+ default:
+ return -1;
+ }
+}
diff --git a/linux/fs/file_dev.c b/linux/fs/file_dev.c
new file mode 100644
index 0000000..da5d014
--- /dev/null
+++ b/linux/fs/file_dev.c
@@ -0,0 +1,84 @@
+#include <errno.h>
+#include <fcntl.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
+{
+ int left,chars,nr;
+ struct buffer_head * bh;
+
+ if ((left=count)<=0)
+ return 0;
+ while (left) {
+ if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) {
+ if (!(bh=bread(inode->i_dev,nr)))
+ break;
+ } else
+ bh = NULL;
+ nr = filp->f_pos % BLOCK_SIZE;
+ chars = MIN( BLOCK_SIZE-nr , left );
+ filp->f_pos += chars;
+ left -= chars;
+ if (bh) {
+ char * p = nr + bh->b_data;
+ while (chars-->0)
+ put_fs_byte(*(p++),buf++);
+ brelse(bh);
+ } else {
+ while (chars-->0)
+ put_fs_byte(0,buf++);
+ }
+ }
+ inode->i_atime = CURRENT_TIME;
+ return (count-left)?(count-left):-ERROR;
+}
+
+int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)
+{
+ off_t pos;
+ int block,c;
+ struct buffer_head * bh;
+ char * p;
+ int i=0;
+
+/*
+ * ok, append may not work when many processes are writing at the same time
+ * but so what. That way leads to madness anyway.
+ */
+ if (filp->f_flags & O_APPEND)
+ pos = inode->i_size;
+ else
+ pos = filp->f_pos;
+ while (i<count) {
+ if (!(block = create_block(inode,pos/BLOCK_SIZE)))
+ break;
+ if (!(bh=bread(inode->i_dev,block)))
+ break;
+ c = pos % BLOCK_SIZE;
+ p = c + bh->b_data;
+ bh->b_dirt = 1;
+ c = BLOCK_SIZE-c;
+ if (c > count-i) c = count-i;
+ pos += c;
+ if (pos > inode->i_size) {
+ inode->i_size = pos;
+ inode->i_dirt = 1;
+ }
+ i += c;
+ while (c-->0)
+ *(p++) = get_fs_byte(buf++);
+ brelse(bh);
+ }
+ inode->i_mtime = CURRENT_TIME;
+ if (!(filp->f_flags & O_APPEND)) {
+ filp->f_pos = pos;
+ inode->i_ctime = CURRENT_TIME;
+ }
+ return (i?i:-1);
+}
diff --git a/linux/fs/file_table.c b/linux/fs/file_table.c
new file mode 100644
index 0000000..ab7cebf
--- /dev/null
+++ b/linux/fs/file_table.c
@@ -0,0 +1,3 @@
+#include <linux/fs.h>
+
+struct file file_table[NR_FILE];
diff --git a/linux/fs/inode.c b/linux/fs/inode.c
new file mode 100644
index 0000000..d06ff90
--- /dev/null
+++ b/linux/fs/inode.c
@@ -0,0 +1,288 @@
+#include <string.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+
+struct m_inode inode_table[NR_INODE]={{0,},};
+
+static void read_inode(struct m_inode * inode);
+static void write_inode(struct m_inode * inode);
+
+static inline void wait_on_inode(struct m_inode * inode)
+{
+ cli();
+ while (inode->i_lock)
+ sleep_on(&inode->i_wait);
+ sti();
+}
+
+static inline void lock_inode(struct m_inode * inode)
+{
+ cli();
+ while (inode->i_lock)
+ sleep_on(&inode->i_wait);
+ inode->i_lock=1;
+ sti();
+}
+
+static inline void unlock_inode(struct m_inode * inode)
+{
+ inode->i_lock=0;
+ wake_up(&inode->i_wait);
+}
+
+void sync_inodes(void)
+{
+ int i;
+ struct m_inode * inode;
+
+ inode = 0+inode_table;
+ for(i=0 ; i<NR_INODE ; i++,inode++) {
+ wait_on_inode(inode);
+ if (inode->i_dirt && !inode->i_pipe)
+ write_inode(inode);
+ }
+}
+
+static int _bmap(struct m_inode * inode,int block,int create)
+{
+ struct buffer_head * bh;
+ int i;
+
+ if (block<0)
+ panic("_bmap: block<0");
+ if (block >= 7+512+512*512)
+ panic("_bmap: block>big");
+ if (block<7) {
+ if (create && !inode->i_zone[block])
+ if (inode->i_zone[block]=new_block(inode->i_dev)) {
+ inode->i_ctime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
+ return inode->i_zone[block];
+ }
+ block -= 7;
+ if (block<512) {
+ if (create && !inode->i_zone[7])
+ if (inode->i_zone[7]=new_block(inode->i_dev)) {
+ inode->i_dirt=1;
+ inode->i_ctime=CURRENT_TIME;
+ }
+ if (!inode->i_zone[7])
+ return 0;
+ if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
+ return 0;
+ i = ((unsigned short *) (bh->b_data))[block];
+ if (create && !i)
+ if (i=new_block(inode->i_dev)) {
+ ((unsigned short *) (bh->b_data))[block]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ return i;
+ }
+ block -= 512;
+ if (create && !inode->i_zone[8])
+ if (inode->i_zone[8]=new_block(inode->i_dev)) {
+ inode->i_dirt=1;
+ inode->i_ctime=CURRENT_TIME;
+ }
+ if (!inode->i_zone[8])
+ return 0;
+ if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
+ return 0;
+ i = ((unsigned short *)bh->b_data)[block>>9];
+ if (create && !i)
+ if (i=new_block(inode->i_dev)) {
+ ((unsigned short *) (bh->b_data))[block>>9]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ if (!i)
+ return 0;
+ if (!(bh=bread(inode->i_dev,i)))
+ return 0;
+ i = ((unsigned short *)bh->b_data)[block&511];
+ if (create && !i)
+ if (i=new_block(inode->i_dev)) {
+ ((unsigned short *) (bh->b_data))[block&511]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ return i;
+}
+
+int bmap(struct m_inode * inode,int block)
+{
+ return _bmap(inode,block,0);
+}
+
+int create_block(struct m_inode * inode, int block)
+{
+ return _bmap(inode,block,1);
+}
+
+void iput(struct m_inode * inode)
+{
+ if (!inode)
+ return;
+ wait_on_inode(inode);
+ if (!inode->i_count)
+ panic("iput: trying to free free inode");
+ if (inode->i_pipe) {
+ wake_up(&inode->i_wait);
+ if (--inode->i_count)
+ return;
+ free_page(inode->i_size);
+ inode->i_count=0;
+ inode->i_dirt=0;
+ inode->i_pipe=0;
+ return;
+ }
+ if (!inode->i_dev || inode->i_count>1) {
+ inode->i_count--;
+ return;
+ }
+repeat:
+ if (!inode->i_nlinks) {
+ truncate(inode);
+ free_inode(inode);
+ return;
+ }
+ if (inode->i_dirt) {
+ write_inode(inode); /* we can sleep - so do again */
+ wait_on_inode(inode);
+ goto repeat;
+ }
+ inode->i_count--;
+ return;
+}
+
+static volatile int last_allocated_inode = 0;
+
+struct m_inode * get_empty_inode(void)
+{
+ struct m_inode * inode;
+ int inr;
+
+ while (1) {
+ inode = NULL;
+ inr = last_allocated_inode;
+ do {
+ if (!inode_table[inr].i_count) {
+ inode = inr + inode_table;
+ break;
+ }
+ inr++;
+ if (inr>=NR_INODE)
+ inr=0;
+ } while (inr != last_allocated_inode);
+ if (!inode) {
+ for (inr=0 ; inr<NR_INODE ; inr++)
+ printk("%04x: %6d\t",inode_table[inr].i_dev,
+ inode_table[inr].i_num);
+ panic("No free inodes in mem");
+ }
+ last_allocated_inode = inr;
+ wait_on_inode(inode);
+ while (inode->i_dirt) {
+ write_inode(inode);
+ wait_on_inode(inode);
+ }
+ if (!inode->i_count)
+ break;
+ }
+ memset(inode,0,sizeof(*inode));
+ inode->i_count = 1;
+ return inode;
+}
+
+struct m_inode * get_pipe_inode(void)
+{
+ struct m_inode * inode;
+
+ if (!(inode = get_empty_inode()))
+ return NULL;
+ if (!(inode->i_size=get_free_page())) {
+ inode->i_count = 0;
+ return NULL;
+ }
+ inode->i_count = 2; /* sum of readers/writers */
+ PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
+ inode->i_pipe = 1;
+ return inode;
+}
+
+struct m_inode * iget(int dev,int nr)
+{
+ struct m_inode * inode, * empty;
+
+ if (!dev)
+ panic("iget with dev==0");
+ empty = get_empty_inode();
+ inode = inode_table;
+ while (inode < NR_INODE+inode_table) {
+ if (inode->i_dev != dev || inode->i_num != nr) {
+ inode++;
+ continue;
+ }
+ wait_on_inode(inode);
+ if (inode->i_dev != dev || inode->i_num != nr) {
+ inode = inode_table;
+ continue;
+ }
+ inode->i_count++;
+ if (empty)
+ iput(empty);
+ return inode;
+ }
+ if (!empty)
+ return (NULL);
+ inode=empty;
+ inode->i_dev = dev;
+ inode->i_num = nr;
+ read_inode(inode);
+ return inode;
+}
+
+static void read_inode(struct m_inode * inode)
+{
+ struct super_block * sb;
+ struct buffer_head * bh;
+ int block;
+
+ lock_inode(inode);
+ sb=get_super(inode->i_dev);
+ block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
+ (inode->i_num-1)/INODES_PER_BLOCK;
+ if (!(bh=bread(inode->i_dev,block)))
+ panic("unable to read i-node block");
+ *(struct d_inode *)inode =
+ ((struct d_inode *)bh->b_data)
+ [(inode->i_num-1)%INODES_PER_BLOCK];
+ brelse(bh);
+ unlock_inode(inode);
+}
+
+static void write_inode(struct m_inode * inode)
+{
+ struct super_block * sb;
+ struct buffer_head * bh;
+ int block;
+
+ lock_inode(inode);
+ sb=get_super(inode->i_dev);
+ block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
+ (inode->i_num-1)/INODES_PER_BLOCK;
+ if (!(bh=bread(inode->i_dev,block)))
+ panic("unable to read i-node block");
+ ((struct d_inode *)bh->b_data)
+ [(inode->i_num-1)%INODES_PER_BLOCK] =
+ *(struct d_inode *)inode;
+ bh->b_dirt=1;
+ inode->i_dirt=0;
+ brelse(bh);
+ unlock_inode(inode);
+}
diff --git a/linux/fs/ioctl.c b/linux/fs/ioctl.c
new file mode 100644
index 0000000..131561b
--- /dev/null
+++ b/linux/fs/ioctl.c
@@ -0,0 +1,40 @@
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <linux/sched.h>
+
+extern int tty_ioctl(int dev, int cmd, int arg);
+
+typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
+
+#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
+
+static ioctl_ptr ioctl_table[]={
+ NULL, /* nodev */
+ NULL, /* /dev/mem */
+ NULL, /* /dev/fd */
+ NULL, /* /dev/hd */
+ tty_ioctl, /* /dev/ttyx */
+ tty_ioctl, /* /dev/tty */
+ NULL, /* /dev/lp */
+ NULL}; /* named pipes */
+
+
+int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct file * filp;
+ int dev,mode;
+
+ if (fd >= NR_OPEN || !(filp = current->filp[fd]))
+ return -EBADF;
+ mode=filp->f_inode->i_mode;
+ if (!S_ISCHR(mode) && !S_ISBLK(mode))
+ return -EINVAL;
+ dev = filp->f_inode->i_zone[0];
+ if (MAJOR(dev) >= NRDEVS)
+ panic("unknown device for ioctl");
+ if (!ioctl_table[MAJOR(dev)])
+ return -ENOTTY;
+ return ioctl_table[MAJOR(dev)](dev,cmd,arg);
+}
diff --git a/linux/fs/namei.c b/linux/fs/namei.c
new file mode 100644
index 0000000..600737b
--- /dev/null
+++ b/linux/fs/namei.c
@@ -0,0 +1,678 @@
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <const.h>
+#include <sys/stat.h>
+
+#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
+
+/*
+ * comment out this line if you want names > NAME_LEN chars to be
+ * truncated. Else they will be disallowed.
+ */
+/* #define NO_TRUNCATE */
+
+#define MAY_EXEC 1
+#define MAY_WRITE 2
+#define MAY_READ 4
+
+/*
+ * permission()
+ *
+ * is used to check for read/write/execute permissions on a file.
+ * I don't know if we should look at just the euid or both euid and
+ * uid, but that should be easily changed.
+ */
+static int permission(struct m_inode * inode,int mask)
+{
+ int mode = inode->i_mode;
+
+/* special case: not even root can read/write a deleted file */
+ if (inode->i_dev && !inode->i_nlinks)
+ return 0;
+ if (!(current->uid && current->euid))
+ mode=0777;
+ else if (current->uid==inode->i_uid || current->euid==inode->i_uid)
+ mode >>= 6;
+ else if (current->gid==inode->i_gid || current->egid==inode->i_gid)
+ mode >>= 3;
+ return mode & mask & 0007;
+}
+
+/*
+ * ok, we cannot use strncmp, as the name is not in our data space.
+ * Thus we'll have to use match. No big problem. Match also makes
+ * some sanity tests.
+ *
+ * NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
+ */
+static int match(int len,const char * name,struct dir_entry * de)
+{
+ register int same __asm__("ax");
+
+ if (!de || !de->inode || len > NAME_LEN)
+ return 0;
+ if (len < NAME_LEN && de->name[len])
+ return 0;
+ __asm__("cld\n\t"
+ "fs ; repe ; cmpsb\n\t"
+ "setz %%al"
+ :"=a" (same)
+ :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
+ :"cx","di","si");
+ return same;
+}
+
+/*
+ * find_entry()
+ *
+ * finds and entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ */
+static struct buffer_head * find_entry(struct m_inode * dir,
+ const char * name, int namelen, struct dir_entry ** res_dir)
+{
+ int entries;
+ int block,i;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+#ifdef NO_TRUNCATE
+ if (namelen > NAME_LEN)
+ return NULL;
+#else
+ if (namelen > NAME_LEN)
+ namelen = NAME_LEN;
+#endif
+ entries = dir->i_size / (sizeof (struct dir_entry));
+ *res_dir = NULL;
+ if (!namelen)
+ return NULL;
+ if (!(block = dir->i_zone[0]))
+ return NULL;
+ if (!(bh = bread(dir->i_dev,block)))
+ return NULL;
+ i = 0;
+ de = (struct dir_entry *) bh->b_data;
+ while (i < entries) {
+ if ((char *)de >= BLOCK_SIZE+bh->b_data) {
+ brelse(bh);
+ bh = NULL;
+ if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) ||
+ !(bh = bread(dir->i_dev,block))) {
+ i += DIR_ENTRIES_PER_BLOCK;
+ continue;
+ }
+ de = (struct dir_entry *) bh->b_data;
+ }
+ if (match(namelen,name,de)) {
+ *res_dir = de;
+ return bh;
+ }
+ de++;
+ i++;
+ }
+ brelse(bh);
+ return NULL;
+}
+
+/*
+ * add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static struct buffer_head * add_entry(struct m_inode * dir,
+ const char * name, int namelen, struct dir_entry ** res_dir)
+{
+ int block,i;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+ *res_dir = NULL;
+#ifdef NO_TRUNCATE
+ if (namelen > NAME_LEN)
+ return NULL;
+#else
+ if (namelen > NAME_LEN)
+ namelen = NAME_LEN;
+#endif
+ if (!namelen)
+ return NULL;
+ if (!(block = dir->i_zone[0]))
+ return NULL;
+ if (!(bh = bread(dir->i_dev,block)))
+ return NULL;
+ i = 0;
+ de = (struct dir_entry *) bh->b_data;
+ while (1) {
+ if ((char *)de >= BLOCK_SIZE+bh->b_data) {
+ brelse(bh);
+ bh = NULL;
+ block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
+ if (!block)
+ return NULL;
+ if (!(bh = bread(dir->i_dev,block))) {
+ i += DIR_ENTRIES_PER_BLOCK;
+ continue;
+ }
+ de = (struct dir_entry *) bh->b_data;
+ }
+ if (i*sizeof(struct dir_entry) >= dir->i_size) {
+ de->inode=0;
+ dir->i_size = (i+1)*sizeof(struct dir_entry);
+ dir->i_dirt = 1;
+ dir->i_ctime = CURRENT_TIME;
+ }
+ if (!de->inode) {
+ dir->i_mtime = CURRENT_TIME;
+ for (i=0; i < NAME_LEN ; i++)
+ de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
+ bh->b_dirt = 1;
+ *res_dir = de;
+ return bh;
+ }
+ de++;
+ i++;
+ }
+ brelse(bh);
+ return NULL;
+}
+
+/*
+ * get_dir()
+ *
+ * Getdir traverses the pathname until it hits the topmost directory.
+ * It returns NULL on failure.
+ */
+static struct m_inode * get_dir(const char * pathname)
+{
+ char c;
+ const char * thisname;
+ struct m_inode * inode;
+ struct buffer_head * bh;
+ int namelen,inr,idev;
+ struct dir_entry * de;
+
+ if (!current->root || !current->root->i_count)
+ panic("No root inode");
+ if (!current->pwd || !current->pwd->i_count)
+ panic("No cwd inode");
+ if ((c=get_fs_byte(pathname))=='/') {
+ inode = current->root;
+ pathname++;
+ } else if (c)
+ inode = current->pwd;
+ else
+ return NULL; /* empty name is bad */
+ inode->i_count++;
+ while (1) {
+ thisname = pathname;
+ if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
+ iput(inode);
+ return NULL;
+ }
+ for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
+ /* nothing */ ;
+ if (!c)
+ return inode;
+ if (!(bh = find_entry(inode,thisname,namelen,&de))) {
+ iput(inode);
+ return NULL;
+ }
+ inr = de->inode;
+ idev = inode->i_dev;
+ brelse(bh);
+ iput(inode);
+ if (!(inode = iget(idev,inr)))
+ return NULL;
+ }
+}
+
+/*
+ * dir_namei()
+ *
+ * dir_namei() returns the inode of the directory of the
+ * specified name, and the name within that directory.
+ */
+static struct m_inode * dir_namei(const char * pathname,
+ int * namelen, const char ** name)
+{
+ char c;
+ const char * basename;
+ struct m_inode * dir;
+
+ if (!(dir = get_dir(pathname)))
+ return NULL;
+ basename = pathname;
+ while (c=get_fs_byte(pathname++))
+ if (c=='/')
+ basename=pathname;
+ *namelen = pathname-basename-1;
+ *name = basename;
+ return dir;
+}
+
+/*
+ * namei()
+ *
+ * is used by most simple commands to get the inode of a specified name.
+ * Open, link etc use their own routines, but this is enough for things
+ * like 'chmod' etc.
+ */
+struct m_inode * namei(const char * pathname)
+{
+ const char * basename;
+ int inr,dev,namelen;
+ struct m_inode * dir;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+ if (!(dir = dir_namei(pathname,&namelen,&basename)))
+ return NULL;
+ if (!namelen) /* special case: '/usr/' etc */
+ return dir;
+ bh = find_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ iput(dir);
+ return NULL;
+ }
+ inr = de->inode;
+ dev = dir->i_dev;
+ brelse(bh);
+ iput(dir);
+ dir=iget(dev,inr);
+ if (dir) {
+ dir->i_atime=CURRENT_TIME;
+ dir->i_dirt=1;
+ }
+ return dir;
+}
+
+/*
+ * open_namei()
+ *
+ * namei for open - this is in fact almost the whole open-routine.
+ */
+int open_namei(const char * pathname, int flag, int mode,
+ struct m_inode ** res_inode)
+{
+ const char * basename;
+ int inr,dev,namelen;
+ struct m_inode * dir, *inode;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+ if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
+ flag |= O_WRONLY;
+ mode &= 0777 & ~current->umask;
+ mode |= I_REGULAR;
+ if (!(dir = dir_namei(pathname,&namelen,&basename)))
+ return -ENOENT;
+ if (!namelen) { /* special case: '/usr/' etc */
+ if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
+ *res_inode=dir;
+ return 0;
+ }
+ iput(dir);
+ return -EISDIR;
+ }
+ bh = find_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ if (!(flag & O_CREAT)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!permission(dir,MAY_WRITE)) {
+ iput(dir);
+ return -EACCES;
+ }
+ inode = new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_mode = mode;
+ inode->i_dirt = 1;
+ bh = add_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ inode->i_nlinks--;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_num;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ *res_inode = inode;
+ return 0;
+ }
+ inr = de->inode;
+ dev = dir->i_dev;
+ brelse(bh);
+ iput(dir);
+ if (flag & O_EXCL)
+ return -EEXIST;
+ if (!(inode=iget(dev,inr)))
+ return -EACCES;
+ if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
+ permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {
+ iput(inode);
+ return -EPERM;
+ }
+ inode->i_atime = CURRENT_TIME;
+ if (flag & O_TRUNC)
+ truncate(inode);
+ *res_inode = inode;
+ return 0;
+}
+
+int sys_mkdir(const char * pathname, int mode)
+{
+ const char * basename;
+ int namelen;
+ struct m_inode * dir, * inode;
+ struct buffer_head * bh, *dir_block;
+ struct dir_entry * de;
+
+ if (current->euid && current->uid)
+ return -EPERM;
+ if (!(dir = dir_namei(pathname,&namelen,&basename)))
+ return -ENOENT;
+ if (!namelen) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!permission(dir,MAY_WRITE)) {
+ iput(dir);
+ return -EPERM;
+ }
+ bh = find_entry(dir,basename,namelen,&de);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_size = 32;
+ inode->i_dirt = 1;
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
+ iput(dir);
+ inode->i_nlinks--;
+ iput(inode);
+ return -ENOSPC;
+ }
+ inode->i_dirt = 1;
+ if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
+ iput(dir);
+ free_block(inode->i_dev,inode->i_zone[0]);
+ inode->i_nlinks--;
+ iput(inode);
+ return -ERROR;
+ }
+ de = (struct dir_entry *) dir_block->b_data;
+ de->inode=inode->i_num;
+ strcpy(de->name,".");
+ de++;
+ de->inode = dir->i_num;
+ strcpy(de->name,"..");
+ inode->i_nlinks = 2;
+ dir_block->b_dirt = 1;
+ brelse(dir_block);
+ inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
+ inode->i_dirt = 1;
+ bh = add_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ iput(dir);
+ free_block(inode->i_dev,inode->i_zone[0]);
+ inode->i_nlinks=0;
+ iput(inode);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_num;
+ bh->b_dirt = 1;
+ dir->i_nlinks++;
+ dir->i_dirt = 1;
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return 0;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int empty_dir(struct m_inode * inode)
+{
+ int nr,block;
+ int len;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+ len = inode->i_size / sizeof (struct dir_entry);
+ if (len<2 || !inode->i_zone[0] ||
+ !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
+ printk("warning - bad directory on dev %04x\n",inode->i_dev);
+ return 0;
+ }
+ de = (struct dir_entry *) bh->b_data;
+ if (de[0].inode != inode->i_num || !de[1].inode ||
+ strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
+ printk("warning - bad directory on dev %04x\n",inode->i_dev);
+ return 0;
+ }
+ nr = 2;
+ de += 2;
+ while (nr<len) {
+ if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
+ brelse(bh);
+ block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
+ if (!block) {
+ nr += DIR_ENTRIES_PER_BLOCK;
+ continue;
+ }
+ if (!(bh=bread(inode->i_dev,block)))
+ return 0;
+ de = (struct dir_entry *) bh->b_data;
+ }
+ if (de->inode) {
+ brelse(bh);
+ return 0;
+ }
+ de++;
+ nr++;
+ }
+ brelse(bh);
+ return 1;
+}
+
+int sys_rmdir(const char * name)
+{
+ const char * basename;
+ int namelen;
+ struct m_inode * dir, * inode;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+ if (current->euid && current->uid)
+ return -EPERM;
+ if (!(dir = dir_namei(name,&namelen,&basename)))
+ return -ENOENT;
+ if (!namelen) {
+ iput(dir);
+ return -ENOENT;
+ }
+ bh = find_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!permission(dir,MAY_WRITE)) {
+ iput(dir);
+ brelse(bh);
+ return -EPERM;
+ }
+ if (!(inode = iget(dir->i_dev, de->inode))) {
+ iput(dir);
+ brelse(bh);
+ return -EPERM;
+ }
+ if (inode == dir) { /* we may not delete ".", but "../dir" is ok */
+ iput(inode);
+ iput(dir);
+ brelse(bh);
+ return -EPERM;
+ }
+ if (!S_ISDIR(inode->i_mode)) {
+ iput(inode);
+ iput(dir);
+ brelse(bh);
+ return -ENOTDIR;
+ }
+ if (!empty_dir(inode)) {
+ iput(inode);
+ iput(dir);
+ brelse(bh);
+ return -ENOTEMPTY;
+ }
+ if (inode->i_nlinks != 2)
+ printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);
+ de->inode = 0;
+ bh->b_dirt = 1;
+ brelse(bh);
+ inode->i_nlinks=0;
+ inode->i_dirt=1;
+ dir->i_nlinks--;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_dirt=1;
+ iput(dir);
+ iput(inode);
+ return 0;
+}
+
+int sys_unlink(const char * name)
+{
+ const char * basename;
+ int namelen;
+ struct m_inode * dir, * inode;
+ struct buffer_head * bh;
+ struct dir_entry * de;
+
+ if (!(dir = dir_namei(name,&namelen,&basename)))
+ return -ENOENT;
+ if (!namelen) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!permission(dir,MAY_WRITE)) {
+ iput(dir);
+ return -EPERM;
+ }
+ bh = find_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ iput(dir);
+ return -ENOENT;
+ }
+ inode = iget(dir->i_dev, de->inode);
+ if (!inode) {
+ printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
+ iput(dir);
+ brelse(bh);
+ return -ENOENT;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ iput(inode);
+ iput(dir);
+ brelse(bh);
+ return -EPERM;
+ }
+ if (!inode->i_nlinks) {
+ printk("Deleting nonexistent file (%04x:%d), %d\n",
+ inode->i_dev,inode->i_num,inode->i_nlinks);
+ inode->i_nlinks=1;
+ }
+ de->inode = 0;
+ bh->b_dirt = 1;
+ brelse(bh);
+ inode->i_nlinks--;
+ inode->i_dirt = 1;
+ inode->i_ctime = CURRENT_TIME;
+ iput(inode);
+ iput(dir);
+ return 0;
+}
+
+int sys_link(const char * oldname, const char * newname)
+{
+ struct dir_entry * de;
+ struct m_inode * oldinode, * dir;
+ struct buffer_head * bh;
+ const char * basename;
+ int namelen;
+
+ oldinode=namei(oldname);
+ if (!oldinode)
+ return -ENOENT;
+ if (!S_ISREG(oldinode->i_mode)) {
+ iput(oldinode);
+ return -EPERM;
+ }
+ dir = dir_namei(newname,&namelen,&basename);
+ if (!dir) {
+ iput(oldinode);
+ return -EACCES;
+ }
+ if (!namelen) {
+ iput(oldinode);
+ iput(dir);
+ return -EPERM;
+ }
+ if (dir->i_dev != oldinode->i_dev) {
+ iput(dir);
+ iput(oldinode);
+ return -EXDEV;
+ }
+ if (!permission(dir,MAY_WRITE)) {
+ iput(dir);
+ iput(oldinode);
+ return -EACCES;
+ }
+ bh = find_entry(dir,basename,namelen,&de);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ iput(oldinode);
+ return -EEXIST;
+ }
+ bh = add_entry(dir,basename,namelen,&de);
+ if (!bh) {
+ iput(dir);
+ iput(oldinode);
+ return -ENOSPC;
+ }
+ de->inode = oldinode->i_num;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ oldinode->i_nlinks++;
+ oldinode->i_ctime = CURRENT_TIME;
+ oldinode->i_dirt = 1;
+ iput(oldinode);
+ return 0;
+}
diff --git a/linux/fs/open.c b/linux/fs/open.c
new file mode 100644
index 0000000..6918690
--- /dev/null
+++ b/linux/fs/open.c
@@ -0,0 +1,188 @@
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utime.h>
+#include <sys/stat.h>
+
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+int sys_utime(char * filename, struct utimbuf * times)
+{
+ struct m_inode * inode;
+ long actime,modtime;
+
+ if (!(inode=namei(filename)))
+ return -ENOENT;
+ if (times) {
+ actime = get_fs_long((unsigned long *) &times->actime);
+ modtime = get_fs_long((unsigned long *) &times->modtime);
+ } else
+ actime = modtime = CURRENT_TIME;
+ inode->i_atime = actime;
+ inode->i_mtime = modtime;
+ inode->i_dirt = 1;
+ iput(inode);
+ return 0;
+}
+
+int sys_access(const char * filename,int mode)
+{
+ struct m_inode * inode;
+ int res;
+
+ mode &= 0007;
+ if (!(inode=namei(filename)))
+ return -EACCES;
+ res = inode->i_mode & 0777;
+ iput(inode);
+ if (!(current->euid && current->uid))
+ if (res & 0111)
+ res = 0777;
+ else
+ res = 0666;
+ if (current->euid == inode->i_uid)
+ res >>= 6;
+ else if (current->egid == inode->i_gid)
+ res >>= 6;
+ if ((res & 0007 & mode) == mode)
+ return 0;
+ return -EACCES;
+}
+
+int sys_chdir(const char * filename)
+{
+ struct m_inode * inode;
+
+ if (!(inode = namei(filename)))
+ return -ENOENT;
+ if (!S_ISDIR(inode->i_mode)) {
+ iput(inode);
+ return -ENOTDIR;
+ }
+ iput(current->pwd);
+ current->pwd = inode;
+ return (0);
+}
+
+int sys_chroot(const char * filename)
+{
+ struct m_inode * inode;
+
+ if (!(inode=namei(filename)))
+ return -ENOENT;
+ if (!S_ISDIR(inode->i_mode)) {
+ iput(inode);
+ return -ENOTDIR;
+ }
+ iput(current->root);
+ current->root = inode;
+ return (0);
+}
+
+int sys_chmod(const char * filename,int mode)
+{
+ struct m_inode * inode;
+
+ if (!(inode=namei(filename)))
+ return -ENOENT;
+ if (current->uid && current->euid)
+ if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) {
+ iput(inode);
+ return -EACCES;
+ } else
+ mode = (mode & 0777) | (inode->i_mode & 07000);
+ inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
+ inode->i_dirt = 1;
+ iput(inode);
+ return 0;
+}
+
+int sys_chown(const char * filename,int uid,int gid)
+{
+ struct m_inode * inode;
+
+ if (!(inode=namei(filename)))
+ return -ENOENT;
+ if (current->uid && current->euid) {
+ iput(inode);
+ return -EACCES;
+ }
+ inode->i_uid=uid;
+ inode->i_gid=gid;
+ inode->i_dirt=1;
+ iput(inode);
+ return 0;
+}
+
+int sys_open(const char * filename,int flag,int mode)
+{
+ struct m_inode * inode;
+ struct file * f;
+ int i,fd;
+
+ mode &= 0777 & ~current->umask;
+ for(fd=0 ; fd<NR_OPEN ; fd++)
+ if (!current->filp[fd])
+ break;
+ if (fd>=NR_OPEN)
+ return -EINVAL;
+ current->close_on_exec &= ~(1<<fd);
+ f=0+file_table;
+ for (i=0 ; i<NR_FILE ; i++,f++)
+ if (!f->f_count) break;
+ if (i>=NR_FILE)
+ return -EINVAL;
+ (current->filp[fd]=f)->f_count++;
+ if ((i=open_namei(filename,flag,mode,&inode))<0) {
+ current->filp[fd]=NULL;
+ f->f_count=0;
+ return i;
+ }
+/* ttys are somewhat special (ttyxx major==4, tty major==5) */
+ if (S_ISCHR(inode->i_mode))
+ if (MAJOR(inode->i_zone[0])==4) {
+ if (current->leader && current->tty<0) {
+ current->tty = MINOR(inode->i_zone[0]);
+ tty_table[current->tty].pgrp = current->pgrp;
+ }
+ } else if (MAJOR(inode->i_zone[0])==5)
+ if (current->tty<0) {
+ iput(inode);
+ current->filp[fd]=NULL;
+ f->f_count=0;
+ return -EPERM;
+ }
+ f->f_mode = inode->i_mode;
+ f->f_flags = flag;
+ f->f_count = 1;
+ f->f_inode = inode;
+ f->f_pos = 0;
+ return (fd);
+}
+
+int sys_creat(const char * pathname, int mode)
+{
+ return sys_open(pathname, O_CREAT | O_TRUNC, mode);
+}
+
+int sys_close(unsigned int fd)
+{
+ struct file * filp;
+
+ if (fd >= NR_OPEN)
+ return -EINVAL;
+ current->close_on_exec &= ~(1<<fd);
+ if (!(filp = current->filp[fd]))
+ return -EINVAL;
+ current->filp[fd] = NULL;
+ if (filp->f_count == 0)
+ panic("Close: file count is 0");
+ if (--filp->f_count)
+ return (0);
+ iput(filp->f_inode);
+ return (0);
+}
diff --git a/linux/fs/pipe.c b/linux/fs/pipe.c
new file mode 100644
index 0000000..7e03e13
--- /dev/null
+++ b/linux/fs/pipe.c
@@ -0,0 +1,92 @@
+#include <signal.h>
+
+#include <linux/sched.h>
+#include <linux/mm.h> /* for get_free_page */
+#include <asm/segment.h>
+
+int read_pipe(struct m_inode * inode, char * buf, int count)
+{
+ char * b=buf;
+
+ while (PIPE_EMPTY(*inode)) {
+ wake_up(&inode->i_wait);
+ if (inode->i_count != 2) /* are there any writers left? */
+ return 0;
+ sleep_on(&inode->i_wait);
+ }
+ while (count>0 && !(PIPE_EMPTY(*inode))) {
+ count --;
+ put_fs_byte(((char *)inode->i_size)[PIPE_TAIL(*inode)],b++);
+ INC_PIPE( PIPE_TAIL(*inode) );
+ }
+ wake_up(&inode->i_wait);
+ return b-buf;
+}
+
+int write_pipe(struct m_inode * inode, char * buf, int count)
+{
+ char * b=buf;
+
+ wake_up(&inode->i_wait);
+ if (inode->i_count != 2) { /* no readers */
+ current->signal |= (1<<(SIGPIPE-1));
+ return -1;
+ }
+ while (count-->0) {
+ while (PIPE_FULL(*inode)) {
+ wake_up(&inode->i_wait);
+ if (inode->i_count != 2) {
+ current->signal |= (1<<(SIGPIPE-1));
+ return b-buf;
+ }
+ sleep_on(&inode->i_wait);
+ }
+ ((char *)inode->i_size)[PIPE_HEAD(*inode)] = get_fs_byte(b++);
+ INC_PIPE( PIPE_HEAD(*inode) );
+ wake_up(&inode->i_wait);
+ }
+ wake_up(&inode->i_wait);
+ return b-buf;
+}
+
+int sys_pipe(unsigned long * fildes)
+{
+ struct m_inode * inode;
+ struct file * f[2];
+ int fd[2];
+ int i,j;
+
+ j=0;
+ for(i=0;j<2 && i<NR_FILE;i++)
+ if (!file_table[i].f_count)
+ (f[j++]=i+file_table)->f_count++;
+ if (j==1)
+ f[0]->f_count=0;
+ if (j<2)
+ return -1;
+ j=0;
+ for(i=0;j<2 && i<NR_OPEN;i++)
+ if (!current->filp[i]) {
+ current->filp[ fd[j]=i ] = f[j];
+ j++;
+ }
+ if (j==1)
+ current->filp[fd[0]]=NULL;
+ if (j<2) {
+ f[0]->f_count=f[1]->f_count=0;
+ return -1;
+ }
+ if (!(inode=get_pipe_inode())) {
+ current->filp[fd[0]] =
+ current->filp[fd[1]] = NULL;
+ f[0]->f_count = f[1]->f_count = 0;
+ return -1;
+ }
+ f[0]->f_inode = f[1]->f_inode = inode;
+ f[0]->f_pos = f[1]->f_pos = 0;
+ f[0]->f_mode = 1; /* read */
+ f[1]->f_mode = 2; /* write */
+ put_fs_long(fd[0],0+fildes);
+ put_fs_long(fd[1],1+fildes);
+ return 0;
+}
diff --git a/linux/fs/read_write.c b/linux/fs/read_write.c
new file mode 100644
index 0000000..93faac2
--- /dev/null
+++ b/linux/fs/read_write.c
@@ -0,0 +1,97 @@
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+
+extern int rw_char(int rw,int dev, char * buf, int count);
+extern int read_pipe(struct m_inode * inode, char * buf, int count);
+extern int write_pipe(struct m_inode * inode, char * buf, int count);
+extern int block_read(int dev, off_t * pos, char * buf, int count);
+extern int block_write(int dev, off_t * pos, char * buf, int count);
+extern int file_read(struct m_inode * inode, struct file * filp,
+ char * buf, int count);
+extern int file_write(struct m_inode * inode, struct file * filp,
+ char * buf, int count);
+
+int sys_lseek(unsigned int fd,off_t offset, int origin)
+{
+ struct file * file;
+ int tmp;
+
+ if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)
+ || !IS_BLOCKDEV(MAJOR(file->f_inode->i_dev)))
+ return -EBADF;
+ if (file->f_inode->i_pipe)
+ return -ESPIPE;
+ switch (origin) {
+ case 0:
+ if (offset<0) return -EINVAL;
+ file->f_pos=offset;
+ break;
+ case 1:
+ if (file->f_pos+offset<0) return -EINVAL;
+ file->f_pos += offset;
+ break;
+ case 2:
+ if ((tmp=file->f_inode->i_size+offset) < 0)
+ return -EINVAL;
+ file->f_pos = tmp;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return file->f_pos;
+}
+
+int sys_read(unsigned int fd,char * buf,int count)
+{
+ struct file * file;
+ struct m_inode * inode;
+
+ if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
+ return -EINVAL;
+ if (!count)
+ return 0;
+ verify_area(buf,count);
+ inode = file->f_inode;
+ if (inode->i_pipe)
+ return (file->f_mode&1)?read_pipe(inode,buf,count):-1;
+ if (S_ISCHR(inode->i_mode))
+ return rw_char(READ,inode->i_zone[0],buf,count);
+ if (S_ISBLK(inode->i_mode))
+ return block_read(inode->i_zone[0],&file->f_pos,buf,count);
+ if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
+ if (count+file->f_pos > inode->i_size)
+ count = inode->i_size - file->f_pos;
+ if (count<=0)
+ return 0;
+ return file_read(inode,file,buf,count);
+ }
+ printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
+ return -EINVAL;
+}
+
+int sys_write(unsigned int fd,char * buf,int count)
+{
+ struct file * file;
+ struct m_inode * inode;
+
+ if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
+ return -EINVAL;
+ if (!count)
+ return 0;
+ inode=file->f_inode;
+ if (inode->i_pipe)
+ return (file->f_mode&2)?write_pipe(inode,buf,count):-1;
+ if (S_ISCHR(inode->i_mode))
+ return rw_char(WRITE,inode->i_zone[0],buf,count);
+ if (S_ISBLK(inode->i_mode))
+ return block_write(inode->i_zone[0],&file->f_pos,buf,count);
+ if (S_ISREG(inode->i_mode))
+ return file_write(inode,file,buf,count);
+ printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
+ return -EINVAL;
+}
diff --git a/linux/fs/stat.c b/linux/fs/stat.c
new file mode 100644
index 0000000..4bec71d
--- /dev/null
+++ b/linux/fs/stat.c
@@ -0,0 +1,51 @@
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+static int cp_stat(struct m_inode * inode, struct stat * statbuf)
+{
+ struct stat tmp;
+ int i;
+
+ verify_area(statbuf,sizeof (* statbuf));
+ tmp.st_dev = inode->i_dev;
+ tmp.st_ino = inode->i_num;
+ tmp.st_mode = inode->i_mode;
+ tmp.st_nlink = inode->i_nlinks;
+ tmp.st_uid = inode->i_uid;
+ tmp.st_gid = inode->i_gid;
+ tmp.st_rdev = inode->i_zone[0];
+ tmp.st_size = inode->i_size;
+ tmp.st_atime = inode->i_atime;
+ tmp.st_mtime = inode->i_mtime;
+ tmp.st_ctime = inode->i_ctime;
+ for (i=0 ; i<sizeof (tmp) ; i++)
+ put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]);
+ return (0);
+}
+
+int sys_stat(char * filename, struct stat * statbuf)
+{
+ int i;
+ struct m_inode * inode;
+
+ if (!(inode=namei(filename)))
+ return -ENOENT;
+ i=cp_stat(inode,statbuf);
+ iput(inode);
+ return i;
+}
+
+int sys_fstat(unsigned int fd, struct stat * statbuf)
+{
+ struct file * f;
+ struct m_inode * inode;
+
+ if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
+ return -ENOENT;
+ return cp_stat(inode,statbuf);
+}
diff --git a/linux/fs/super.c b/linux/fs/super.c
new file mode 100644
index 0000000..d832289
--- /dev/null
+++ b/linux/fs/super.c
@@ -0,0 +1,102 @@
+/*
+ * super.c contains code to handle the super-block tables.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+/* set_bit uses setb, as gas doesn't recognize setc */
+#define set_bit(bitnr,addr) ({ \
+register int __res __asm__("ax"); \
+__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
+__res; })
+
+struct super_block super_block[NR_SUPER];
+
+struct super_block * do_mount(int dev)
+{
+ struct super_block * p;
+ struct buffer_head * bh;
+ int i,block;
+
+ for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++ )
+ if (!(p->s_dev))
+ break;
+ p->s_dev = -1; /* mark it in use */
+ if (p >= &super_block[NR_SUPER])
+ return NULL;
+ if (!(bh = bread(dev,1)))
+ return NULL;
+ *p = *((struct super_block *) bh->b_data);
+ brelse(bh);
+ if (p->s_magic != SUPER_MAGIC) {
+ p->s_dev = 0;
+ return NULL;
+ }
+ for (i=0;i<I_MAP_SLOTS;i++)
+ p->s_imap[i] = NULL;
+ for (i=0;i<Z_MAP_SLOTS;i++)
+ p->s_zmap[i] = NULL;
+ block=2;
+ for (i=0 ; i < p->s_imap_blocks ; i++)
+ if (p->s_imap[i]=bread(dev,block))
+ block++;
+ else
+ break;
+ for (i=0 ; i < p->s_zmap_blocks ; i++)
+ if (p->s_zmap[i]=bread(dev,block))
+ block++;
+ else
+ break;
+ if (block != 2+p->s_imap_blocks+p->s_zmap_blocks) {
+ for(i=0;i<I_MAP_SLOTS;i++)
+ brelse(p->s_imap[i]);
+ for(i=0;i<Z_MAP_SLOTS;i++)
+ brelse(p->s_zmap[i]);
+ p->s_dev=0;
+ return NULL;
+ }
+ p->s_imap[0]->b_data[0] |= 1;
+ p->s_zmap[0]->b_data[0] |= 1;
+ p->s_dev = dev;
+ p->s_isup = NULL;
+ p->s_imount = NULL;
+ p->s_time = 0;
+ p->s_rd_only = 0;
+ p->s_dirt = 0;
+ return p;
+}
+
+void mount_root(void)
+{
+ int i,free;
+ struct super_block * p;
+ struct m_inode * mi;
+
+ if (32 != sizeof (struct d_inode))
+ panic("bad i-node size");
+ for(i=0;i<NR_FILE;i++)
+ file_table[i].f_count=0;
+ for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++)
+ p->s_dev = 0;
+ if (!(p=do_mount(ROOT_DEV)))
+ panic("Unable to mount root");
+ if (!(mi=iget(ROOT_DEV,1)))
+ panic("Unable to read root i-node");
+ mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
+ p->s_isup = p->s_imount = mi;
+ current->pwd = mi;
+ current->root = mi;
+ free=0;
+ i=p->s_nzones;
+ while (-- i >= 0)
+ if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
+ free++;
+ printk("%d/%d free blocks\n\r",free,p->s_nzones);
+ free=0;
+ i=p->s_ninodes+1;
+ while (-- i >= 0)
+ if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
+ free++;
+ printk("%d/%d free inodes\n\r",free,p->s_ninodes);
+}
diff --git a/linux/fs/truncate.c b/linux/fs/truncate.c
new file mode 100644
index 0000000..fd82db8
--- /dev/null
+++ b/linux/fs/truncate.c
@@ -0,0 +1,59 @@
+#include <linux/sched.h>
+
+#include <sys/stat.h>
+
+static void free_ind(int dev,int block)
+{
+ struct buffer_head * bh;
+ unsigned short * p;
+ int i;
+
+ if (!block)
+ return;
+ if (bh=bread(dev,block)) {
+ p = (unsigned short *) bh->b_data;
+ for (i=0;i<512;i++,p++)
+ if (*p)
+ free_block(dev,*p);
+ brelse(bh);
+ }
+ free_block(dev,block);
+}
+
+static void free_dind(int dev,int block)
+{
+ struct buffer_head * bh;
+ unsigned short * p;
+ int i;
+
+ if (!block)
+ return;
+ if (bh=bread(dev,block)) {
+ p = (unsigned short *) bh->b_data;
+ for (i=0;i<512;i++,p++)
+ if (*p)
+ free_ind(dev,*p);
+ brelse(bh);
+ }
+ free_block(dev,block);
+}
+
+void truncate(struct m_inode * inode)
+{
+ int i;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
+ return;
+ for (i=0;i<7;i++)
+ if (inode->i_zone[i]) {
+ free_block(inode->i_dev,inode->i_zone[i]);
+ inode->i_zone[i]=0;
+ }
+ free_ind(inode->i_dev,inode->i_zone[7]);
+ free_dind(inode->i_dev,inode->i_zone[8]);
+ inode->i_zone[7] = inode->i_zone[8] = 0;
+ inode->i_size = 0;
+ inode->i_dirt = 1;
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+}
+
diff --git a/linux/fs/tty_ioctl.c b/linux/fs/tty_ioctl.c
new file mode 100644
index 0000000..b4d9bf7
--- /dev/null
+++ b/linux/fs/tty_ioctl.c
@@ -0,0 +1,166 @@
+#include <errno.h>
+#include <termios.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+static void flush(struct tty_queue * queue)
+{
+ cli();
+ queue->head = queue->tail;
+ sti();
+}
+
+static void wait_until_sent(struct tty_struct * tty)
+{
+ /* do nothing - not implemented */
+}
+
+static void send_break(struct tty_struct * tty)
+{
+ /* do nothing - not implemented */
+}
+
+static int get_termios(struct tty_struct * tty, struct termios * termios)
+{
+ int i;
+
+ verify_area(termios, sizeof (*termios));
+ for (i=0 ; i< (sizeof (*termios)) ; i++)
+ put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
+ return 0;
+}
+
+static int set_termios(struct tty_struct * tty, struct termios * termios)
+{
+ int i;
+
+ for (i=0 ; i< (sizeof (*termios)) ; i++)
+ ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
+ return 0;
+}
+
+static int get_termio(struct tty_struct * tty, struct termio * termio)
+{
+ int i;
+ struct termio tmp_termio;
+
+ verify_area(termio, sizeof (*termio));
+ tmp_termio.c_iflag = tty->termios.c_iflag;
+ tmp_termio.c_oflag = tty->termios.c_oflag;
+ tmp_termio.c_cflag = tty->termios.c_cflag;
+ tmp_termio.c_lflag = tty->termios.c_lflag;
+ tmp_termio.c_line = tty->termios.c_line;
+ for(i=0 ; i < NCC ; i++)
+ tmp_termio.c_cc[i] = tty->termios.c_cc[i];
+ for (i=0 ; i< (sizeof (*termio)) ; i++)
+ put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
+ return 0;
+}
+
+static int set_termio(struct tty_struct * tty, struct termio * termio)
+{
+ int i;
+ struct termio tmp_termio;
+
+ for (i=0 ; i< (sizeof (*termio)) ; i++)
+ ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
+ *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
+ *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
+ *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
+ *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
+ tty->termios.c_line = tmp_termio.c_line;
+ for(i=0 ; i < NCC ; i++)
+ tty->termios.c_cc[i] = tmp_termio.c_cc[i];
+ return 0;
+}
+
+int tty_ioctl(int dev, int cmd, int arg)
+{
+ struct tty_struct * tty;
+ if (MAJOR(dev) == 5) {
+ dev=current->tty;
+ if (dev<0)
+ panic("tty_ioctl: dev<0");
+ } else
+ dev=MINOR(dev);
+ tty = dev + tty_table;
+ switch (cmd) {
+ case TCGETS:
+ return get_termios(tty,(struct termios *) arg);
+ case TCSETSF:
+ flush(&tty->read_q); /* fallthrough */
+ case TCSETSW:
+ wait_until_sent(tty); /* fallthrough */
+ case TCSETS:
+ return set_termios(tty,(struct termios *) arg);
+ case TCGETA:
+ return get_termio(tty,(struct termio *) arg);
+ case TCSETAF:
+ flush(&tty->read_q); /* fallthrough */
+ case TCSETAW:
+ wait_until_sent(tty); /* fallthrough */
+ case TCSETA:
+ return set_termio(tty,(struct termio *) arg);
+ case TCSBRK:
+ if (!arg) {
+ wait_until_sent(tty);
+ send_break(tty);
+ }
+ return 0;
+ case TCXONC:
+ return -EINVAL; /* not implemented */
+ case TCFLSH:
+ if (arg==0)
+ flush(&tty->read_q);
+ else if (arg==1)
+ flush(&tty->write_q);
+ else if (arg==2) {
+ flush(&tty->read_q);
+ flush(&tty->write_q);
+ } else
+ return -EINVAL;
+ return 0;
+ case TIOCEXCL:
+ return -EINVAL; /* not implemented */
+ case TIOCNXCL:
+ return -EINVAL; /* not implemented */
+ case TIOCSCTTY:
+ return -EINVAL; /* set controlling term NI */
+ case TIOCGPGRP:
+ verify_area((void *) arg,4);
+ put_fs_long(tty->pgrp,(unsigned long *) arg);
+ return 0;
+ case TIOCSPGRP:
+ tty->pgrp=get_fs_long((unsigned long *) arg);
+ return 0;
+ case TIOCOUTQ:
+ verify_area((void *) arg,4);
+ put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
+ return 0;
+ case TIOCSTI:
+ return -EINVAL; /* not implemented */
+ case TIOCGWINSZ:
+ return -EINVAL; /* not implemented */
+ case TIOCSWINSZ:
+ return -EINVAL; /* not implemented */
+ case TIOCMGET:
+ return -EINVAL; /* not implemented */
+ case TIOCMBIS:
+ return -EINVAL; /* not implemented */
+ case TIOCMBIC:
+ return -EINVAL; /* not implemented */
+ case TIOCMSET:
+ return -EINVAL; /* not implemented */
+ case TIOCGSOFTCAR:
+ return -EINVAL; /* not implemented */
+ case TIOCSSOFTCAR:
+ return -EINVAL; /* not implemented */
+ default:
+ return -EINVAL;
+ }
+}
diff --git a/linux/include/a.out.h b/linux/include/a.out.h
new file mode 100644
index 0000000..3e67974
--- /dev/null
+++ b/linux/include/a.out.h
@@ -0,0 +1,220 @@
+#ifndef _A_OUT_H
+#define _A_OUT_H
+
+#define __GNU_EXEC_MACROS__
+
+struct exec {
+ unsigned long a_magic; /* Use macros N_MAGIC, etc for access */
+ unsigned a_text; /* length of text, in bytes */
+ unsigned a_data; /* length of data, in bytes */
+ unsigned a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned a_syms; /* length of symbol table data in file, in bytes */
+ unsigned a_entry; /* start address */
+ unsigned a_trsize; /* length of relocation info for text, in bytes */
+ unsigned a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#ifndef N_MAGIC
+#define N_MAGIC(exec) ((exec).a_magic)
+#endif
+
+#ifndef OMAGIC
+/* Code indicating object file or impure executable. */
+#define OMAGIC 0407
+/* Code indicating pure executable. */
+#define NMAGIC 0410
+/* Code indicating demand-paged executable. */
+#define ZMAGIC 0413
+#endif /* not OMAGIC */
+
+#ifndef N_BADMAG
+#define N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#endif
+
+#define _N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+
+#define _N_HDROFF(x) (SEGMENT_SIZE - sizeof (struct exec))
+
+#ifndef N_TXTOFF
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
+#endif
+
+#ifndef N_DATOFF
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#endif
+
+#ifndef N_TRELOFF
+#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
+#endif
+
+#ifndef N_DRELOFF
+#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
+#endif
+
+#ifndef N_SYMOFF
+#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
+#endif
+
+#ifndef N_STROFF
+#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
+#endif
+
+/* Address of text segment in memory after it is loaded. */
+#ifndef N_TXTADDR
+#define N_TXTADDR(x) 0
+#endif
+
+/* Address of data segment in memory after it is loaded.
+ Note that it is up to you to define SEGMENT_SIZE
+ on machines not listed here. */
+#if defined(vax) || defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+#ifdef hp300
+#define PAGE_SIZE 4096
+#endif
+#ifdef sony
+#define SEGMENT_SIZE 0x2000
+#endif /* Sony. */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+
+#define PAGE_SIZE 4096
+#define SEGMENT_SIZE 1024
+
+#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+#endif
+
+/* Address of bss segment in memory after it is loaded. */
+#ifndef N_BSSADDR
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+#endif
+
+#ifndef N_NLIST_DECLARED
+struct nlist {
+ union {
+ char *n_name;
+ struct nlist *n_next;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ char n_other;
+ short n_desc;
+ unsigned long n_value;
+};
+#endif
+
+#ifndef N_UNDF
+#define N_UNDF 0
+#endif
+#ifndef N_ABS
+#define N_ABS 2
+#endif
+#ifndef N_TEXT
+#define N_TEXT 4
+#endif
+#ifndef N_DATA
+#define N_DATA 6
+#endif
+#ifndef N_BSS
+#define N_BSS 8
+#endif
+#ifndef N_COMM
+#define N_COMM 18
+#endif
+#ifndef N_FN
+#define N_FN 15
+#endif
+
+#ifndef N_EXT
+#define N_EXT 1
+#endif
+#ifndef N_TYPE
+#define N_TYPE 036
+#endif
+#ifndef N_STAB
+#define N_STAB 0340
+#endif
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+#define N_INDR 0xa
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+#ifndef N_RELOCATION_INFO_DECLARED
+
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct relocation_info
+{
+ /* Address (within segment) to be relocated. */
+ int r_address;
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in file's the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* Four bits that aren't used, but when writing an object file
+ it is desirable to clear them. */
+ unsigned int r_pad:4;
+};
+#endif /* no N_RELOCATION_INFO_DECLARED. */
+
+
+#endif /* __A_OUT_GNU_H__ */
diff --git a/linux/include/asm/io.h b/linux/include/asm/io.h
new file mode 100644
index 0000000..d5cc42a
--- /dev/null
+++ b/linux/include/asm/io.h
@@ -0,0 +1,24 @@
+#define outb(value,port) \
+__asm__ ("outb %%al,%%dx"::"a" (value),"d" (port))
+
+
+#define inb(port) ({ \
+unsigned char _v; \
+__asm__ volatile ("inb %%dx,%%al":"=a" (_v):"d" (port)); \
+_v; \
+})
+
+#define outb_p(value,port) \
+__asm__ ("outb %%al,%%dx\n" \
+ "\tjmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:"::"a" (value),"d" (port))
+
+#define inb_p(port) ({ \
+unsigned char _v; \
+__asm__ volatile ("inb %%dx,%%al\n" \
+ "\tjmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:":"=a" (_v):"d" (port)); \
+_v; \
+})
diff --git a/linux/include/asm/memory.h b/linux/include/asm/memory.h
new file mode 100644
index 0000000..4b0a98e
--- /dev/null
+++ b/linux/include/asm/memory.h
@@ -0,0 +1,14 @@
+/*
+ * NOTE!!! memcpy(dest,src,n) assumes ds=es=normal data segment. This
+ * goes for all kernel functions (ds=es=kernel space, fs=local data,
+ * gs=null), as well as for all well-behaving user programs (ds=es=
+ * user data space). This is NOT a bug, as any user program that changes
+ * es deserves to die if it isn't careful.
+ */
+#define memcpy(dest,src,n) ({ \
+void * _res = dest; \
+__asm__ ("cld;rep;movsb" \
+ ::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \
+ :"di","si","cx"); \
+_res; \
+})
diff --git a/linux/include/asm/segment.h b/linux/include/asm/segment.h
new file mode 100644
index 0000000..1a53b08
--- /dev/null
+++ b/linux/include/asm/segment.h
@@ -0,0 +1,38 @@
+extern inline unsigned char get_fs_byte(const char * addr)
+{
+ unsigned register char _v;
+
+ __asm__ ("movb %%fs:%1,%0":"=r" (_v):"m" (*addr));
+ return _v;
+}
+
+extern inline unsigned short get_fs_word(const unsigned short *addr)
+{
+ unsigned short _v;
+
+ __asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr));
+ return _v;
+}
+
+extern inline unsigned long get_fs_long(const unsigned long *addr)
+{
+ unsigned long _v;
+
+ __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
+ return _v;
+}
+
+extern inline void put_fs_byte(char val,char *addr)
+{
+__asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr));
+}
+
+extern inline void put_fs_word(short val,short * addr)
+{
+__asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr));
+}
+
+extern inline void put_fs_long(unsigned long val,unsigned long * addr)
+{
+__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
+}
diff --git a/linux/include/asm/system.h b/linux/include/asm/system.h
new file mode 100644
index 0000000..0b5a21d
--- /dev/null
+++ b/linux/include/asm/system.h
@@ -0,0 +1,66 @@
+#define move_to_user_mode() \
+__asm__ ("movl %%esp,%%eax\n\t" \
+ "pushl $0x17\n\t" \
+ "pushl %%eax\n\t" \
+ "pushfl\n\t" \
+ "pushl $0x0f\n\t" \
+ "pushl $1f\n\t" \
+ "iret\n" \
+ "1:\tmovl $0x17,%%eax\n\t" \
+ "movw %%ax,%%ds\n\t" \
+ "movw %%ax,%%es\n\t" \
+ "movw %%ax,%%fs\n\t" \
+ "movw %%ax,%%gs" \
+ :::"ax")
+
+#define sti() __asm__ ("sti"::)
+#define cli() __asm__ ("cli"::)
+#define nop() __asm__ ("nop"::)
+
+#define iret() __asm__ ("iret"::)
+
+#define _set_gate(gate_addr,type,dpl,addr) \
+__asm__ ("movw %%dx,%%ax\n\t" \
+ "movw %0,%%dx\n\t" \
+ "movl %%eax,%1\n\t" \
+ "movl %%edx,%2" \
+ : \
+ : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+ "o" (*((char *) (gate_addr))), \
+ "o" (*(4+(char *) (gate_addr))), \
+ "d" ((char *) (addr)),"a" (0x00080000))
+
+#define set_intr_gate(n,addr) \
+ _set_gate(&idt[n],14,0,addr)
+
+#define set_trap_gate(n,addr) \
+ _set_gate(&idt[n],15,0,addr)
+
+#define set_system_gate(n,addr) \
+ _set_gate(&idt[n],15,3,addr)
+
+#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
+ *(gate_addr) = ((base) & 0xff000000) | \
+ (((base) & 0x00ff0000)>>16) | \
+ ((limit) & 0xf0000) | \
+ ((dpl)<<13) | \
+ (0x00408000) | \
+ ((type)<<8); \
+ *((gate_addr)+1) = (((base) & 0x0000ffff)<<16) | \
+ ((limit) & 0x0ffff); }
+
+#define _set_tssldt_desc(n,addr,type) \
+__asm__ ("movw $104,%1\n\t" \
+ "movw %%ax,%2\n\t" \
+ "rorl $16,%%eax\n\t" \
+ "movb %%al,%3\n\t" \
+ "movb $" type ",%4\n\t" \
+ "movb $0x00,%5\n\t" \
+ "movb %%ah,%6\n\t" \
+ "rorl $16,%%eax" \
+ ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
+ "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
+ )
+
+#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x89")
+#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x82")
diff --git a/linux/include/const.h b/linux/include/const.h
new file mode 100644
index 0000000..7828e61
--- /dev/null
+++ b/linux/include/const.h
@@ -0,0 +1,15 @@
+#ifndef _CONST_H
+#define _CONST_H
+
+#define BUFFER_END 0x200000
+
+#define I_TYPE 0170000
+#define I_DIRECTORY 0040000
+#define I_REGULAR 0100000
+#define I_BLOCK_SPECIAL 0060000
+#define I_CHAR_SPECIAL 0020000
+#define I_NAMED_PIPE 0010000
+#define I_SET_UID_BIT 0004000
+#define I_SET_GID_BIT 0002000
+
+#endif
diff --git a/linux/include/ctype.h b/linux/include/ctype.h
new file mode 100644
index 0000000..4043d6e
--- /dev/null
+++ b/linux/include/ctype.h
@@ -0,0 +1,34 @@
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#define _U 0x01 /* upper */
+#define _L 0x02 /* lower */
+#define _D 0x04 /* digit */
+#define _C 0x08 /* cntrl */
+#define _P 0x10 /* punct */
+#define _S 0x20 /* white space (space/lf/tab) */
+#define _X 0x40 /* hex digit */
+#define _SP 0x80 /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+extern char _ctmp;
+
+#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
+#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
+#define iscntrl(c) ((_ctype+1)[c]&(_C))
+#define isdigit(c) ((_ctype+1)[c]&(_D))
+#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
+#define islower(c) ((_ctype+1)[c]&(_L))
+#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
+#define ispunct(c) ((_ctype+1)[c]&(_P))
+#define isspace(c) ((_ctype+1)[c]&(_S))
+#define isupper(c) ((_ctype+1)[c]&(_U))
+#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
+
+#define isascii(c) (((unsigned) c)<=0x7f)
+#define toascii(c) (((unsigned) c)&0x7f)
+
+#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp+('a'+'A'):_ctmp)
+#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp+('A'-'a'):_ctmp)
+
+#endif
diff --git a/linux/include/errno.h b/linux/include/errno.h
new file mode 100644
index 0000000..c282f69
--- /dev/null
+++ b/linux/include/errno.h
@@ -0,0 +1,60 @@
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+/*
+ * ok, as I hadn't got any other source of information about
+ * possible error numbers, I was forced to use the same numbers
+ * as minix.
+ * Hopefully these are posix or something. I wouldn't know (and posix
+ * isn't telling me - they want $$$ for their f***ing standard).
+ *
+ * We don't use the _SIGN cludge of minix, so kernel returns must
+ * see to the sign by themselves.
+ *
+ * NOTE! Remember to change strerror() if you change this file!
+ */
+
+extern int errno;
+
+#define ERROR 99
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EIO 5
+#define ENXIO 6
+#define E2BIG 7
+#define ENOEXEC 8
+#define EBADF 9
+#define ECHILD 10
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EFAULT 14
+#define ENOTBLK 15
+#define EBUSY 16
+#define EEXIST 17
+#define EXDEV 18
+#define ENODEV 19
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define ENFILE 23
+#define EMFILE 24
+#define ENOTTY 25
+#define ETXTBSY 26
+#define EFBIG 27
+#define ENOSPC 28
+#define ESPIPE 29
+#define EROFS 30
+#define EMLINK 31
+#define EPIPE 32
+#define EDOM 33
+#define ERANGE 34
+#define EDEADLK 35
+#define ENAMETOOLONG 36
+#define ENOLCK 37
+#define ENOSYS 38
+#define ENOTEMPTY 39
+
+#endif
diff --git a/linux/include/fcntl.h b/linux/include/fcntl.h
new file mode 100644
index 0000000..a5bf9af
--- /dev/null
+++ b/linux/include/fcntl.h
@@ -0,0 +1,55 @@
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+#include <sys/types.h>
+
+/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */
+#define O_ACCMODE 00003
+#define O_RDONLY 00
+#define O_WRONLY 01
+#define O_RDWR 02
+#define O_CREAT 00100 /* not fcntl */
+#define O_EXCL 00200 /* not fcntl */
+#define O_NOCTTY 00400 /* not fcntl */
+#define O_TRUNC 01000 /* not fcntl */
+#define O_APPEND 02000
+#define O_NONBLOCK 04000 /* not fcntl */
+#define O_NDELAY O_NONBLOCK
+
+/* Defines for fcntl-commands. Note that currently
+ * locking isn't supported, and other things aren't really
+ * tested.
+ */
+#define F_DUPFD 0 /* dup */
+#define F_GETFD 1 /* get f_flags */
+#define F_SETFD 2 /* set f_flags */
+#define F_GETFL 3 /* more flags (cloexec) */
+#define F_SETFL 4
+#define F_GETLK 5 /* not implemented */
+#define F_SETLK 6
+#define F_SETLKW 7
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+/* Ok, these are locking features, and aren't implemented at any
+ * level. POSIX wants them.
+ */
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+/* Once again - not implemented, but ... */
+struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+};
+
+extern int creat(const char * filename,mode_t mode);
+extern int fcntl(int fildes,int cmd, ...);
+extern int open(const char * filename, int flags, ...);
+
+#endif
diff --git a/linux/include/linux/config.h b/linux/include/linux/config.h
new file mode 100644
index 0000000..c84cacc
--- /dev/null
+++ b/linux/include/linux/config.h
@@ -0,0 +1,53 @@
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+/* #define LASU_HD */
+#define LINUS_HD
+
+/*
+ * Amount of ram memory (in bytes, 640k-1M not discounted). Currently 8Mb.
+ * Don't make this bigger without making sure that there are enough page
+ * directory entries (boot/head.s)
+ */
+#if defined(LINUS_HD)
+#define HIGH_MEMORY (0x800000)
+#elif defined(LASU_HD)
+#define HIGH_MEMORY (0x400000)
+#else
+#error "must define hd"
+#endif
+
+/* End of buffer memory. Must be 0xA0000, or > 0x100000, 4096-byte aligned */
+#if (HIGH_MEMORY>=0x600000)
+#define BUFFER_END 0x200000
+#else
+#define BUFFER_END 0xA0000
+#endif
+
+/* Root device at bootup. */
+#if defined(LINUS_HD)
+#define ROOT_DEV 0x306
+#elif defined(LASU_HD)
+#define ROOT_DEV 0x302
+#else
+#error "must define HD"
+#endif
+
+/*
+ * HD type. If 2, put 2 structures with a comma. If just 1, put
+ * only 1 struct. The structs are { HEAD, SECTOR, TRACKS, WPCOM, LZONE, CTL }
+ *
+ * NOTE. CTL is supposed to be 0 for drives with less than 8 heads, and
+ * 8 if heads >= 8. Don't know why, and I haven't tested it on a drive with
+ * more than 8 heads, but that is what the bios-listings seem to imply. I
+ * just love not having a manual.
+ */
+#if defined(LASU_HD)
+#define HD_TYPE { 7,35,915,65536,920,0 }
+#elif defined(LINUS_HD)
+#define HD_TYPE { 5,17,980,300,980,0 },{ 5,17,980,300,980,0 }
+#else
+#error "must define a hard-disk type"
+#endif
+
+#endif
diff --git a/linux/include/linux/fs.h b/linux/include/linux/fs.h
new file mode 100644
index 0000000..e5db892
--- /dev/null
+++ b/linux/include/linux/fs.h
@@ -0,0 +1,185 @@
+/*
+ * This file has definitions for some important file table
+ * structures etc.
+ */
+
+#ifndef _FS_H
+#define _FS_H
+
+#include <sys/types.h>
+
+/* devices are as follows: (same as minix, so we can use the minix
+ * file system. These are major numbers.)
+ *
+ * 0 - unused (nodev)
+ * 1 - /dev/mem
+ * 2 - /dev/fd
+ * 3 - /dev/hd
+ * 4 - /dev/ttyx
+ * 5 - /dev/tty
+ * 6 - /dev/lp
+ * 7 - unnamed pipes
+ */
+
+#define IS_BLOCKDEV(x) ((x)==2 || (x)==3)
+
+#define READ 0
+#define WRITE 1
+
+void buffer_init(void);
+
+#define MAJOR(a) (((unsigned)(a))>>8)
+#define MINOR(a) ((a)&0xff)
+
+#define NAME_LEN 14
+
+#define I_MAP_SLOTS 8
+#define Z_MAP_SLOTS 8
+#define SUPER_MAGIC 0x137F
+
+#define NR_OPEN 20
+#define NR_INODE 32
+#define NR_FILE 64
+#define NR_SUPER 8
+#define NR_HASH 307
+#define NR_BUFFERS nr_buffers
+#define BLOCK_SIZE 1024
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode)))
+#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry)))
+
+typedef char buffer_block[BLOCK_SIZE];
+
+struct buffer_head {
+ char * b_data; /* pointer to data block (1024 bytes) */
+ unsigned short b_dev; /* device (0 = free) */
+ unsigned short b_blocknr; /* block number */
+ unsigned char b_uptodate;
+ unsigned char b_dirt; /* 0-clean,1-dirty */
+ unsigned char b_count; /* users using this block */
+ unsigned char b_lock; /* 0 - ok, 1 -locked */
+ struct task_struct * b_wait;
+ struct buffer_head * b_prev;
+ struct buffer_head * b_next;
+ struct buffer_head * b_prev_free;
+ struct buffer_head * b_next_free;
+};
+
+struct d_inode {
+ unsigned short i_mode;
+ unsigned short i_uid;
+ unsigned long i_size;
+ unsigned long i_time;
+ unsigned char i_gid;
+ unsigned char i_nlinks;
+ unsigned short i_zone[9];
+};
+
+struct m_inode {
+ unsigned short i_mode;
+ unsigned short i_uid;
+ unsigned long i_size;
+ unsigned long i_mtime;
+ unsigned char i_gid;
+ unsigned char i_nlinks;
+ unsigned short i_zone[9];
+/* these are in memory also */
+ struct task_struct * i_wait;
+ unsigned long i_atime;
+ unsigned long i_ctime;
+ unsigned short i_dev;
+ unsigned short i_num;
+ unsigned short i_count;
+ unsigned char i_lock;
+ unsigned char i_dirt;
+ unsigned char i_pipe;
+ unsigned char i_mount;
+ unsigned char i_seek;
+ unsigned char i_update;
+};
+
+#define PIPE_HEAD(inode) (((long *)((inode).i_zone))[0])
+#define PIPE_TAIL(inode) (((long *)((inode).i_zone))[1])
+#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1))
+#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
+#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
+#define INC_PIPE(head) \
+__asm__("incl %0\n\tandl $4095,%0"::"m" (head))
+
+struct file {
+ unsigned short f_mode;
+ unsigned short f_flags;
+ unsigned short f_count;
+ struct m_inode * f_inode;
+ off_t f_pos;
+};
+
+struct super_block {
+ unsigned short s_ninodes;
+ unsigned short s_nzones;
+ unsigned short s_imap_blocks;
+ unsigned short s_zmap_blocks;
+ unsigned short s_firstdatazone;
+ unsigned short s_log_zone_size;
+ unsigned long s_max_size;
+ unsigned short s_magic;
+/* These are only in memory */
+ struct buffer_head * s_imap[8];
+ struct buffer_head * s_zmap[8];
+ unsigned short s_dev;
+ struct m_inode * s_isup;
+ struct m_inode * s_imount;
+ unsigned long s_time;
+ unsigned char s_rd_only;
+ unsigned char s_dirt;
+};
+
+struct dir_entry {
+ unsigned short inode;
+ char name[NAME_LEN];
+};
+
+extern struct m_inode inode_table[NR_INODE];
+extern struct file file_table[NR_FILE];
+extern struct super_block super_block[NR_SUPER];
+extern struct buffer_head * start_buffer;
+extern int nr_buffers;
+
+extern void truncate(struct m_inode * inode);
+extern void sync_inodes(void);
+extern void wait_on(struct m_inode * inode);
+extern int bmap(struct m_inode * inode,int block);
+extern int create_block(struct m_inode * inode,int block);
+extern struct m_inode * namei(const char * pathname);
+extern int open_namei(const char * pathname, int flag, int mode,
+ struct m_inode ** res_inode);
+extern void iput(struct m_inode * inode);
+extern struct m_inode * iget(int dev,int nr);
+extern struct m_inode * get_empty_inode(void);
+extern struct m_inode * get_pipe_inode(void);
+extern struct buffer_head * get_hash_table(int dev, int block);
+extern struct buffer_head * getblk(int dev, int block);
+extern void ll_rw_block(int rw, struct buffer_head * bh);
+extern void brelse(struct buffer_head * buf);
+extern struct buffer_head * bread(int dev,int block);
+extern int new_block(int dev);
+extern void free_block(int dev, int block);
+extern struct m_inode * new_inode(int dev);
+extern void free_inode(struct m_inode * inode);
+
+extern void mount_root(void);
+
+extern inline struct super_block * get_super(int dev)
+{
+ struct super_block * s;
+
+ for(s = 0+super_block;s < NR_SUPER+super_block; s++)
+ if (s->s_dev == dev)
+ return s;
+ return NULL;
+}
+
+#endif
diff --git a/linux/include/linux/hdreg.h b/linux/include/linux/hdreg.h
new file mode 100644
index 0000000..04ebf87
--- /dev/null
+++ b/linux/include/linux/hdreg.h
@@ -0,0 +1,99 @@
+/*
+ * This file contains some defines for the AT-hd-controller.
+ * Various sources. Check out some definitions (see comments with
+ * a ques).
+ */
+#ifndef _HDREG_H
+#define _HDREG_H
+
+/* currently supports only 1 hd, put type here */
+#define HARD_DISK_TYPE 17
+
+/*
+ * Ok, hard-disk-type is currently hardcoded. Not beatiful,
+ * but easier. We don't use BIOS for anything else, why should
+ * we get HD-type from it? Get these values from Reference Guide.
+ */
+
+#if HARD_DISK_TYPE == 17
+#define _CYL 977
+#define _HEAD 5
+#define __WPCOM 300
+#define _LZONE 977
+#define _SECT 17
+#define _CTL 0
+#elif HARD_DISK_TYPE == 18
+#define _CYL 977
+#define _HEAD 7
+#define __WPCOM (-1)
+#define _LZONE 977
+#define _SECT 17
+#define _CTL 0
+#else
+#error Define HARD_DISK_TYPE and parameters, add your own entries as well
+#endif
+
+/* Controller wants just wp-com/4 */
+#if __WPCOM >= 0
+#define _WPCOM ((__WPCOM)>>2)
+#else
+#define _WPCOM __WPCOM
+#endif
+
+/* Hd controller regs. Ref: IBM AT Bios-listing */
+#define HD_DATA 0x1f0 /* _CTL when writing */
+#define HD_ERROR 0x1f1 /* see err-bits */
+#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */
+#define HD_SECTOR 0x1f3 /* starting sector */
+#define HD_LCYL 0x1f4 /* starting cylinder */
+#define HD_HCYL 0x1f5 /* high byte of starting cyl */
+#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS 0x1f7 /* see status-bits */
+#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */
+#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
+
+#define HD_CMD 0x3f6
+
+/* Bits of HD_STATUS */
+#define ERR_STAT 0x01
+#define INDEX_STAT 0x02
+#define ECC_STAT 0x04 /* Corrected error */
+#define DRQ_STAT 0x08
+#define SEEK_STAT 0x10
+#define WRERR_STAT 0x20
+#define READY_STAT 0x40
+#define BUSY_STAT 0x80
+
+/* Values for HD_COMMAND */
+#define WIN_RESTORE 0x10
+#define WIN_READ 0x20
+#define WIN_WRITE 0x30
+#define WIN_VERIFY 0x40
+#define WIN_FORMAT 0x50
+#define WIN_INIT 0x60
+#define WIN_SEEK 0x70
+#define WIN_DIAGNOSE 0x90
+#define WIN_SPECIFY 0x91
+
+/* Bits for HD_ERROR */
+#define MARK_ERR 0x01 /* Bad address mark ? */
+#define TRK0_ERR 0x02 /* couldn't find track 0 */
+#define ABRT_ERR 0x04 /* ? */
+#define ID_ERR 0x10 /* ? */
+#define ECC_ERR 0x40 /* ? */
+#define BBD_ERR 0x80 /* ? */
+
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active (unused) */
+ unsigned char head; /* ? */
+ unsigned char sector; /* ? */
+ unsigned char cyl; /* ? */
+ unsigned char sys_ind; /* ? */
+ unsigned char end_head; /* ? */
+ unsigned char end_sector; /* ? */
+ unsigned char end_cyl; /* ? */
+ unsigned int start_sect; /* starting sector counting from 0 */
+ unsigned int nr_sects; /* nr of sectors in partition */
+};
+
+#endif
diff --git a/linux/include/linux/head.h b/linux/include/linux/head.h
new file mode 100644
index 0000000..db3dda2
--- /dev/null
+++ b/linux/include/linux/head.h
@@ -0,0 +1,20 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+
+typedef struct desc_struct {
+ unsigned long a,b;
+} desc_table[256];
+
+extern unsigned long pg_dir[1024];
+extern desc_table idt,gdt;
+
+#define GDT_NUL 0
+#define GDT_CODE 1
+#define GDT_DATA 2
+#define GDT_TMP 3
+
+#define LDT_NUL 0
+#define LDT_CODE 1
+#define LDT_DATA 2
+
+#endif
diff --git a/linux/include/linux/kernel.h b/linux/include/linux/kernel.h
new file mode 100644
index 0000000..9e533a7
--- /dev/null
+++ b/linux/include/linux/kernel.h
@@ -0,0 +1,8 @@
+/*
+ * 'kernel.h' contains some often-used function prototypes etc
+ */
+void verify_area(void * addr,int count);
+volatile void panic(const char * str);
+int printf(const char * fmt, ...);
+int printk(const char * fmt, ...);
+int tty_write(unsigned ch,char * buf,int count);
diff --git a/linux/include/linux/mm.h b/linux/include/linux/mm.h
new file mode 100644
index 0000000..5a160f3
--- /dev/null
+++ b/linux/include/linux/mm.h
@@ -0,0 +1,10 @@
+#ifndef _MM_H
+#define _MM_H
+
+#define PAGE_SIZE 4096
+
+extern unsigned long get_free_page(void);
+extern unsigned long put_page(unsigned long page,unsigned long address);
+extern void free_page(unsigned long addr);
+
+#endif
diff --git a/linux/include/linux/sched.h b/linux/include/linux/sched.h
new file mode 100644
index 0000000..bf6b639
--- /dev/null
+++ b/linux/include/linux/sched.h
@@ -0,0 +1,230 @@
+#ifndef _SCHED_H
+#define _SCHED_H
+
+#define NR_TASKS 64
+#define HZ 100
+
+#define FIRST_TASK task[0]
+#define LAST_TASK task[NR_TASKS-1]
+
+#include <linux/head.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+
+#if (NR_OPEN > 32)
+#error "Currently the close-on-exec-flags are in one word, max 32 files/proc"
+#endif
+
+#define TASK_RUNNING 0
+#define TASK_INTERRUPTIBLE 1
+#define TASK_UNINTERRUPTIBLE 2
+#define TASK_ZOMBIE 3
+#define TASK_STOPPED 4
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern int copy_page_tables(unsigned long from, unsigned long to, long size);
+extern int free_page_tables(unsigned long from, long size);
+
+extern void sched_init(void);
+extern void schedule(void);
+extern void trap_init(void);
+extern void panic(const char * str);
+extern int tty_write(unsigned minor,char * buf,int count);
+
+typedef int (*fn_ptr)();
+
+struct i387_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+struct tss_struct {
+ long back_link; /* 16 high bits zero */
+ long esp0;
+ long ss0; /* 16 high bits zero */
+ long esp1;
+ long ss1; /* 16 high bits zero */
+ long esp2;
+ long ss2; /* 16 high bits zero */
+ long cr3;
+ long eip;
+ long eflags;
+ long eax,ecx,edx,ebx;
+ long esp;
+ long ebp;
+ long esi;
+ long edi;
+ long es; /* 16 high bits zero */
+ long cs; /* 16 high bits zero */
+ long ss; /* 16 high bits zero */
+ long ds; /* 16 high bits zero */
+ long fs; /* 16 high bits zero */
+ long gs; /* 16 high bits zero */
+ long ldt; /* 16 high bits zero */
+ long trace_bitmap; /* bits: trace 0, bitmap 16-31 */
+ struct i387_struct i387;
+};
+
+struct task_struct {
+/* these are hardcoded - don't touch */
+ long state; /* -1 unrunnable, 0 runnable, >0 stopped */
+ long counter;
+ long priority;
+ long signal;
+ fn_ptr sig_restorer;
+ fn_ptr sig_fn[32];
+/* various fields */
+ int exit_code;
+ unsigned long end_code,end_data,brk,start_stack;
+ long pid,father,pgrp,session,leader;
+ unsigned short uid,euid,suid;
+ unsigned short gid,egid,sgid;
+ long alarm;
+ long utime,stime,cutime,cstime,start_time;
+ unsigned short used_math;
+/* file system info */
+ int tty; /* -1 if no tty, so it must be signed */
+ unsigned short umask;
+ struct m_inode * pwd;
+ struct m_inode * root;
+ unsigned long close_on_exec;
+ struct file * filp[NR_OPEN];
+/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
+ struct desc_struct ldt[3];
+/* tss for this task */
+ struct tss_struct tss;
+};
+
+/*
+ * INIT_TASK is used to set up the first task table, touch at
+ * your own risk!. Base=0, limit=0x9ffff (=640kB)
+ */
+#define INIT_TASK \
+/* state etc */ { 0,15,15, \
+/* signals */ 0,NULL,{(fn_ptr) 0,}, \
+/* ec,brk... */ 0,0,0,0,0, \
+/* pid etc.. */ 0,-1,0,0,0, \
+/* uid etc */ 0,0,0,0,0,0, \
+/* alarm */ 0,0,0,0,0,0, \
+/* math */ 0, \
+/* fs info */ -1,0133,NULL,NULL,0, \
+/* filp */ {NULL,}, \
+ { \
+ {0,0}, \
+/* ldt */ {0x9f,0xc0fa00}, \
+ {0x9f,0xc0f200}, \
+ }, \
+/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
+ 0,0,0,0,0,0,0,0, \
+ 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
+ _LDT(0),0x80000000, \
+ {} \
+ }, \
+}
+
+extern struct task_struct *task[NR_TASKS];
+extern struct task_struct *last_task_used_math;
+extern struct task_struct *current;
+extern long volatile jiffies;
+extern long startup_time;
+
+#define CURRENT_TIME (startup_time+jiffies/HZ)
+
+extern void sleep_on(struct task_struct ** p);
+extern void interruptible_sleep_on(struct task_struct ** p);
+extern void wake_up(struct task_struct ** p);
+
+/*
+ * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
+ * 4-TSS0, 5-LDT0, 6-TSS1 etc ...
+ */
+#define FIRST_TSS_ENTRY 4
+#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
+#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
+#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
+#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n)))
+#define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n)))
+#define str(n) \
+__asm__("str %%ax\n\t" \
+ "subl %2,%%eax\n\t" \
+ "shrl $4,%%eax" \
+ :"=a" (n) \
+ :"a" (0),"i" (FIRST_TSS_ENTRY<<3))
+/*
+ * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ * This also clears the TS-flag if the task we switched to has used
+ * tha math co-processor latest.
+ */
+#define switch_to(n) {\
+struct {long a,b;} __tmp; \
+__asm__("cmpl %%ecx,_current\n\t" \
+ "je 1f\n\t" \
+ "xchgl %%ecx,_current\n\t" \
+ "movw %%dx,%1\n\t" \
+ "ljmp %0\n\t" \
+ "cmpl %%ecx,%2\n\t" \
+ "jne 1f\n\t" \
+ "clts\n" \
+ "1:" \
+ ::"m" (*&__tmp.a),"m" (*&__tmp.b), \
+ "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \
+}
+
+#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000)
+
+#define _set_base(addr,base) \
+__asm__("movw %%dx,%0\n\t" \
+ "rorl $16,%%edx\n\t" \
+ "movb %%dl,%1\n\t" \
+ "movb %%dh,%2" \
+ ::"m" (*((addr)+2)), \
+ "m" (*((addr)+4)), \
+ "m" (*((addr)+7)), \
+ "d" (base) \
+ :"dx")
+
+#define _set_limit(addr,limit) \
+__asm__("movw %%dx,%0\n\t" \
+ "rorl $16,%%edx\n\t" \
+ "movb %1,%%dh\n\t" \
+ "andb $0xf0,%%dh\n\t" \
+ "orb %%dh,%%dl\n\t" \
+ "movb %%dl,%1" \
+ ::"m" (*(addr)), \
+ "m" (*((addr)+6)), \
+ "d" (limit) \
+ :"dx")
+
+#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
+#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
+
+#define _get_base(addr) ({\
+unsigned long __base; \
+__asm__("movb %3,%%dh\n\t" \
+ "movb %2,%%dl\n\t" \
+ "shll $16,%%edx\n\t" \
+ "movw %1,%%dx" \
+ :"=d" (__base) \
+ :"m" (*((addr)+2)), \
+ "m" (*((addr)+4)), \
+ "m" (*((addr)+7))); \
+__base;})
+
+#define get_base(ldt) _get_base( ((char *)&(ldt)) )
+
+#define get_limit(segment) ({ \
+unsigned long __limit; \
+__asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \
+__limit;})
+
+#endif
diff --git a/linux/include/linux/sys.h b/linux/include/linux/sys.h
new file mode 100644
index 0000000..acdcc95
--- /dev/null
+++ b/linux/include/linux/sys.h
@@ -0,0 +1,80 @@
+extern int sys_setup();
+extern int sys_exit();
+extern int sys_fork();
+extern int sys_read();
+extern int sys_write();
+extern int sys_open();
+extern int sys_close();
+extern int sys_waitpid();
+extern int sys_creat();
+extern int sys_link();
+extern int sys_unlink();
+extern int sys_execve();
+extern int sys_chdir();
+extern int sys_time();
+extern int sys_mknod();
+extern int sys_chmod();
+extern int sys_chown();
+extern int sys_break();
+extern int sys_stat();
+extern int sys_lseek();
+extern int sys_getpid();
+extern int sys_mount();
+extern int sys_umount();
+extern int sys_setuid();
+extern int sys_getuid();
+extern int sys_stime();
+extern int sys_ptrace();
+extern int sys_alarm();
+extern int sys_fstat();
+extern int sys_pause();
+extern int sys_utime();
+extern int sys_stty();
+extern int sys_gtty();
+extern int sys_access();
+extern int sys_nice();
+extern int sys_ftime();
+extern int sys_sync();
+extern int sys_kill();
+extern int sys_rename();
+extern int sys_mkdir();
+extern int sys_rmdir();
+extern int sys_dup();
+extern int sys_pipe();
+extern int sys_times();
+extern int sys_prof();
+extern int sys_brk();
+extern int sys_setgid();
+extern int sys_getgid();
+extern int sys_signal();
+extern int sys_geteuid();
+extern int sys_getegid();
+extern int sys_acct();
+extern int sys_phys();
+extern int sys_lock();
+extern int sys_ioctl();
+extern int sys_fcntl();
+extern int sys_mpx();
+extern int sys_setpgid();
+extern int sys_ulimit();
+extern int sys_uname();
+extern int sys_umask();
+extern int sys_chroot();
+extern int sys_ustat();
+extern int sys_dup2();
+extern int sys_getppid();
+extern int sys_getpgrp();
+extern int sys_setsid();
+
+fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
+sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
+sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
+sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
+sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
+sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
+sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
+sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
+sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
+sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
+sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
+sys_getpgrp,sys_setsid};
diff --git a/linux/include/linux/tty.h b/linux/include/linux/tty.h
new file mode 100644
index 0000000..1d103e0
--- /dev/null
+++ b/linux/include/linux/tty.h
@@ -0,0 +1,74 @@
+/*
+ * 'tty.h' defines some structures used by tty_io.c and some defines.
+ *
+ * NOTE! Don't touch this without checking that nothing in rs_io.s or
+ * con_io.s breaks. Some constants are hardwired into the system (mainly
+ * offsets into 'tty_queue'
+ */
+
+#ifndef _TTY_H
+#define _TTY_H
+
+#include <termios.h>
+
+#define TTY_BUF_SIZE 1024
+
+struct tty_queue {
+ unsigned long data;
+ unsigned long head;
+ unsigned long tail;
+ struct task_struct * proc_list;
+ char buf[TTY_BUF_SIZE];
+};
+
+#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
+#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
+#define EMPTY(a) ((a).head == (a).tail)
+#define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1))
+#define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)])
+#define FULL(a) (!LEFT(a))
+#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1))
+#define GETCH(queue,c) \
+(void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
+#define PUTCH(c,queue) \
+(void)({(queue).buf[(queue).head]=(c);INC((queue).head);})
+
+#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
+#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
+#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
+#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
+#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
+
+struct tty_struct {
+ struct termios termios;
+ int pgrp;
+ int stopped;
+ void (*write)(struct tty_struct * tty);
+ struct tty_queue read_q;
+ struct tty_queue write_q;
+ struct tty_queue secondary;
+ };
+
+extern struct tty_struct tty_table[];
+
+/* intr=^C quit=^| erase=del kill=^U
+ eof=^D vtime=\0 vmin=\1 sxtc=\0
+ start=^Q stop=^S susp=^Y eol=\0
+ reprint=^R discard=^U werase=^W lnext=^V
+ eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\031\0\022\017\027\026\0"
+
+void rs_init(void);
+void con_init(void);
+void tty_init(void);
+
+int tty_read(unsigned c, char * buf, int n);
+int tty_write(unsigned c, char * buf, int n);
+
+void rs_write(struct tty_struct * tty);
+void con_write(struct tty_struct * tty);
+
+void copy_to_cooked(struct tty_struct * tty);
+
+#endif
diff --git a/linux/include/signal.h b/linux/include/signal.h
new file mode 100644
index 0000000..b895813
--- /dev/null
+++ b/linux/include/signal.h
@@ -0,0 +1,65 @@
+#ifndef _SIGNAL_H
+#define _SIGNAL_H
+
+#include <sys/types.h>
+
+typedef int sig_atomic_t;
+typedef unsigned int sigset_t; /* 32 bits */
+
+#define _NSIG 32
+#define NSIG _NSIG
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGUNUSED 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+
+/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
+#define SA_NOCLDSTOP 1
+
+#define SIG_BLOCK 0 /* for blocking signals */
+#define SIG_UNBLOCK 1 /* for unblocking signals */
+#define SIG_SETMASK 2 /* for setting the signal mask */
+
+#define SIG_DFL ((void (*)(int))0) /* default signal handling */
+#define SIG_IGN ((void (*)(int))1) /* ignore signal */
+
+struct sigaction {
+ void (*sa_handler)(int);
+ sigset_t sa_mask;
+ int sa_flags;
+};
+
+void (*signal(int _sig, void (*_func)(int)))(int);
+int raise(int sig);
+int kill(pid_t pid, int sig);
+int sigaddset(sigset_t *mask, int signo);
+int sigdelset(sigset_t *mask, int signo);
+int sigemptyset(sigset_t *mask);
+int sigfillset(sigset_t *mask);
+int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */
+int sigpending(sigset_t *set);
+int sigprocmask(int how, sigset_t *set, sigset_t *oldset);
+int sigsuspend(sigset_t *sigmask);
+int sigaction(int sig, struct sigaction *act, struct sigaction *oldact);
+
+#endif /* _SIGNAL_H */
diff --git a/linux/include/stdarg.h b/linux/include/stdarg.h
new file mode 100755
index 0000000..fd79ec0
--- /dev/null
+++ b/linux/include/stdarg.h
@@ -0,0 +1,28 @@
+#ifndef _STDARG_H
+#define _STDARG_H
+
+typedef char *va_list;
+
+/* Amount of space required in an argument list for an arg of type TYPE.
+ TYPE may alternatively be an expression whose type is used. */
+
+#define __va_rounded_size(TYPE) \
+ (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
+
+#ifndef __sparc__
+#define va_start(AP, LASTARG) \
+ (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
+#else
+#define va_start(AP, LASTARG) \
+ (__builtin_saveregs (), \
+ AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
+#endif
+
+void va_end (va_list); /* Defined in gnulib */
+#define va_end(AP)
+
+#define va_arg(AP, TYPE) \
+ (AP += __va_rounded_size (TYPE), \
+ *((TYPE *) (AP - __va_rounded_size (TYPE))))
+
+#endif /* _STDARG_H */
diff --git a/linux/include/stddef.h b/linux/include/stddef.h
new file mode 100644
index 0000000..97f72ff
--- /dev/null
+++ b/linux/include/stddef.h
@@ -0,0 +1,19 @@
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef long ptrdiff_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned long size_t;
+#endif
+
+#undef NULL
+#define NULL ((void *)0)
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif
diff --git a/linux/include/string.h b/linux/include/string.h
new file mode 100644
index 0000000..05a6d9c
--- /dev/null
+++ b/linux/include/string.h
@@ -0,0 +1,405 @@
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+extern char * strerror(int errno);
+
+/*
+ * This string-include defines all string functions as inline
+ * functions. Use gcc. It also assumes ds=es=data space, this should be
+ * normal. Most of the string-functions are rather heavily hand-optimized,
+ * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+extern inline char * strcpy(char * dest,const char *src)
+{
+__asm__("cld\n"
+ "1:\tlodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b"
+ ::"S" (src),"D" (dest):"si","di","ax");
+return dest;
+}
+
+extern inline char * strncpy(char * dest,const char *src,int count)
+{
+__asm__("cld\n"
+ "1:\tdecl %2\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "rep\n\t"
+ "stosb\n"
+ "2:"
+ ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx");
+return dest;
+}
+
+extern inline char * strcat(char * dest,const char * src)
+{
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "decl %1\n"
+ "1:\tlodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b"
+ ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
+return dest;
+}
+
+extern inline char * strncat(char * dest,const char * src,int count)
+{
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "decl %1\n\t"
+ "movl %4,%3\n"
+ "1:\tdecl %3\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n"
+ "2:\txorl %2,%2\n\t"
+ "stosb"
+ ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
+ :"si","di","ax","cx");
+return dest;
+}
+
+extern inline int strcmp(const char * cs,const char * ct)
+{
+register int __res __asm__("ax");
+__asm__("cld\n"
+ "1:\tlodsb\n\t"
+ "scasb\n\t"
+ "jne 2f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "xorl %%eax,%%eax\n\t"
+ "jmp 3f\n"
+ "2:\tmovl $1,%%eax\n\t"
+ "jl 3f\n\t"
+ "negl %%eax\n"
+ "3:"
+ :"=a" (__res):"D" (cs),"S" (ct):"si","di");
+return __res;
+}
+
+extern inline int strncmp(const char * cs,const char * ct,int count)
+{
+register int __res __asm__("ax");
+__asm__("cld\n"
+ "1:\tdecl %3\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "scasb\n\t"
+ "jne 3f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n"
+ "2:\txorl %%eax,%%eax\n\t"
+ "jmp 4f\n"
+ "3:\tmovl $1,%%eax\n\t"
+ "jl 4f\n\t"
+ "negl %%eax\n"
+ "4:"
+ :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
+return __res;
+}
+
+extern inline char * strchr(const char * s,char c)
+{
+register char * __res __asm__("ax");
+__asm__("cld\n\t"
+ "movb %%al,%%ah\n"
+ "1:\tlodsb\n\t"
+ "cmpb %%ah,%%al\n\t"
+ "je 2f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "movl $1,%1\n"
+ "2:\tmovl %1,%0\n\t"
+ "decl %0"
+ :"=a" (__res):"S" (s),"0" (c):"si");
+return __res;
+}
+
+extern inline char * strrchr(const char * s,char c)
+{
+register char * __res __asm__("dx");
+__asm__("cld\n\t"
+ "movb %%al,%%ah\n"
+ "1:\tlodsb\n\t"
+ "cmpb %%ah,%%al\n\t"
+ "jne 2f\n\t"
+ "movl %%esi,%0\n\t"
+ "decl %0\n"
+ "2:\ttestb %%al,%%al\n\t"
+ "jne 1b"
+ :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
+return __res;
+}
+
+extern inline int strspn(const char * cs, const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "movl %%ecx,%%edx\n"
+ "1:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 2f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "je 1b\n"
+ "2:\tdecl %0"
+ :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+ :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline int strcspn(const char * cs, const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "movl %%ecx,%%edx\n"
+ "1:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 2f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "jne 1b\n"
+ "2:\tdecl %0"
+ :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+ :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline char * strpbrk(const char * cs,const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "movl %%ecx,%%edx\n"
+ "1:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 2f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "jne 1b\n\t"
+ "decl %0\n\t"
+ "jmp 3f\n"
+ "2:\txorl %0,%0\n"
+ "3:"
+ :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+ :"ax","cx","dx","di");
+return __res;
+}
+
+extern inline char * strstr(const char * cs,const char * ct)
+{
+register char * __res __asm__("ax");
+__asm__("cld\n\t" \
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
+ "movl %%ecx,%%edx\n"
+ "1:\tmovl %4,%%edi\n\t"
+ "movl %%esi,%%eax\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repe\n\t"
+ "cmpsb\n\t"
+ "je 2f\n\t" /* also works for empty string, see above */
+ "xchgl %%eax,%%esi\n\t"
+ "incl %%esi\n\t"
+ "cmpb $0,-1(%%eax)\n\t"
+ "jne 1b\n\t"
+ "xorl %%eax,%%eax\n\t"
+ "2:"
+ :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
+ :"cx","dx","di","si");
+return __res;
+}
+
+extern inline int strlen(const char * s)
+{
+register int __res __asm__("cx");
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %0\n\t"
+ "decl %0"
+ :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
+return __res;
+}
+
+extern char * ___strtok;
+
+extern inline char * strtok(char * s,const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("testl %1,%1\n\t"
+ "jne 1f\n\t"
+ "testl %0,%0\n\t"
+ "je 8f\n\t"
+ "movl %0,%1\n"
+ "1:\txorl %0,%0\n\t"
+ "movl $-1,%%ecx\n\t"
+ "xorl %%eax,%%eax\n\t"
+ "cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "je 7f\n\t" /* empty delimeter-string */
+ "movl %%ecx,%%edx\n"
+ "2:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 7f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "je 2b\n\t"
+ "decl %1\n\t"
+ "cmpb $0,(%1)\n\t"
+ "je 7f\n\t"
+ "movl %1,%0\n"
+ "3:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 5f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "jne 3b\n\t"
+ "decl %1\n\t"
+ "cmpb $0,(%1)\n\t"
+ "je 5f\n\t"
+ "movb $0,(%1)\n\t"
+ "incl %1\n\t"
+ "jmp 6f\n"
+ "5:\txorl %1,%1\n"
+ "6:\tcmpb $0,(%0)\n\t"
+ "jne 7f\n\t"
+ "xorl %0,%0\n"
+ "7:\ttestl %0,%0\n\t"
+ "jne 8f\n\t"
+ "movl %0,%1\n"
+ "8:"
+ :"=b" (__res),"=S" (___strtok)
+ :"0" (___strtok),"1" (s),"g" (ct)
+ :"ax","cx","dx","di");
+return __res;
+}
+
+extern inline void * memcpy(void * dest,const void * src, int n)
+{
+__asm__("cld\n\t"
+ "rep\n\t"
+ "movsb"
+ ::"c" (n),"S" (src),"D" (dest)
+ :"cx","si","di");
+return dest;
+}
+
+extern inline void * memmove(void * dest,const void * src, int n)
+{
+if (dest<src)
+__asm__("cld\n\t"
+ "rep\n\t"
+ "movsb"
+ ::"c" (n),"S" (src),"D" (dest)
+ :"cx","si","di");
+else
+__asm__("std\n\t"
+ "rep\n\t"
+ "movsb"
+ ::"c" (n),"S" (src+n-1),"D" (dest+n-1)
+ :"cx","si","di");
+return dest;
+}
+
+extern inline int memcmp(const void * cs,const void * ct,int count)
+{
+register int __res __asm__("ax");
+__asm__("cld\n\t"
+ "repe\n\t"
+ "cmpsb\n\t"
+ "je 1f\n\t"
+ "movl $1,%%eax\n\t"
+ "jl 1f\n\t"
+ "negl %%eax\n"
+ "1:"
+ :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
+ :"si","di","cx");
+return __res;
+}
+
+extern inline void * memchr(const void * cs,char c,int count)
+{
+register void * __res __asm__("di");
+if (!count)
+ return NULL;
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "je 1f\n\t"
+ "movl $1,%0\n"
+ "1:\tdecl %0"
+ :"=D" (__res):"a" (c),"D" (cs),"c" (count)
+ :"cx");
+return __res;
+}
+
+extern inline void * memset(void * s,char c,int count)
+{
+__asm__("cld\n\t"
+ "rep\n\t"
+ "stosb"
+ ::"a" (c),"D" (s),"c" (count)
+ :"cx","di");
+return s;
+}
+
+#endif
diff --git a/linux/include/sys/stat.h b/linux/include/sys/stat.h
new file mode 100644
index 0000000..41c3840
--- /dev/null
+++ b/linux/include/sys/stat.h
@@ -0,0 +1,58 @@
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <sys/types.h>
+
+struct stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ umode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ time_t st_atime;
+ time_t st_mtime;
+ time_t st_ctime;
+};
+
+#define S_IFMT 00170000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+extern int chmod(const char *_path, mode_t mode);
+extern int fstat(int fildes, struct stat *stat_buf);
+extern int mkdir(const char *_path, mode_t mode);
+extern int mkfifo(const char *_path, mode_t mode);
+extern int stat(const char *filename, struct stat *stat_buf);
+extern mode_t umask(mode_t mask);
+
+#endif
diff --git a/linux/include/sys/times.h b/linux/include/sys/times.h
new file mode 100644
index 0000000..68d5bfb
--- /dev/null
+++ b/linux/include/sys/times.h
@@ -0,0 +1,15 @@
+#ifndef _TIMES_H
+#define _TIMES_H
+
+#include <sys/types.h>
+
+struct tms {
+ time_t tms_utime;
+ time_t tms_stime;
+ time_t tms_cutime;
+ time_t tms_cstime;
+};
+
+extern time_t times(struct tms * tp);
+
+#endif
diff --git a/linux/include/sys/types.h b/linux/include/sys/types.h
new file mode 100644
index 0000000..557aa31
--- /dev/null
+++ b/linux/include/sys/types.h
@@ -0,0 +1,46 @@
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef long ptrdiff_t;
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+typedef int pid_t;
+typedef unsigned short uid_t;
+typedef unsigned char gid_t;
+typedef unsigned short dev_t;
+typedef unsigned short ino_t;
+typedef unsigned short mode_t;
+typedef unsigned short umode_t;
+typedef unsigned char nlink_t;
+typedef int daddr_t;
+typedef long off_t;
+typedef unsigned char u_char;
+typedef unsigned short ushort;
+
+typedef struct { int quot,rem; } div_t;
+typedef struct { long quot,rem; } ldiv_t;
+
+struct ustat {
+ daddr_t f_tfree;
+ ino_t f_tinode;
+ char f_fname[6];
+ char f_fpack[6];
+};
+
+#endif
diff --git a/linux/include/sys/utsname.h b/linux/include/sys/utsname.h
new file mode 100644
index 0000000..0a1c5a0
--- /dev/null
+++ b/linux/include/sys/utsname.h
@@ -0,0 +1,16 @@
+#ifndef _SYS_UTSNAME_H
+#define _SYS_UTSNAME_H
+
+#include <sys/types.h>
+
+struct utsname {
+ char sysname[9];
+ char nodename[9];
+ char release[9];
+ char version[9];
+ char machine[9];
+};
+
+extern int uname(struct utsname * utsbuf);
+
+#endif
diff --git a/linux/include/sys/wait.h b/linux/include/sys/wait.h
new file mode 100644
index 0000000..53190c2
--- /dev/null
+++ b/linux/include/sys/wait.h
@@ -0,0 +1,23 @@
+#ifndef _SYS_WAIT_H
+#define _SYS_WAIT_H
+
+#include <sys/types.h>
+
+#define _LOW(v) ( (v) & 0377)
+#define _HIGH(v) ( ((v) >> 8) & 0377)
+
+/* options for waitpid, WUNTRACED not supported */
+#define WNOHANG 1
+#define WUNTRACED 2
+
+#define WIFEXITED(s) (!((s)&0xFF)
+#define WIFSTOPPED(s) (((s)&0xFF)==0x7F)
+#define WEXITSTATUS(s) (((s)>>8)&0xFF)
+#define WTERMSIG(s) ((s)&0x7F)
+#define WSTOPSIG(s) (((s)>>8)&0xFF)
+#define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF)
+
+pid_t wait(int *stat_loc);
+pid_t waitpid(pid_t pid, int *stat_loc, int options);
+
+#endif
diff --git a/linux/include/termios.h b/linux/include/termios.h
new file mode 100644
index 0000000..f707674
--- /dev/null
+++ b/linux/include/termios.h
@@ -0,0 +1,222 @@
+#ifndef _TERMIOS_H
+#define _TERMIOS_H
+
+#define TTY_BUF_SIZE 1024
+
+/* 0x54 is just a magic number to make these relatively uniqe ('T') */
+
+#define TCGETS 0x5401
+#define TCSETS 0x5402
+#define TCSETSW 0x5403
+#define TCSETSF 0x5404
+#define TCGETA 0x5405
+#define TCSETA 0x5406
+#define TCSETAW 0x5407
+#define TCSETAF 0x5408
+#define TCSBRK 0x5409
+#define TCXONC 0x540A
+#define TCFLSH 0x540B
+#define TIOCEXCL 0x540C
+#define TIOCNXCL 0x540D
+#define TIOCSCTTY 0x540E
+#define TIOCGPGRP 0x540F
+#define TIOCSPGRP 0x5410
+#define TIOCOUTQ 0x5411
+#define TIOCSTI 0x5412
+#define TIOCGWINSZ 0x5413
+#define TIOCSWINSZ 0x5414
+#define TIOCMGET 0x5415
+#define TIOCMBIS 0x5416
+#define TIOCMBIC 0x5417
+#define TIOCMSET 0x5418
+#define TIOCGSOFTCAR 0x5419
+#define TIOCSSOFTCAR 0x541A
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+#define NCCS 17
+struct termios {
+ unsigned long c_iflag; /* input mode flags */
+ unsigned long c_oflag; /* output mode flags */
+ unsigned long c_cflag; /* control mode flags */
+ unsigned long c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCCS]; /* control characters */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK 0000020
+#define ISTRIP 0000040
+#define INLCR 0000100
+#define IGNCR 0000200
+#define ICRNL 0000400
+#define IUCLC 0001000
+#define IXON 0002000
+#define IXANY 0004000
+#define IXOFF 0010000
+#define IMAXBEL 0020000
+
+/* c_oflag bits */
+#define OPOST 0000001
+#define OLCUC 0000002
+#define ONLCR 0000004
+#define OCRNL 0000010
+#define ONOCR 0000020
+#define ONLRET 0000040
+#define OFILL 0000100
+#define OFDEL 0000200
+#define NLDLY 0000400
+#define NL0 0000000
+#define NL1 0000400
+#define CRDLY 0003000
+#define CR0 0000000
+#define CR1 0001000
+#define CR2 0002000
+#define CR3 0003000
+#define TABDLY 0014000
+#define TAB0 0000000
+#define TAB1 0004000
+#define TAB2 0010000
+#define TAB3 0014000
+#define XTABS 0014000
+#define BSDLY 0020000
+#define BS0 0000000
+#define BS1 0020000
+#define VTDLY 0040000
+#define VT0 0000000
+#define VT1 0040000
+#define FFDLY 0040000
+#define FF0 0000000
+#define FF1 0040000
+
+/* c_cflag bit meaning */
+#define CBAUD 0000017
+#define B0 0000000 /* hang up */
+#define B50 0000001
+#define B75 0000002
+#define B110 0000003
+#define B134 0000004
+#define B150 0000005
+#define B200 0000006
+#define B300 0000007
+#define B600 0000010
+#define B1200 0000011
+#define B1800 0000012
+#define B2400 0000013
+#define B4800 0000014
+#define B9600 0000015
+#define B19200 0000016
+#define B38400 0000017
+#define CSIZE 0000060
+#define CS5 0000000
+#define CS6 0000020
+#define CS7 0000040
+#define CS8 0000060
+#define CSTOPB 0000100
+#define CREAD 0000200
+#define CPARENB 0000400
+#define CPARODD 0001000
+#define HUPCL 0002000
+#define CLOCAL 0004000
+#define CIBAUD 03600000 /* input baud rate (not used) */
+#define CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+
+/* modem lines */
+#define TIOCM_LE 0x001
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_ST 0x008
+#define TIOCM_SR 0x010
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+
+/* tcflow() and TCXONC use these */
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
+/* tcflush() and TCFLSH use these */
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+
+/* tcsetattr uses these */
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+typedef int speed_t;
+
+extern speed_t cfgetispeed(struct termios *termios_p);
+extern speed_t cfgetospeed(struct termios *termios_p);
+extern int cfsetispeed(struct termios *termios_p, speed_t speed);
+extern int cfsetospeed(struct termios *termios_p, speed_t speed);
+extern int tcdrain(int fildes);
+extern int tcflow(int fildes, int action);
+extern int tcflush(int fildes, int queue_selector);
+extern int tcgetattr(int fildes, struct termios *termios_p);
+extern int tcsendbreak(int fildes, int duration);
+extern int tcsetattr(int fildes, int optional_actions,
+ struct termios *termios_p);
+
+#endif
diff --git a/linux/include/time.h b/linux/include/time.h
new file mode 100644
index 0000000..d0a765d
--- /dev/null
+++ b/linux/include/time.h
@@ -0,0 +1,42 @@
+#ifndef _TIME_H
+#define _TIME_H
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#define CLOCKS_PER_SEC 100
+
+typedef long clock_t;
+
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+clock_t clock(void);
+time_t time(time_t * tp);
+double difftime(time_t time2, time_t time1);
+time_t mktime(struct tm * tp);
+
+char * asctime(const struct tm * tp);
+char * ctime(const time_t * tp);
+struct tm * gmtime(const time_t *tp);
+struct tm *localtime(const time_t * tp);
+size_t strftime(char * s, size_t smax, const char * fmt, const struct tm * tp);
+void tzset(void);
+
+#endif
diff --git a/linux/include/unistd.h b/linux/include/unistd.h
new file mode 100644
index 0000000..eb10771
--- /dev/null
+++ b/linux/include/unistd.h
@@ -0,0 +1,247 @@
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+/* ok, this may be a joke, but I'm working on it */
+#define _POSIX_VERSION 198808L
+
+#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */
+/* #define _POSIX_NO_TRUNC*/ /* pathname truncation (but see in kernel) */
+#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
+/*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */
+/*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/* access */
+#define F_OK 0
+#define X_OK 1
+#define W_OK 2
+#define R_OK 4
+
+/* lseek */
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+/* _SC stands for System Configuration. We don't use them much */
+#define _SC_ARG_MAX 1
+#define _SC_CHILD_MAX 2
+#define _SC_CLOCKS_PER_SEC 3
+#define _SC_NGROUPS_MAX 4
+#define _SC_OPEN_MAX 5
+#define _SC_JOB_CONTROL 6
+#define _SC_SAVED_IDS 7
+#define _SC_VERSION 8
+
+/* more (possibly) configurable things - now pathnames */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_NO_TRUNC 7
+#define _PC_VDISABLE 8
+#define _PC_CHOWN_RESTRICTED 9
+
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <sys/utsname.h>
+#include <utime.h>
+
+#ifdef __LIBRARY__
+
+#define __NR_setup 0 /* used only by init, to get system going */
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+#define __NR_waitpid 7
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_chdir 12
+#define __NR_time 13
+#define __NR_mknod 14
+#define __NR_chmod 15
+#define __NR_chown 16
+#define __NR_break 17
+#define __NR_stat 18
+#define __NR_lseek 19
+#define __NR_getpid 20
+#define __NR_mount 21
+#define __NR_umount 22
+#define __NR_setuid 23
+#define __NR_getuid 24
+#define __NR_stime 25
+#define __NR_ptrace 26
+#define __NR_alarm 27
+#define __NR_fstat 28
+#define __NR_pause 29
+#define __NR_utime 30
+#define __NR_stty 31
+#define __NR_gtty 32
+#define __NR_access 33
+#define __NR_nice 34
+#define __NR_ftime 35
+#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+#define __NR_mkdir 39
+#define __NR_rmdir 40
+#define __NR_dup 41
+#define __NR_pipe 42
+#define __NR_times 43
+#define __NR_prof 44
+#define __NR_brk 45
+#define __NR_setgid 46
+#define __NR_getgid 47
+#define __NR_signal 48
+#define __NR_geteuid 49
+#define __NR_getegid 50
+#define __NR_acct 51
+#define __NR_phys 52
+#define __NR_lock 53
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+#define __NR_mpx 56
+#define __NR_setpgid 57
+#define __NR_ulimit 58
+#define __NR_uname 59
+#define __NR_umask 60
+#define __NR_chroot 61
+#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_getpgrp 65
+#define __NR_setsid 66
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+type __res; \
+__asm__ volatile ("int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name)); \
+if (__res >= 0) \
+ return __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall1(type,name,atype,a) \
+type name(atype a) \
+{ \
+type __res; \
+__asm__ volatile ("int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"b" (a)); \
+if (__res >= 0) \
+ return __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall2(type,name,atype,a,btype,b) \
+type name(atype a,btype b) \
+{ \
+type __res; \
+__asm__ volatile ("int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"b" (a),"c" (b)); \
+if (__res >= 0) \
+ return __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
+type name(atype a,btype b,ctype c) \
+{ \
+type __res; \
+__asm__ volatile ("int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"b" (a),"c" (b),"d" (c)); \
+if (__res<0) \
+ errno=-__res , __res = -1; \
+return __res;\
+}
+
+#endif /* __LIBRARY__ */
+
+extern int errno;
+
+int access(const char * filename, mode_t mode);
+int acct(const char * filename);
+int alarm(int sec);
+int brk(void * end_data_segment);
+void * sbrk(ptrdiff_t increment);
+int chdir(const char * filename);
+int chmod(const char * filename, mode_t mode);
+int chown(const char * filename, uid_t owner, gid_t group);
+int chroot(const char * filename);
+int close(int fildes);
+int creat(const char * filename, mode_t mode);
+int dup(int fildes);
+int execve(const char * filename, char ** argv, char ** envp);
+int execv(const char * pathname, char ** argv);
+int execvp(const char * file, char ** argv);
+int execl(const char * pathname, char * arg0, ...);
+int execlp(const char * file, char * arg0, ...);
+int execle(const char * pathname, char * arg0, ...);
+volatile void exit(int status);
+volatile void _exit(int status);
+int fcntl(int fildes, int cmd, ...);
+int fork(void);
+int getpid(void);
+int getuid(void);
+int geteuid(void);
+int getgid(void);
+int getegid(void);
+int ioctl(int fildes, int cmd, ...);
+int kill(pid_t pid, int signal);
+int link(const char * filename1, const char * filename2);
+int lseek(int fildes, off_t offset, int origin);
+int mknod(const char * filename, mode_t mode, dev_t dev);
+int mount(const char * specialfile, const char * dir, int rwflag);
+int nice(int val);
+int open(const char * filename, int flag, ...);
+int pause(void);
+int pipe(int * fildes);
+int read(int fildes, char * buf, off_t count);
+int setpgrp(void);
+int setpgid(pid_t pid,pid_t pgid);
+int setuid(uid_t uid);
+int setgid(gid_t gid);
+void (*signal(int sig, void (*fn)(int)))(int);
+int stat(const char * filename, struct stat * stat_buf);
+int fstat(int fildes, struct stat * stat_buf);
+int stime(time_t * tptr);
+int sync(void);
+time_t time(time_t * tloc);
+time_t times(struct tms * tbuf);
+int ulimit(int cmd, long limit);
+mode_t umask(mode_t mask);
+int umount(const char * specialfile);
+int uname(struct utsname * name);
+int unlink(const char * filename);
+int ustat(dev_t dev, struct ustat * ubuf);
+int utime(const char * filename, struct utimbuf * times);
+pid_t waitpid(pid_t pid,int * wait_stat,int options);
+pid_t wait(int * wait_stat);
+int write(int fildes, const char * buf, off_t count);
+int dup2(int oldfd, int newfd);
+int getppid(void);
+pid_t getpgrp(void);
+pid_t setsid(void);
+
+#endif
diff --git a/linux/include/utime.h b/linux/include/utime.h
new file mode 100644
index 0000000..83f07c7
--- /dev/null
+++ b/linux/include/utime.h
@@ -0,0 +1,13 @@
+#ifndef _UTIME_H
+#define _UTIME_H
+
+#include <sys/types.h> /* I know - shouldn't do this, but .. */
+
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+
+extern int utime(const char *filename, struct utimbuf *times);
+
+#endif
diff --git a/linux/init/main.c b/linux/init/main.c
new file mode 100644
index 0000000..1192119
--- /dev/null
+++ b/linux/init/main.c
@@ -0,0 +1,147 @@
+#define __LIBRARY__
+#include <unistd.h>
+#include <time.h>
+
+/*
+ * we need this inline - forking from kernel space will result
+ * in NO COPY ON WRITE (!!!), until an execve is executed. This
+ * is no problem, but for the stack. This is handled by not letting
+ * main() use the stack at all after fork(). Thus, no function
+ * calls - which means inline code for fork too, as otherwise we
+ * would use the stack upon exit from 'fork()'.
+ *
+ * Actually only pause and fork are needed inline, so that there
+ * won't be any messing with the stack from main(), but we define
+ * some others too.
+ */
+static inline _syscall0(int,fork)
+static inline _syscall0(int,pause)
+static inline _syscall0(int,setup)
+static inline _syscall0(int,sync)
+
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+
+static char printbuf[1024];
+
+extern int vsprintf();
+extern void init(void);
+extern void hd_init(void);
+extern long kernel_mktime(struct tm * tm);
+extern long startup_time;
+
+/*
+ * Yeah, yeah, it's ugly, but I cannot find how to do this correctly
+ * and this seems to work. I anybody has more info on the real-time
+ * clock I'd be interested. Most of this was trial and error, and some
+ * bios-listing reading. Urghh.
+ */
+
+#define CMOS_READ(addr) ({ \
+outb_p(0x80|addr,0x70); \
+inb_p(0x71); \
+})
+
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+
+static void time_init(void)
+{
+ struct tm time;
+
+ do {
+ time.tm_sec = CMOS_READ(0);
+ time.tm_min = CMOS_READ(2);
+ time.tm_hour = CMOS_READ(4);
+ time.tm_mday = CMOS_READ(7);
+ time.tm_mon = CMOS_READ(8)-1;
+ time.tm_year = CMOS_READ(9);
+ } while (time.tm_sec != CMOS_READ(0));
+ BCD_TO_BIN(time.tm_sec);
+ BCD_TO_BIN(time.tm_min);
+ BCD_TO_BIN(time.tm_hour);
+ BCD_TO_BIN(time.tm_mday);
+ BCD_TO_BIN(time.tm_mon);
+ BCD_TO_BIN(time.tm_year);
+ startup_time = kernel_mktime(&time);
+}
+
+void main(void) /* This really IS void, no error here. */
+{ /* The startup routine assumes (well, ...) this */
+/*
+ * Interrupts are still disabled. Do necessary setups, then
+ * enable them
+ */
+ time_init();
+ tty_init();
+ trap_init();
+ sched_init();
+ buffer_init();
+ hd_init();
+ sti();
+ move_to_user_mode();
+ if (!fork()) { /* we count on this going ok */
+ init();
+ }
+/*
+ * NOTE!! For any other task 'pause()' would mean we have to get a
+ * signal to awaken, but task0 is the sole exception (see 'schedule()')
+ * as task 0 gets activated at every idle moment (when no other tasks
+ * can run). For task0 'pause()' just means we go check if some other
+ * task can run, and if not we return here.
+ */
+ for(;;) pause();
+}
+
+static int printf(const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ write(1,printbuf,i=vsprintf(printbuf, fmt, args));
+ va_end(args);
+ return i;
+}
+
+static char * argv[] = { "-",NULL };
+static char * envp[] = { "HOME=/usr/root", NULL };
+
+void init(void)
+{
+ int i,j;
+
+ setup();
+ if (!fork())
+ _exit(execve("/bin/update",NULL,NULL));
+ (void) open("/dev/tty0",O_RDWR,0);
+ (void) dup(0);
+ (void) dup(0);
+ printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
+ NR_BUFFERS*BLOCK_SIZE);
+ printf(" Ok.\n\r");
+ if ((i=fork())<0)
+ printf("Fork failed in init\r\n");
+ else if (!i) {
+ close(0);close(1);close(2);
+ setsid();
+ (void) open("/dev/tty0",O_RDWR,0);
+ (void) dup(0);
+ (void) dup(0);
+ _exit(execve("/bin/sh",argv,envp));
+ }
+ j=wait(&i);
+ printf("child %d died with code %04x\n",j,i);
+ sync();
+ _exit(0); /* NOTE! _exit, not exit() */
+}
diff --git a/linux/kernel/Makefile b/linux/kernel/Makefile
new file mode 100644
index 0000000..23fe7dd
--- /dev/null
+++ b/linux/kernel/Makefile
@@ -0,0 +1,90 @@
+#
+# Makefile for the FREAX-kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+AR =gar
+AS =gas
+LD =gld
+LDFLAGS =-s -x
+CC =gcc
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
+ -finline-functions -mstring-insns -nostdinc -I../include
+CPP =gcc -E -nostdinc -I../include
+
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) \
+ -c -o $*.o $<
+
+OBJS = sched.o system_call.o traps.o asm.o fork.o \
+ panic.o printk.o vsprintf.o tty_io.o console.o \
+ keyboard.o rs_io.o hd.o sys.o exit.o serial.o \
+ mktime.o
+
+kernel.o: $(OBJS)
+ $(LD) -r -o kernel.o $(OBJS)
+ sync
+
+clean:
+ rm -f core *.o *.a tmp_make
+ for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
+ $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
+console.s console.o : console.c ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
+ ../include/linux/tty.h ../include/termios.h ../include/asm/io.h \
+ ../include/asm/system.h
+exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \
+ ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
+ ../include/asm/segment.h
+fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/segment.h \
+ ../include/asm/system.h
+hd.s hd.o : hd.c ../include/linux/config.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/linux/hdreg.h \
+ ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h
+mktime.s mktime.o : mktime.c ../include/time.h
+panic.s panic.o : panic.c ../include/linux/kernel.h
+printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \
+ ../include/linux/kernel.h
+sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/signal.h ../include/linux/sys.h \
+ ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h
+serial.s serial.o : serial.c ../include/linux/tty.h ../include/termios.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/linux/mm.h ../include/asm/system.h \
+ ../include/asm/io.h
+sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/tty.h ../include/termios.h \
+ ../include/linux/kernel.h ../include/asm/segment.h ../include/sys/times.h \
+ ../include/sys/utsname.h
+traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \
+ ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/asm/system.h \
+ ../include/asm/segment.h
+tty_io.s tty_io.o : tty_io.c ../include/ctype.h ../include/errno.h \
+ ../include/signal.h ../include/sys/types.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
+ ../include/linux/tty.h ../include/termios.h ../include/asm/segment.h \
+ ../include/asm/system.h
+vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h
diff --git a/linux/kernel/asm.s b/linux/kernel/asm.s
new file mode 100644
index 0000000..6fe1981
--- /dev/null
+++ b/linux/kernel/asm.s
@@ -0,0 +1,157 @@
+/*
+ * asm.s contains the low-level code for most hardware faults.
+ * page_exception is handled by the mm, so that isn't here. This
+ * file also handles (hopefully) fpu-exceptions due to TS-bit, as
+ * the fpu must be properly saved/resored. This hasn't been tested.
+ */
+
+.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
+.globl _device_not_available,_double_fault,_coprocessor_segment_overrun
+.globl _invalid_TSS,_segment_not_present,_stack_segment
+.globl _general_protection,_coprocessor_error,_reserved
+
+_divide_error:
+ pushl $_do_divide_error
+no_error_code:
+ xchgl %eax,(%esp)
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ push %ds
+ push %es
+ push %fs
+ pushl $0 # "error code"
+ lea 44(%esp),%edx
+ pushl %edx
+ movl $0x10,%edx
+ mov %dx,%ds
+ mov %dx,%es
+ mov %dx,%fs
+ call *%eax
+ addl $8,%esp
+ pop %fs
+ pop %es
+ pop %ds
+ popl %ebp
+ popl %esi
+ popl %edi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ iret
+
+_debug:
+ pushl $_do_int3 # _do_debug
+ jmp no_error_code
+
+_nmi:
+ pushl $_do_nmi
+ jmp no_error_code
+
+_int3:
+ pushl $_do_int3
+ jmp no_error_code
+
+_overflow:
+ pushl $_do_overflow
+ jmp no_error_code
+
+_bounds:
+ pushl $_do_bounds
+ jmp no_error_code
+
+_invalid_op:
+ pushl $_do_invalid_op
+ jmp no_error_code
+
+math_emulate:
+ popl %eax
+ pushl $_do_device_not_available
+ jmp no_error_code
+_device_not_available:
+ pushl %eax
+ movl %cr0,%eax
+ bt $2,%eax # EM (math emulation bit)
+ jc math_emulate
+ clts # clear TS so that we can use math
+ movl _current,%eax
+ cmpl _last_task_used_math,%eax
+ je 1f # shouldn't happen really ...
+ pushl %ecx
+ pushl %edx
+ push %ds
+ movl $0x10,%eax
+ mov %ax,%ds
+ call _math_state_restore
+ pop %ds
+ popl %edx
+ popl %ecx
+1: popl %eax
+ iret
+
+_coprocessor_segment_overrun:
+ pushl $_do_coprocessor_segment_overrun
+ jmp no_error_code
+
+_reserved:
+ pushl $_do_reserved
+ jmp no_error_code
+
+_coprocessor_error:
+ pushl $_do_coprocessor_error
+ jmp no_error_code
+
+_double_fault:
+ pushl $_do_double_fault
+error_code:
+ xchgl %eax,4(%esp) # error code <-> %eax
+ xchgl %ebx,(%esp) # &function <-> %ebx
+ pushl %ecx
+ pushl %edx
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ push %ds
+ push %es
+ push %fs
+ pushl %eax # error code
+ lea 44(%esp),%eax # offset
+ pushl %eax
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ call *%ebx
+ addl $8,%esp
+ pop %fs
+ pop %es
+ pop %ds
+ popl %ebp
+ popl %esi
+ popl %edi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ iret
+
+_invalid_TSS:
+ pushl $_do_invalid_TSS
+ jmp error_code
+
+_segment_not_present:
+ pushl $_do_segment_not_present
+ jmp error_code
+
+_stack_segment:
+ pushl $_do_stack_segment
+ jmp error_code
+
+_general_protection:
+ pushl $_do_general_protection
+ jmp error_code
+
diff --git a/linux/kernel/console.c b/linux/kernel/console.c
new file mode 100644
index 0000000..9e00b31
--- /dev/null
+++ b/linux/kernel/console.c
@@ -0,0 +1,550 @@
+/*
+ * console.c
+ *
+ * This module implements the console io functions
+ * 'void con_init(void)'
+ * 'void con_write(struct tty_queue * queue)'
+ * Hopefully this will be a rather complete VT102 implementation.
+ *
+ */
+
+/*
+ * NOTE!!! We sometimes disable and enable interrupts for a short while
+ * (to put a word in video IO), but this will work even for keyboard
+ * interrupts. We know interrupts aren't enabled when getting a keyboard
+ * interrupt, as we use trap-gates. Hopefully all is well.
+ */
+
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#define SCREEN_START 0xb8000
+#define SCREEN_END 0xc0000
+#define LINES 25
+#define COLUMNS 80
+#define NPAR 16
+
+extern void keyboard_interrupt(void);
+
+static unsigned long origin=SCREEN_START;
+static unsigned long scr_end=SCREEN_START+LINES*COLUMNS*2;
+static unsigned long pos;
+static unsigned long x,y;
+static unsigned long top=0,bottom=LINES;
+static unsigned long lines=LINES,columns=COLUMNS;
+static unsigned long state=0;
+static unsigned long npar,par[NPAR];
+static unsigned long ques=0;
+static unsigned char attr=0x07;
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c
+ * query (= vt100 response).
+ */
+#define RESPONSE "\033[?1;2c"
+
+static inline void gotoxy(unsigned int new_x,unsigned int new_y)
+{
+ if (new_x>=columns || new_y>=lines)
+ return;
+ x=new_x;
+ y=new_y;
+ pos=origin+((y*columns+x)<<1);
+}
+
+static inline void set_origin(void)
+{
+ cli();
+ outb_p(12,0x3d4);
+ outb_p(0xff&((origin-SCREEN_START)>>9),0x3d5);
+ outb_p(13,0x3d4);
+ outb_p(0xff&((origin-SCREEN_START)>>1),0x3d5);
+ sti();
+}
+
+static void scrup(void)
+{
+ if (!top && bottom==lines) {
+ origin += columns<<1;
+ pos += columns<<1;
+ scr_end += columns<<1;
+ if (scr_end>SCREEN_END) {
+ __asm__("cld\n\t"
+ "rep\n\t"
+ "movsl\n\t"
+ "movl _columns,%1\n\t"
+ "rep\n\t"
+ "stosw"
+ ::"a" (0x0720),
+ "c" ((lines-1)*columns>>1),
+ "D" (SCREEN_START),
+ "S" (origin)
+ :"cx","di","si");
+ scr_end -= origin-SCREEN_START;
+ pos -= origin-SCREEN_START;
+ origin = SCREEN_START;
+ } else {
+ __asm__("cld\n\t"
+ "rep\n\t"
+ "stosl"
+ ::"a" (0x07200720),
+ "c" (columns>>1),
+ "D" (scr_end-(columns<<1))
+ :"cx","di");
+ }
+ set_origin();
+ } else {
+ __asm__("cld\n\t"
+ "rep\n\t"
+ "movsl\n\t"
+ "movl _columns,%%ecx\n\t"
+ "rep\n\t"
+ "stosw"
+ ::"a" (0x0720),
+ "c" ((bottom-top-1)*columns>>1),
+ "D" (origin+(columns<<1)*top),
+ "S" (origin+(columns<<1)*(top+1))
+ :"cx","di","si");
+ }
+}
+
+static void scrdown(void)
+{
+ __asm__("std\n\t"
+ "rep\n\t"
+ "movsl\n\t"
+ "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
+ "movl _columns,%%ecx\n\t"
+ "rep\n\t"
+ "stosw"
+ ::"a" (0x0720),
+ "c" ((bottom-top-1)*columns>>1),
+ "D" (origin+(columns<<1)*bottom-4),
+ "S" (origin+(columns<<1)*(bottom-1)-4)
+ :"ax","cx","di","si");
+}
+
+static void lf(void)
+{
+ if (y+1<bottom) {
+ y++;
+ pos += columns<<1;
+ return;
+ }
+ scrup();
+}
+
+static void ri(void)
+{
+ if (y>top) {
+ y--;
+ pos -= columns<<1;
+ return;
+ }
+ scrdown();
+}
+
+static void cr(void)
+{
+ pos -= x<<1;
+ x=0;
+}
+
+static void del(void)
+{
+ if (x) {
+ pos -= 2;
+ x--;
+ *(unsigned short *)pos = 0x0720;
+ }
+}
+
+static void csi_J(int par)
+{
+ long count __asm__("cx");
+ long start __asm__("di");
+
+ switch (par) {
+ case 0: /* erase from cursor to end of display */
+ count = (scr_end-pos)>>1;
+ start = pos;
+ break;
+ case 1: /* erase from start to cursor */
+ count = (pos-origin)>>1;
+ start = origin;
+ break;
+ case 2: /* erase whole display */
+ count = columns*lines;
+ start = origin;
+ break;
+ default:
+ return;
+ }
+ __asm__("cld\n\t"
+ "rep\n\t"
+ "stosw\n\t"
+ ::"c" (count),
+ "D" (start),"a" (0x0720)
+ :"cx","di");
+}
+
+static void csi_K(int par)
+{
+ long count __asm__("cx");
+ long start __asm__("di");
+
+ switch (par) {
+ case 0: /* erase from cursor to end of line */
+ if (x>=columns)
+ return;
+ count = columns-x;
+ start = pos;
+ break;
+ case 1: /* erase from start of line to cursor */
+ start = pos - (x<<1);
+ count = (x<columns)?x:columns;
+ break;
+ case 2: /* erase whole line */
+ start = pos - (x<<1);
+ count = columns;
+ break;
+ default:
+ return;
+ }
+ __asm__("cld\n\t"
+ "rep\n\t"
+ "stosw\n\t"
+ ::"c" (count),
+ "D" (start),"a" (0x0720)
+ :"cx","di");
+}
+
+void csi_m(void)
+{
+ int i;
+
+ for (i=0;i<=npar;i++)
+ switch (par[i]) {
+ case 0:attr=0x07;break;
+ case 1:attr=0x0f;break;
+ case 4:attr=0x0f;break;
+ case 7:attr=0x70;break;
+ case 27:attr=0x07;break;
+ }
+}
+
+static inline void set_cursor(void)
+{
+ cli();
+ outb_p(14,0x3d4);
+ outb_p(0xff&((pos-SCREEN_START)>>9),0x3d5);
+ outb_p(15,0x3d4);
+ outb_p(0xff&((pos-SCREEN_START)>>1),0x3d5);
+ sti();
+}
+
+static void respond(struct tty_struct * tty)
+{
+ char * p = RESPONSE;
+
+ cli();
+ while (*p) {
+ PUTCH(*p,tty->read_q);
+ p++;
+ }
+ sti();
+ copy_to_cooked(tty);
+}
+
+static void insert_char(void)
+{
+ int i=x;
+ unsigned short tmp,old=0x0720;
+ unsigned short * p = (unsigned short *) pos;
+
+ while (i++<columns) {
+ tmp=*p;
+ *p=old;
+ old=tmp;
+ p++;
+ }
+}
+
+static void insert_line(void)
+{
+ int oldtop,oldbottom;
+
+ oldtop=top;
+ oldbottom=bottom;
+ top=y;
+ bottom=lines;
+ scrdown();
+ top=oldtop;
+ bottom=oldbottom;
+}
+
+static void delete_char(void)
+{
+ int i;
+ unsigned short * p = (unsigned short *) pos;
+
+ if (x>=columns)
+ return;
+ i = x;
+ while (++i < columns) {
+ *p = *(p+1);
+ p++;
+ }
+ *p=0x0720;
+}
+
+static void delete_line(void)
+{
+ int oldtop,oldbottom;
+
+ oldtop=top;
+ oldbottom=bottom;
+ top=y;
+ bottom=lines;
+ scrup();
+ top=oldtop;
+ bottom=oldbottom;
+}
+
+static void csi_at(int nr)
+{
+ if (nr>columns)
+ nr=columns;
+ else if (!nr)
+ nr=1;
+ while (nr--)
+ insert_char();
+}
+
+static void csi_L(int nr)
+{
+ if (nr>lines)
+ nr=lines;
+ else if (!nr)
+ nr=1;
+ while (nr--)
+ insert_line();
+}
+
+static void csi_P(int nr)
+{
+ if (nr>columns)
+ nr=columns;
+ else if (!nr)
+ nr=1;
+ while (nr--)
+ delete_char();
+}
+
+static void csi_M(int nr)
+{
+ if (nr>lines)
+ nr=lines;
+ else if (!nr)
+ nr=1;
+ while (nr--)
+ delete_line();
+}
+
+static int saved_x=0;
+static int saved_y=0;
+
+static void save_cur(void)
+{
+ saved_x=x;
+ saved_y=y;
+}
+
+static void restore_cur(void)
+{
+ x=saved_x;
+ y=saved_y;
+ pos=origin+((y*columns+x)<<1);
+}
+
+void con_write(struct tty_struct * tty)
+{
+ int nr;
+ char c;
+
+ nr = CHARS(tty->write_q);
+ while (nr--) {
+ GETCH(tty->write_q,c);
+ switch(state) {
+ case 0:
+ if (c>31 && c<127) {
+ if (x>=columns) {
+ x -= columns;
+ pos -= columns<<1;
+ lf();
+ }
+ __asm__("movb _attr,%%ah\n\t"
+ "movw %%ax,%1\n\t"
+ ::"a" (c),"m" (*(short *)pos)
+ :"ax");
+ pos += 2;
+ x++;
+ } else if (c==27)
+ state=1;
+ else if (c==10 || c==11 || c==12)
+ lf();
+ else if (c==13)
+ cr();
+ else if (c==ERASE_CHAR(tty))
+ del();
+ else if (c==8) {
+ if (x) {
+ x--;
+ pos -= 2;
+ }
+ } else if (c==9) {
+ c=8-(x&7);
+ x += c;
+ pos += c<<1;
+ if (x>columns) {
+ x -= columns;
+ pos -= columns<<1;
+ lf();
+ }
+ c=9;
+ }
+ break;
+ case 1:
+ state=0;
+ if (c=='[')
+ state=2;
+ else if (c=='E')
+ gotoxy(0,y+1);
+ else if (c=='M')
+ ri();
+ else if (c=='D')
+ lf();
+ else if (c=='Z')
+ respond(tty);
+ else if (x=='7')
+ save_cur();
+ else if (x=='8')
+ restore_cur();
+ break;
+ case 2:
+ for(npar=0;npar<NPAR;npar++)
+ par[npar]=0;
+ npar=0;
+ state=3;
+ if (ques=(c=='?'))
+ break;
+ case 3:
+ if (c==';' && npar<NPAR-1) {
+ npar++;
+ break;
+ } else if (c>='0' && c<='9') {
+ par[npar]=10*par[npar]+c-'0';
+ break;
+ } else state=4;
+ case 4:
+ state=0;
+ switch(c) {
+ case 'G': case '`':
+ if (par[0]) par[0]--;
+ gotoxy(par[0],y);
+ break;
+ case 'A':
+ if (!par[0]) par[0]++;
+ gotoxy(x,y-par[0]);
+ break;
+ case 'B': case 'e':
+ if (!par[0]) par[0]++;
+ gotoxy(x,y+par[0]);
+ break;
+ case 'C': case 'a':
+ if (!par[0]) par[0]++;
+ gotoxy(x+par[0],y);
+ break;
+ case 'D':
+ if (!par[0]) par[0]++;
+ gotoxy(x-par[0],y);
+ break;
+ case 'E':
+ if (!par[0]) par[0]++;
+ gotoxy(0,y+par[0]);
+ break;
+ case 'F':
+ if (!par[0]) par[0]++;
+ gotoxy(0,y-par[0]);
+ break;
+ case 'd':
+ if (par[0]) par[0]--;
+ gotoxy(x,par[0]);
+ break;
+ case 'H': case 'f':
+ if (par[0]) par[0]--;
+ if (par[1]) par[1]--;
+ gotoxy(par[1],par[0]);
+ break;
+ case 'J':
+ csi_J(par[0]);
+ break;
+ case 'K':
+ csi_K(par[0]);
+ break;
+ case 'L':
+ csi_L(par[0]);
+ break;
+ case 'M':
+ csi_M(par[0]);
+ break;
+ case 'P':
+ csi_P(par[0]);
+ break;
+ case '@':
+ csi_at(par[0]);
+ break;
+ case 'm':
+ csi_m();
+ break;
+ case 'r':
+ if (par[0]) par[0]--;
+ if (!par[1]) par[1]=lines;
+ if (par[0] < par[1] &&
+ par[1] <= lines) {
+ top=par[0];
+ bottom=par[1];
+ }
+ break;
+ case 's':
+ save_cur();
+ break;
+ case 'u':
+ restore_cur();
+ break;
+ }
+ }
+ }
+ set_cursor();
+}
+
+/*
+ * void con_init(void);
+ *
+ * This routine initalizes console interrupts, and does nothing
+ * else. If you want the screen to clear, call tty_write with
+ * the appropriate escape-sequece.
+ */
+void con_init(void)
+{
+ register unsigned char a;
+
+ gotoxy(*(unsigned char *)(0x90000+510),*(unsigned char *)(0x90000+511));
+ set_trap_gate(0x21,&keyboard_interrupt);
+ outb_p(inb_p(0x21)&0xfd,0x21);
+ a=inb_p(0x61);
+ outb_p(a|0x80,0x61);
+ outb(a,0x61);
+}
diff --git a/linux/kernel/exit.c b/linux/kernel/exit.c
new file mode 100644
index 0000000..3402c33
--- /dev/null
+++ b/linux/kernel/exit.c
@@ -0,0 +1,135 @@
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <asm/segment.h>
+
+int sys_pause(void);
+int sys_close(int fd);
+
+void release(struct task_struct * p)
+{
+ int i;
+
+ if (!p)
+ return;
+ for (i=1 ; i<NR_TASKS ; i++)
+ if (task[i]==p) {
+ task[i]=NULL;
+ free_page((long)p);
+ schedule();
+ return;
+ }
+ panic("trying to release non-existent task");
+}
+
+static inline void send_sig(long sig,struct task_struct * p,int priv)
+{
+ if (!p || sig<1 || sig>32)
+ return;
+ if (priv ||
+ current->uid==p->uid ||
+ current->euid==p->uid ||
+ current->uid==p->euid ||
+ current->euid==p->euid)
+ p->signal |= (1<<(sig-1));
+}
+
+void do_kill(long pid,long sig,int priv)
+{
+ struct task_struct **p = NR_TASKS + task;
+
+ if (!pid) while (--p > &FIRST_TASK) {
+ if (*p && (*p)->pgrp == current->pid)
+ send_sig(sig,*p,priv);
+ } else if (pid>0) while (--p > &FIRST_TASK) {
+ if (*p && (*p)->pid == pid)
+ send_sig(sig,*p,priv);
+ } else if (pid == -1) while (--p > &FIRST_TASK)
+ send_sig(sig,*p,priv);
+ else while (--p > &FIRST_TASK)
+ if (*p && (*p)->pgrp == -pid)
+ send_sig(sig,*p,priv);
+}
+
+int sys_kill(int pid,int sig)
+{
+ do_kill(pid,sig,!(current->uid || current->euid));
+ return 0;
+}
+
+int do_exit(long code)
+{
+ int i;
+
+ free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
+ free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
+ for (i=0 ; i<NR_TASKS ; i++)
+ if (task[i] && task[i]->father == current->pid)
+ task[i]->father = 0;
+ for (i=0 ; i<NR_OPEN ; i++)
+ if (current->filp[i])
+ sys_close(i);
+ iput(current->pwd);
+ current->pwd=NULL;
+ iput(current->root);
+ current->root=NULL;
+ if (current->leader && current->tty >= 0)
+ tty_table[current->tty].pgrp = 0;
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
+ if (current->father) {
+ current->state = TASK_ZOMBIE;
+ do_kill(current->father,SIGCHLD,1);
+ current->exit_code = code;
+ } else
+ release(current);
+ schedule();
+ return (-1); /* just to suppress warnings */
+}
+
+int sys_exit(int error_code)
+{
+ return do_exit((error_code&0xff)<<8);
+}
+
+int sys_waitpid(pid_t pid,int * stat_addr, int options)
+{
+ int flag=0;
+ struct task_struct ** p;
+
+ verify_area(stat_addr,4);
+repeat:
+ for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if (*p && *p != current &&
+ (pid==-1 || (*p)->pid==pid ||
+ (pid==0 && (*p)->pgrp==current->pgrp) ||
+ (pid<0 && (*p)->pgrp==-pid)))
+ if ((*p)->father == current->pid) {
+ flag=1;
+ if ((*p)->state==TASK_ZOMBIE) {
+ put_fs_long((*p)->exit_code,
+ (unsigned long *) stat_addr);
+ current->cutime += (*p)->utime;
+ current->cstime += (*p)->stime;
+ flag = (*p)->pid;
+ release(*p);
+ return flag;
+ }
+ }
+ if (flag) {
+ if (options & WNOHANG)
+ return 0;
+ sys_pause();
+ if (!(current->signal &= ~(1<<(SIGCHLD-1))))
+ goto repeat;
+ else
+ return -EINTR;
+ }
+ return -ECHILD;
+}
+
+
diff --git a/linux/kernel/fork.c b/linux/kernel/fork.c
new file mode 100644
index 0000000..70f9ddd
--- /dev/null
+++ b/linux/kernel/fork.c
@@ -0,0 +1,136 @@
+/*
+ * 'fork.c' contains the help-routines for the 'fork' system call
+ * (see also system_call.s), and some misc functions ('verify_area').
+ * Fork is rather simple, once you get the hang of it, but the memory
+ * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
+ */
+#include <errno.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+extern void write_verify(unsigned long address);
+
+long last_pid=0;
+
+void verify_area(void * addr,int size)
+{
+ unsigned long start;
+
+ start = (unsigned long) addr;
+ size += start & 0xfff;
+ start &= 0xfffff000;
+ start += get_base(current->ldt[2]);
+ while (size>0) {
+ size -= 4096;
+ write_verify(start);
+ start += 4096;
+ }
+}
+
+int copy_mem(int nr,struct task_struct * p)
+{
+ unsigned long old_data_base,new_data_base,data_limit;
+ unsigned long old_code_base,new_code_base,code_limit;
+
+ code_limit=get_limit(0x0f);
+ data_limit=get_limit(0x17);
+ old_code_base = get_base(current->ldt[1]);
+ old_data_base = get_base(current->ldt[2]);
+ if (old_data_base != old_code_base)
+ panic("We don't support separate I&D");
+ if (data_limit < code_limit)
+ panic("Bad data_limit");
+ new_data_base = new_code_base = nr * 0x4000000;
+ set_base(p->ldt[1],new_code_base);
+ set_base(p->ldt[2],new_data_base);
+ if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
+ free_page_tables(new_data_base,data_limit);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * Ok, this is the main fork-routine. It copies the system process
+ * information (task[nr]) and sets up the necessary registers. It
+ * also copies the data segment in it's entirety.
+ */
+int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
+ long ebx,long ecx,long edx,
+ long fs,long es,long ds,
+ long eip,long cs,long eflags,long esp,long ss)
+{
+ struct task_struct *p;
+ int i;
+ struct file *f;
+
+ p = (struct task_struct *) get_free_page();
+ if (!p)
+ return -EAGAIN;
+ *p = *current; /* NOTE! this doesn't copy the supervisor stack */
+ p->state = TASK_RUNNING;
+ p->pid = last_pid;
+ p->father = current->pid;
+ p->counter = p->priority;
+ p->signal = 0;
+ p->alarm = 0;
+ p->leader = 0; /* process leadership doesn't inherit */
+ p->utime = p->stime = 0;
+ p->cutime = p->cstime = 0;
+ p->start_time = jiffies;
+ p->tss.back_link = 0;
+ p->tss.esp0 = PAGE_SIZE + (long) p;
+ p->tss.ss0 = 0x10;
+ p->tss.eip = eip;
+ p->tss.eflags = eflags;
+ p->tss.eax = 0;
+ p->tss.ecx = ecx;
+ p->tss.edx = edx;
+ p->tss.ebx = ebx;
+ p->tss.esp = esp;
+ p->tss.ebp = ebp;
+ p->tss.esi = esi;
+ p->tss.edi = edi;
+ p->tss.es = es & 0xffff;
+ p->tss.cs = cs & 0xffff;
+ p->tss.ss = ss & 0xffff;
+ p->tss.ds = ds & 0xffff;
+ p->tss.fs = fs & 0xffff;
+ p->tss.gs = gs & 0xffff;
+ p->tss.ldt = _LDT(nr);
+ p->tss.trace_bitmap = 0x80000000;
+ if (last_task_used_math == current)
+ __asm__("fnsave %0"::"m" (p->tss.i387));
+ if (copy_mem(nr,p)) {
+ free_page((long) p);
+ return -EAGAIN;
+ }
+ for (i=0; i<NR_OPEN;i++)
+ if (f=p->filp[i])
+ f->f_count++;
+ if (current->pwd)
+ current->pwd->i_count++;
+ if (current->root)
+ current->root->i_count++;
+ set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
+ set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
+ task[nr] = p; /* do this last, just in case */
+ return last_pid;
+}
+
+int find_empty_process(void)
+{
+ int i;
+
+ repeat:
+ if ((++last_pid)<0) last_pid=1;
+ for(i=0 ; i<NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == last_pid) goto repeat;
+ for(i=1 ; i<NR_TASKS ; i++)
+ if (!task[i])
+ return i;
+ return -EAGAIN;
+}
diff --git a/linux/kernel/hd.c b/linux/kernel/hd.c
new file mode 100644
index 0000000..d3e6140
--- /dev/null
+++ b/linux/kernel/hd.c
@@ -0,0 +1,413 @@
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+/*
+ * This code handles all hd-interrupts, and read/write requests to
+ * the hard-disk. It is relatively straigthforward (not obvious maybe,
+ * but interrupts never are), while still being efficient, and never
+ * disabling interrupts (except to overcome possible race-condition).
+ * The elevator block-seek algorithm doesn't need to disable interrupts
+ * due to clever programming.
+ */
+
+/* Max read/write errors/sector */
+#define MAX_ERRORS 5
+#define MAX_HD 2
+#define NR_REQUEST 32
+
+/*
+ * This struct defines the HD's and their types.
+ * Currently defined for CP3044's, ie a modified
+ * type 17.
+ */
+static struct hd_i_struct{
+ int head,sect,cyl,wpcom,lzone,ctl;
+ } hd_info[]= { HD_TYPE };
+
+#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
+
+static struct hd_struct {
+ long start_sect;
+ long nr_sects;
+} hd[5*MAX_HD]={{0,0},};
+
+static struct hd_request {
+ int hd; /* -1 if no request */
+ int nsector;
+ int sector;
+ int head;
+ int cyl;
+ int cmd;
+ int errors;
+ struct buffer_head * bh;
+ struct hd_request * next;
+} request[NR_REQUEST];
+
+#define IN_ORDER(s1,s2) \
+((s1)->hd<(s2)->hd || (s1)->hd==(s2)->hd && \
+((s1)->cyl<(s2)->cyl || (s1)->cyl==(s2)->cyl && \
+((s1)->head<(s2)->head || (s1)->head==(s2)->head && \
+((s1)->sector<(s2)->sector))))
+
+static struct hd_request * this_request = NULL;
+
+static int sorting=0;
+
+static void do_request(void);
+static void reset_controller(void);
+static void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
+ unsigned int cyl,struct buffer_head * bh);
+void hd_init(void);
+
+#define port_read(port,buf,nr) \
+__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
+
+#define port_write(port,buf,nr) \
+__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
+
+extern void hd_interrupt(void);
+
+static struct task_struct * wait_for_request=NULL;
+
+static inline void lock_buffer(struct buffer_head * bh)
+{
+ if (bh->b_lock)
+ printk("hd.c: buffer multiply locked\n");
+ bh->b_lock=1;
+}
+
+static inline void unlock_buffer(struct buffer_head * bh)
+{
+ if (!bh->b_lock)
+ printk("hd.c: free buffer being unlocked\n");
+ bh->b_lock=0;
+ wake_up(&bh->b_wait);
+}
+
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+ cli();
+ while (bh->b_lock)
+ sleep_on(&bh->b_wait);
+ sti();
+}
+
+void rw_hd(int rw, struct buffer_head * bh)
+{
+ unsigned int block,dev;
+ unsigned int sec,head,cyl;
+
+ block = bh->b_blocknr << 1;
+ dev = MINOR(bh->b_dev);
+ if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects)
+ return;
+ block += hd[dev].start_sect;
+ dev /= 5;
+ __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
+ "r" (hd_info[dev].sect));
+ __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
+ "r" (hd_info[dev].head));
+ rw_abs_hd(rw,dev,sec+1,head,cyl,bh);
+}
+
+/* This may be used only once, enforced by 'static int callable' */
+int sys_setup(void)
+{
+ static int callable = 1;
+ int i,drive;
+ struct partition *p;
+
+ if (!callable)
+ return -1;
+ callable = 0;
+ for (drive=0 ; drive<NR_HD ; drive++) {
+ rw_abs_hd(READ,drive,1,0,0,(struct buffer_head *) start_buffer);
+ if (!start_buffer->b_uptodate) {
+ printk("Unable to read partition table of drive %d\n\r",
+ drive);
+ panic("");
+ }
+ if (start_buffer->b_data[510] != 0x55 || (unsigned char)
+ start_buffer->b_data[511] != 0xAA) {
+ printk("Bad partition table on drive %d\n\r",drive);
+ panic("");
+ }
+ p = 0x1BE + (void *)start_buffer->b_data;
+ for (i=1;i<5;i++,p++) {
+ hd[i+5*drive].start_sect = p->start_sect;
+ hd[i+5*drive].nr_sects = p->nr_sects;
+ }
+ }
+ printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
+ mount_root();
+ return (0);
+}
+
+/*
+ * This is the pointer to a routine to be executed at every hd-interrupt.
+ * Interesting way of doing things, but should be rather practical.
+ */
+void (*do_hd)(void) = NULL;
+
+static int controller_ready(void)
+{
+ int retries=1000;
+
+ while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
+ return (retries);
+}
+
+static int win_result(void)
+{
+ int i=inb(HD_STATUS);
+
+ if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
+ == (READY_STAT | SEEK_STAT))
+ return(0); /* ok */
+ if (i&1) i=inb(HD_ERROR);
+ return (1);
+}
+
+static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
+ unsigned int head,unsigned int cyl,unsigned int cmd,
+ void (*intr_addr)(void))
+{
+ register int port asm("dx");
+
+ if (drive>1 || head>15)
+ panic("Trying to write bad sector");
+ if (!controller_ready())
+ panic("HD controller not ready");
+ do_hd = intr_addr;
+ outb(_CTL,HD_CMD);
+ port=HD_DATA;
+ outb_p(_WPCOM,++port);
+ outb_p(nsect,++port);
+ outb_p(sect,++port);
+ outb_p(cyl,++port);
+ outb_p(cyl>>8,++port);
+ outb_p(0xA0|(drive<<4)|head,++port);
+ outb(cmd,++port);
+}
+
+static int drive_busy(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < 100000; i++)
+ if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
+ break;
+ i = inb(HD_STATUS);
+ i &= BUSY_STAT | READY_STAT | SEEK_STAT;
+ if (i == READY_STAT | SEEK_STAT)
+ return(0);
+ printk("HD controller times out\n\r");
+ return(1);
+}
+
+static void reset_controller(void)
+{
+ int i;
+
+ outb(4,HD_CMD);
+ for(i = 0; i < 1000; i++) nop();
+ outb(0,HD_CMD);
+ for(i = 0; i < 10000 && drive_busy(); i++) /* nothing */;
+ if (drive_busy())
+ printk("HD-controller still busy\n\r");
+ if((i = inb(ERR_STAT)) != 1)
+ printk("HD-controller reset failed: %02x\n\r",i);
+}
+
+static void reset_hd(int nr)
+{
+ reset_controller();
+ hd_out(nr,_SECT,_SECT,_HEAD-1,_CYL,WIN_SPECIFY,&do_request);
+}
+
+void unexpected_hd_interrupt(void)
+{
+ panic("Unexpected HD interrupt\n\r");
+}
+
+static void bad_rw_intr(void)
+{
+ int i = this_request->hd;
+
+ if (this_request->errors++ >= MAX_ERRORS) {
+ this_request->bh->b_uptodate = 0;
+ unlock_buffer(this_request->bh);
+ wake_up(&wait_for_request);
+ this_request->hd = -1;
+ this_request=this_request->next;
+ }
+ reset_hd(i);
+}
+
+static void read_intr(void)
+{
+ if (win_result()) {
+ bad_rw_intr();
+ return;
+ }
+ port_read(HD_DATA,this_request->bh->b_data+
+ 512*(this_request->nsector&1),256);
+ this_request->errors = 0;
+ if (--this_request->nsector)
+ return;
+ this_request->bh->b_uptodate = 1;
+ this_request->bh->b_dirt = 0;
+ wake_up(&wait_for_request);
+ unlock_buffer(this_request->bh);
+ this_request->hd = -1;
+ this_request=this_request->next;
+ do_request();
+}
+
+static void write_intr(void)
+{
+ if (win_result()) {
+ bad_rw_intr();
+ return;
+ }
+ if (--this_request->nsector) {
+ port_write(HD_DATA,this_request->bh->b_data+512,256);
+ return;
+ }
+ this_request->bh->b_uptodate = 1;
+ this_request->bh->b_dirt = 0;
+ wake_up(&wait_for_request);
+ unlock_buffer(this_request->bh);
+ this_request->hd = -1;
+ this_request=this_request->next;
+ do_request();
+}
+
+static void do_request(void)
+{
+ int i,r;
+
+ if (sorting)
+ return;
+ if (!this_request) {
+ do_hd=NULL;
+ return;
+ }
+ if (this_request->cmd == WIN_WRITE) {
+ hd_out(this_request->hd,this_request->nsector,this_request->
+ sector,this_request->head,this_request->cyl,
+ this_request->cmd,&write_intr);
+ for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
+ /* nothing */ ;
+ if (!r) {
+ reset_hd(this_request->hd);
+ return;
+ }
+ port_write(HD_DATA,this_request->bh->b_data+
+ 512*(this_request->nsector&1),256);
+ } else if (this_request->cmd == WIN_READ) {
+ hd_out(this_request->hd,this_request->nsector,this_request->
+ sector,this_request->head,this_request->cyl,
+ this_request->cmd,&read_intr);
+ } else
+ panic("unknown hd-command");
+}
+
+/*
+ * add-request adds a request to the linked list.
+ * It sets the 'sorting'-variable when doing something
+ * that interrupts shouldn't touch.
+ */
+static void add_request(struct hd_request * req)
+{
+ struct hd_request * tmp;
+
+ if (req->nsector != 2)
+ panic("nsector!=2 not implemented");
+/*
+ * Not to mess up the linked lists, we never touch the two first
+ * entries (not this_request, as it is used by current interrups,
+ * and not this_request->next, as it can be assigned to this_request).
+ * This is not too high a price to pay for the ability of not
+ * disabling interrupts.
+ */
+ sorting=1;
+ if (!(tmp=this_request))
+ this_request=req;
+ else {
+ if (!(tmp->next))
+ tmp->next=req;
+ else {
+ tmp=tmp->next;
+ for ( ; tmp->next ; tmp=tmp->next)
+ if ((IN_ORDER(tmp,req) ||
+ !IN_ORDER(tmp,tmp->next)) &&
+ IN_ORDER(req,tmp->next))
+ break;
+ req->next=tmp->next;
+ tmp->next=req;
+ }
+ }
+ sorting=0;
+/*
+ * NOTE! As a result of sorting, the interrupts may have died down,
+ * as they aren't redone due to locking with sorting=1. They might
+ * also never have started, if this is the first request in the queue,
+ * so we restart them if necessary.
+ */
+ if (!do_hd)
+ do_request();
+}
+
+void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
+ unsigned int cyl,struct buffer_head * bh)
+{
+ struct hd_request * req;
+
+ if (rw!=READ && rw!=WRITE)
+ panic("Bad hd command, must be R/W");
+ lock_buffer(bh);
+repeat:
+ for (req=0+request ; req<NR_REQUEST+request ; req++)
+ if (req->hd<0)
+ break;
+ if (req==NR_REQUEST+request) {
+ sleep_on(&wait_for_request);
+ goto repeat;
+ }
+ req->hd=nr;
+ req->nsector=2;
+ req->sector=sec;
+ req->head=head;
+ req->cyl=cyl;
+ req->cmd = ((rw==READ)?WIN_READ:WIN_WRITE);
+ req->bh=bh;
+ req->errors=0;
+ req->next=NULL;
+ add_request(req);
+ wait_on_buffer(bh);
+}
+
+void hd_init(void)
+{
+ int i;
+
+ for (i=0 ; i<NR_REQUEST ; i++) {
+ request[i].hd = -1;
+ request[i].next = NULL;
+ }
+ for (i=0 ; i<NR_HD ; i++) {
+ hd[i*5].start_sect = 0;
+ hd[i*5].nr_sects = hd_info[i].head*
+ hd_info[i].sect*hd_info[i].cyl;
+ }
+ set_trap_gate(0x2E,&hd_interrupt);
+ outb_p(inb_p(0x21)&0xfb,0x21);
+ outb(inb_p(0xA1)&0xbf,0xA1);
+}
diff --git a/linux/kernel/keyboard.s b/linux/kernel/keyboard.s
new file mode 100644
index 0000000..ba54be5
--- /dev/null
+++ b/linux/kernel/keyboard.s
@@ -0,0 +1,409 @@
+/*
+ * keyboard.s
+ */
+
+.text
+.globl _keyboard_interrupt
+
+/*
+ * these are for the keyboard read functions
+ */
+size = 1024 /* must be a power of two ! And MUST be the same
+ as in tty_io.c !!!! */
+head = 4
+tail = 8
+proc_list = 12
+buf = 16
+
+mode: .byte 0 /* caps, alt, ctrl and shift mode */
+leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
+e0: .byte 0
+
+/*
+ * con_int is the real interrupt routine that reads the
+ * keyboard scan-code and converts it into the appropriate
+ * ascii character(s).
+ */
+_keyboard_interrupt:
+ pushl %eax
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ xorl %al,%al /* %eax is scan code */
+ inb $0x60,%al
+ cmpb $0xe0,%al
+ je set_e0
+ cmpb $0xe1,%al
+ je set_e1
+ call key_table(,%eax,4)
+ movb $0,e0
+e0_e1: inb $0x61,%al
+ jmp 1f
+1: jmp 1f
+1: orb $0x80,%al
+ jmp 1f
+1: jmp 1f
+1: outb %al,$0x61
+ jmp 1f
+1: jmp 1f
+1: andb $0x7F,%al
+ outb %al,$0x61
+ movb $0x20,%al
+ outb %al,$0x20
+ pushl $0
+ call _do_tty_interrupt
+ addl $4,%esp
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ iret
+set_e0: movb $1,e0
+ jmp e0_e1
+set_e1: movb $2,e0
+ jmp e0_e1
+
+/*
+ * This routine fills the buffer with max 8 bytes, taken from
+ * %ebx:%eax. (%edx is high). The bytes are written in the
+ * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
+ */
+put_queue:
+ pushl %ecx
+ pushl %edx
+ movl _table_list,%edx # read-queue for console
+ movl head(%edx),%ecx
+1: movb %al,buf(%edx,%ecx)
+ incl %ecx
+ andl $size-1,%ecx
+ cmpl tail(%edx),%ecx # buffer full - discard everything
+ je 3f
+ shrdl $8,%ebx,%eax
+ je 2f
+ shrl $8,%ebx
+ jmp 1b
+2: movl %ecx,head(%edx)
+ movl proc_list(%edx),%ecx
+ testl %ecx,%ecx
+ je 3f
+ movl $0,(%ecx)
+3: popl %edx
+ popl %ecx
+ ret
+
+ctrl: movb $0x04,%al
+ jmp 1f
+alt: movb $0x10,%al
+1: cmpb $0,e0
+ je 2f
+ addb %al,%al
+2: orb %al,mode
+ ret
+unctrl: movb $0x04,%al
+ jmp 1f
+unalt: movb $0x10,%al
+1: cmpb $0,e0
+ je 2f
+ addb %al,%al
+2: notb %al
+ andb %al,mode
+ ret
+
+lshift:
+ orb $0x01,mode
+ ret
+unlshift:
+ andb $0xfe,mode
+ ret
+rshift:
+ orb $0x02,mode
+ ret
+unrshift:
+ andb $0xfd,mode
+ ret
+
+caps: testb $0x80,mode
+ jne 1f
+ xorb $4,leds
+ xorb $0x40,mode
+ orb $0x80,mode
+set_leds:
+ call kb_wait
+ movb $0xed,%al /* set leds command */
+ outb %al,$0x60
+ call kb_wait
+ movb leds,%al
+ outb %al,$0x60
+ ret
+uncaps: andb $0x7f,mode
+ ret
+scroll:
+ xorb $1,leds
+ jmp set_leds
+num: xorb $2,leds
+ jmp set_leds
+
+/*
+ * curosr-key/numeric keypad cursor keys are handled here.
+ * checking for numeric keypad etc.
+ */
+cursor:
+ subb $0x47,%al
+ jb 1f
+ cmpb $12,%al
+ ja 1f
+ jne cur2 /* check for ctrl-alt-del */
+ testb $0x0c,mode
+ je cur2
+ testb $0x30,mode
+ jne reboot
+cur2: cmpb $0x01,e0 /* e0 forces cursor movement */
+ je cur
+ testb $0x02,leds /* not num-lock forces cursor */
+ je cur
+ testb $0x03,mode /* shift forces cursor */
+ jne cur
+ xorl %ebx,%ebx
+ movb num_table(%eax),%al
+ jmp put_queue
+1: ret
+
+cur: movb cur_table(%eax),%al
+ cmpb $'9,%al
+ ja ok_cur
+ movb $'~,%ah
+ok_cur: shll $16,%eax
+ movw $0x5b1b,%ax
+ xorl %ebx,%ebx
+ jmp put_queue
+
+num_table:
+ .ascii "789 456 1230,"
+cur_table:
+ .ascii "HA5 DGC YB623"
+
+/*
+ * this routine handles function keys
+ */
+func:
+ subb $0x3B,%al
+ jb end_func
+ cmpb $9,%al
+ jbe ok_func
+ subb $18,%al
+ cmpb $10,%al
+ jb end_func
+ cmpb $11,%al
+ ja end_func
+ok_func:
+ cmpl $4,%ecx /* check that there is enough room */
+ jl end_func
+ movl func_table(,%eax,4),%eax
+ xorl %ebx,%ebx
+ jmp put_queue
+end_func:
+ ret
+
+/*
+ * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
+ */
+func_table:
+ .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
+ .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
+ .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
+
+key_map:
+ .byte 0,27
+ .ascii "1234567890+'"
+ .byte 127,9
+ .ascii "qwertyuiop}"
+ .byte 0,10,0
+ .ascii "asdfghjkl|{"
+ .byte 0,0
+ .ascii "'zxcvbnm,.-"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '<
+ .fill 10,1,0
+
+shift_map:
+ .byte 0,27
+ .ascii "!\"#$%&/()=?`"
+ .byte 127,9
+ .ascii "QWERTYUIOP]^"
+ .byte 10,0
+ .ascii "ASDFGHJKL\\["
+ .byte 0,0
+ .ascii "*ZXCVBNM;:_"
+ .byte 0,'*,0,32 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte '-,0,0,0,'+ /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '>
+ .fill 10,1,0
+
+alt_map:
+ .byte 0,0
+ .ascii "\0@\0$\0\0{[]}\\\0"
+ .byte 0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte '~,10,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0,0,0 /* 36-39 */
+ .fill 16,1,0 /* 3A-49 */
+ .byte 0,0,0,0,0 /* 4A-4E */
+ .byte 0,0,0,0,0,0,0 /* 4F-55 */
+ .byte '|
+ .fill 10,1,0
+
+/*
+ * do_self handles "normal" keys, ie keys that don't change meaning
+ * and which have just one character returns.
+ */
+do_self:
+ lea alt_map,%ebx
+ testb $0x20,mode /* alt-gr */
+ jne 1f
+ lea shift_map,%ebx
+ testb $0x03,mode
+ jne 1f
+ lea key_map,%ebx
+1: movb (%ebx,%eax),%al
+ orb %al,%al
+ je none
+ testb $0x4c,mode /* ctrl or caps */
+ je 2f
+ cmpb $'a,%al
+ jb 2f
+ cmpb $'z,%al
+ ja 2f
+ subb $32,%al
+2: testb $0x0c,mode /* ctrl */
+ je 3f
+ cmpb $64,%al
+ jb 3f
+ cmpb $64+32,%al
+ jae 3f
+ subb $64,%al
+3: testb $0x10,mode /* left alt */
+ je 4f
+ orb $0x80,%al
+4: andl $0xff,%eax
+ xorl %ebx,%ebx
+ call put_queue
+none: ret
+
+/*
+ * minus has a routine of it's own, as a 'E0h' before
+ * the scan code for minus means that the numeric keypad
+ * slash was pushed.
+ */
+minus: cmpb $1,e0
+ jne do_self
+ movl $'/,%eax
+ xorl %ebx,%ebx
+ jmp put_queue
+
+/*
+ * This table decides which routine to call when a scan-code has been
+ * gotten. Most routines just call do_self, or none, depending if
+ * they are make or break.
+ */
+key_table:
+ .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
+ .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
+ .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
+ .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
+ .long do_self,do_self,do_self,do_self /* 10-13 q w e r */
+ .long do_self,do_self,do_self,do_self /* 14-17 t y u i */
+ .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */
+ .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */
+ .long do_self,do_self,do_self,do_self /* 20-23 d f g h */
+ .long do_self,do_self,do_self,do_self /* 24-27 j k l | */
+ .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */
+ .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */
+ .long do_self,do_self,do_self,do_self /* 30-33 b n m , */
+ .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */
+ .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */
+ .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */
+ .long func,func,func,func /* 40-43 f6 f7 f8 f9 */
+ .long func,num,scroll,cursor /* 44-47 f10 num scr home */
+ .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */
+ .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */
+ .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */
+ .long none,none,do_self,func /* 54-57 sysreq ? < f11 */
+ .long func,none,none,none /* 58-5B f12 ? ? ? */
+ .long none,none,none,none /* 5C-5F ? ? ? ? */
+ .long none,none,none,none /* 60-63 ? ? ? ? */
+ .long none,none,none,none /* 64-67 ? ? ? ? */
+ .long none,none,none,none /* 68-6B ? ? ? ? */
+ .long none,none,none,none /* 6C-6F ? ? ? ? */
+ .long none,none,none,none /* 70-73 ? ? ? ? */
+ .long none,none,none,none /* 74-77 ? ? ? ? */
+ .long none,none,none,none /* 78-7B ? ? ? ? */
+ .long none,none,none,none /* 7C-7F ? ? ? ? */
+ .long none,none,none,none /* 80-83 ? br br br */
+ .long none,none,none,none /* 84-87 br br br br */
+ .long none,none,none,none /* 88-8B br br br br */
+ .long none,none,none,none /* 8C-8F br br br br */
+ .long none,none,none,none /* 90-93 br br br br */
+ .long none,none,none,none /* 94-97 br br br br */
+ .long none,none,none,none /* 98-9B br br br br */
+ .long none,unctrl,none,none /* 9C-9F br unctrl br br */
+ .long none,none,none,none /* A0-A3 br br br br */
+ .long none,none,none,none /* A4-A7 br br br br */
+ .long none,none,unlshift,none /* A8-AB br br unlshift br */
+ .long none,none,none,none /* AC-AF br br br br */
+ .long none,none,none,none /* B0-B3 br br br br */
+ .long none,none,unrshift,none /* B4-B7 br br unrshift br */
+ .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */
+ .long none,none,none,none /* BC-BF br br br br */
+ .long none,none,none,none /* C0-C3 br br br br */
+ .long none,none,none,none /* C4-C7 br br br br */
+ .long none,none,none,none /* C8-CB br br br br */
+ .long none,none,none,none /* CC-CF br br br br */
+ .long none,none,none,none /* D0-D3 br br br br */
+ .long none,none,none,none /* D4-D7 br br br br */
+ .long none,none,none,none /* D8-DB br ? ? ? */
+ .long none,none,none,none /* DC-DF ? ? ? ? */
+ .long none,none,none,none /* E0-E3 e0 e1 ? ? */
+ .long none,none,none,none /* E4-E7 ? ? ? ? */
+ .long none,none,none,none /* E8-EB ? ? ? ? */
+ .long none,none,none,none /* EC-EF ? ? ? ? */
+ .long none,none,none,none /* F0-F3 ? ? ? ? */
+ .long none,none,none,none /* F4-F7 ? ? ? ? */
+ .long none,none,none,none /* F8-FB ? ? ? ? */
+ .long none,none,none,none /* FC-FF ? ? ? ? */
+
+/*
+ * kb_wait waits for the keyboard controller buffer to empty.
+ * there is no timeout - if the buffer doesn't empty, we hang.
+ */
+kb_wait:
+ pushl %eax
+1: inb $0x64,%al
+ testb $0x02,%al
+ jne 1b
+ popl %eax
+ ret
+/*
+ * This routine reboots the machine by asking the keyboard
+ * controller to pulse the reset-line low.
+ */
+reboot:
+ call kb_wait
+ movw $0x1234,0x472 /* don't do memory check */
+ movb $0xfc,%al /* pulse reset and A20 low */
+ outb %al,$0x64
+die: jmp die
diff --git a/linux/kernel/mktime.c b/linux/kernel/mktime.c
new file mode 100644
index 0000000..3ba79be
--- /dev/null
+++ b/linux/kernel/mktime.c
@@ -0,0 +1,52 @@
+#include <time.h>
+
+/*
+ * This isn't the library routine, it is only used in the kernel.
+ * as such, we don't care about years<1970 etc, but assume everything
+ * is ok. Similarly, TZ etc is happily ignored. We just do everything
+ * as easily as possible. Let's find something public for the library
+ * routines (although I think minix times is public).
+ */
+/*
+ * PS. I hate whoever though up the year 1970 - couldn't they have gotten
+ * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy.
+ */
+#define MINUTE 60
+#define HOUR (60*MINUTE)
+#define DAY (24*HOUR)
+#define YEAR (365*DAY)
+
+/* interestingly, we assume leap-years */
+static int month[12] = {
+ 0,
+ DAY*(31),
+ DAY*(31+29),
+ DAY*(31+29+31),
+ DAY*(31+29+31+30),
+ DAY*(31+29+31+30+31),
+ DAY*(31+29+31+30+31+30),
+ DAY*(31+29+31+30+31+30+31),
+ DAY*(31+29+31+30+31+30+31+31),
+ DAY*(31+29+31+30+31+30+31+31+30),
+ DAY*(31+29+31+30+31+30+31+31+30+31),
+ DAY*(31+29+31+30+31+30+31+31+30+31+30)
+};
+
+long kernel_mktime(struct tm * tm)
+{
+ long res;
+ int year;
+
+ year = tm->tm_year - 70;
+/* magic offsets (y+1) needed to get leapyears right.*/
+ res = YEAR*year + DAY*((year+1)/4);
+ res += month[tm->tm_mon];
+/* and (y+2) here. If it wasn't a leap-year, we have to adjust */
+ if (tm->tm_mon>1 && ((year+2)%4))
+ res -= DAY;
+ res += DAY*(tm->tm_mday-1);
+ res += HOUR*tm->tm_hour;
+ res += MINUTE*tm->tm_min;
+ res += tm->tm_sec;
+ return res;
+}
diff --git a/linux/kernel/panic.c b/linux/kernel/panic.c
new file mode 100644
index 0000000..feab0cc
--- /dev/null
+++ b/linux/kernel/panic.c
@@ -0,0 +1,11 @@
+/*
+ * This function is used through-out the kernel (includeinh mm and fs)
+ * to indicate a major problem.
+ */
+#include <linux/kernel.h>
+
+volatile void panic(const char * s)
+{
+ printk("Kernel panic: %s\n\r",s);
+ for(;;);
+}
diff --git a/linux/kernel/printk.c b/linux/kernel/printk.c
new file mode 100644
index 0000000..7a70dc3
--- /dev/null
+++ b/linux/kernel/printk.c
@@ -0,0 +1,33 @@
+/*
+ * When in kernel-mode, we cannot use printf, as fs is liable to
+ * point to 'interesting' things. Make a printf with fs-saving, and
+ * all is well.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+
+#include <linux/kernel.h>
+
+static char buf[1024];
+
+int printk(const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsprintf(buf,fmt,args);
+ va_end(args);
+ __asm__("push %%fs\n\t"
+ "push %%ds\n\t"
+ "pop %%fs\n\t"
+ "pushl %0\n\t"
+ "pushl $_buf\n\t"
+ "pushl $0\n\t"
+ "call _tty_write\n\t"
+ "addl $8,%%esp\n\t"
+ "popl %0\n\t"
+ "pop %%fs"
+ ::"r" (i):"ax","cx","dx");
+ return i;
+}
diff --git a/linux/kernel/rs_io.s b/linux/kernel/rs_io.s
new file mode 100644
index 0000000..62f075f
--- /dev/null
+++ b/linux/kernel/rs_io.s
@@ -0,0 +1,141 @@
+/*
+ * rs_io.s
+ *
+ * This module implements the rs232 io interrupts.
+ */
+
+.text
+.globl _rs1_interrupt,_rs2_interrupt
+
+size = 1024 /* must be power of two !
+ and must match the value
+ in tty_io.c!!! */
+
+/* these are the offsets into the read/write buffer structures */
+rs_addr = 0
+head = 4
+tail = 8
+proc_list = 12
+buf = 16
+
+startup = 256 /* chars left in write queue when we restart it */
+
+/*
+ * These are the actual interrupt routines. They look where
+ * the interrupt is coming from, and take appropriate action.
+ */
+.align 2
+_rs1_interrupt:
+ pushl $_table_list+8
+ jmp rs_int
+.align 2
+_rs2_interrupt:
+ pushl $_table_list+16
+rs_int:
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ pushl %eax
+ push %es
+ push %ds /* as this is an interrupt, we cannot */
+ pushl $0x10 /* know that bs is ok. Load it */
+ pop %ds
+ pushl $0x10
+ pop %es
+ movl 24(%esp),%edx
+ movl (%edx),%edx
+ movl rs_addr(%edx),%edx
+ addl $2,%edx /* interrupt ident. reg */
+rep_int:
+ xorl %eax,%eax
+ inb %dx,%al
+ testb $1,%al
+ jne end
+ cmpb $6,%al /* this shouldn't happen, but ... */
+ ja end
+ movl 24(%esp),%ecx
+ pushl %edx
+ subl $2,%edx
+ call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */
+ popl %edx
+ jmp rep_int
+end: movb $0x20,%al
+ outb %al,$0x20 /* EOI */
+ pop %ds
+ pop %es
+ popl %eax
+ popl %ebx
+ popl %ecx
+ popl %edx
+ addl $4,%esp # jump over _table_list entry
+ iret
+
+jmp_table:
+ .long modem_status,write_char,read_char,line_status
+
+.align 2
+modem_status:
+ addl $6,%edx /* clear intr by reading modem status reg */
+ inb %dx,%al
+ ret
+
+.align 2
+line_status:
+ addl $5,%edx /* clear intr by reading line status reg. */
+ inb %dx,%al
+ ret
+
+.align 2
+read_char:
+ inb %dx,%al
+ movl %ecx,%edx
+ subl $_table_list,%edx
+ shrl $3,%edx
+ movl (%ecx),%ecx # read-queue
+ movl head(%ecx),%ebx
+ movb %al,buf(%ecx,%ebx)
+ incl %ebx
+ andl $size-1,%ebx
+ cmpl tail(%ecx),%ebx
+ je 1f
+ movl %ebx,head(%ecx)
+ pushl %edx
+ call _do_tty_interrupt
+ addl $4,%esp
+1: ret
+
+.align 2
+write_char:
+ movl 4(%ecx),%ecx # write-queue
+ movl head(%ecx),%ebx
+ subl tail(%ecx),%ebx
+ andl $size-1,%ebx # nr chars in queue
+ je write_buffer_empty
+ cmpl $startup,%ebx
+ ja 1f
+ movl proc_list(%ecx),%ebx # wake up sleeping process
+ testl %ebx,%ebx # is there any?
+ je 1f
+ movl $0,(%ebx)
+1: movl tail(%ecx),%ebx
+ movb buf(%ecx,%ebx),%al
+ outb %al,%dx
+ incl %ebx
+ andl $size-1,%ebx
+ movl %ebx,tail(%ecx)
+ cmpl head(%ecx),%ebx
+ je write_buffer_empty
+ ret
+.align 2
+write_buffer_empty:
+ movl proc_list(%ecx),%ebx # wake up sleeping process
+ testl %ebx,%ebx # is there any?
+ je 1f
+ movl $0,(%ebx)
+1: incl %edx
+ inb %dx,%al
+ jmp 1f
+1: jmp 1f
+1: andb $0xd,%al /* disable transmit interrupt */
+ outb %al,%dx
+ ret
diff --git a/linux/kernel/sched.c b/linux/kernel/sched.c
new file mode 100644
index 0000000..03399fa
--- /dev/null
+++ b/linux/kernel/sched.c
@@ -0,0 +1,254 @@
+/*
+ * 'sched.c' is the main kernel file. It contains scheduling primitives
+ * (sleep_on, wakeup, schedule etc) as well as a number of simple system
+ * call functions (type getpid(), which just extracts a field from
+ * current-task
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <signal.h>
+#include <linux/sys.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#define LATCH (1193180/HZ)
+
+extern void mem_use(void);
+
+extern int timer_interrupt(void);
+extern int system_call(void);
+
+union task_union {
+ struct task_struct task;
+ char stack[PAGE_SIZE];
+};
+
+static union task_union init_task = {INIT_TASK,};
+
+long volatile jiffies=0;
+long startup_time=0;
+struct task_struct *current = &(init_task.task), *last_task_used_math = NULL;
+
+struct task_struct * task[NR_TASKS] = {&(init_task.task), };
+
+long user_stack [ PAGE_SIZE>>2 ] ;
+
+struct {
+ long * a;
+ short b;
+ } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
+/*
+ * 'math_state_restore()' saves the current math information in the
+ * old math state array, and gets the new ones from the current task
+ */
+void math_state_restore()
+{
+ if (last_task_used_math)
+ __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
+ if (current->used_math)
+ __asm__("frstor %0"::"m" (current->tss.i387));
+ else {
+ __asm__("fninit"::);
+ current->used_math=1;
+ }
+ last_task_used_math=current;
+}
+
+/*
+ * 'schedule()' is the scheduler function. This is GOOD CODE! There
+ * probably won't be any reason to change this, as it should work well
+ * in all circumstances (ie gives IO-bound processes good response etc).
+ * The one thing you might take a look at is the signal-handler code here.
+ *
+ * NOTE!! Task 0 is the 'idle' task, which gets called when no other
+ * tasks can run. It can not be killed, and it cannot sleep. The 'state'
+ * information in task[0] is never used.
+ */
+void schedule(void)
+{
+ int i,next,c;
+ struct task_struct ** p;
+
+/* check alarm, wake up any interruptible tasks that have got a signal */
+
+ for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if (*p) {
+ if ((*p)->alarm && (*p)->alarm < jiffies) {
+ (*p)->signal |= (1<<(SIGALRM-1));
+ (*p)->alarm = 0;
+ }
+ if ((*p)->signal && (*p)->state==TASK_INTERRUPTIBLE)
+ (*p)->state=TASK_RUNNING;
+ }
+
+/* this is the scheduler proper: */
+
+ while (1) {
+ c = -1;
+ next = 0;
+ i = NR_TASKS;
+ p = &task[NR_TASKS];
+ while (--i) {
+ if (!*--p)
+ continue;
+ if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
+ c = (*p)->counter, next = i;
+ }
+ if (c) break;
+ for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if (*p)
+ (*p)->counter = ((*p)->counter >> 1) +
+ (*p)->priority;
+ }
+ switch_to(next);
+}
+
+int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return 0;
+}
+
+void sleep_on(struct task_struct **p)
+{
+ struct task_struct *tmp;
+
+ if (!p)
+ return;
+ if (current == &(init_task.task))
+ panic("task[0] trying to sleep");
+ tmp = *p;
+ *p = current;
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule();
+ if (tmp)
+ tmp->state=0;
+}
+
+void interruptible_sleep_on(struct task_struct **p)
+{
+ struct task_struct *tmp;
+
+ if (!p)
+ return;
+ if (current == &(init_task.task))
+ panic("task[0] trying to sleep");
+ tmp=*p;
+ *p=current;
+repeat: current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (*p && *p != current) {
+ (**p).state=0;
+ goto repeat;
+ }
+ *p=NULL;
+ if (tmp)
+ tmp->state=0;
+}
+
+void wake_up(struct task_struct **p)
+{
+ if (p && *p) {
+ (**p).state=0;
+ *p=NULL;
+ }
+}
+
+void do_timer(long cpl)
+{
+ if (cpl)
+ current->utime++;
+ else
+ current->stime++;
+ if ((--current->counter)>0) return;
+ current->counter=0;
+ if (!cpl) return;
+ schedule();
+}
+
+int sys_alarm(long seconds)
+{
+ current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
+ return seconds;
+}
+
+int sys_getpid(void)
+{
+ return current->pid;
+}
+
+int sys_getppid(void)
+{
+ return current->father;
+}
+
+int sys_getuid(void)
+{
+ return current->uid;
+}
+
+int sys_geteuid(void)
+{
+ return current->euid;
+}
+
+int sys_getgid(void)
+{
+ return current->gid;
+}
+
+int sys_getegid(void)
+{
+ return current->egid;
+}
+
+int sys_nice(long increment)
+{
+ if (current->priority-increment>0)
+ current->priority -= increment;
+ return 0;
+}
+
+int sys_signal(long signal,long addr,long restorer)
+{
+ long i;
+
+ switch (signal) {
+ case SIGHUP: case SIGINT: case SIGQUIT: case SIGILL:
+ case SIGTRAP: case SIGABRT: case SIGFPE: case SIGUSR1:
+ case SIGSEGV: case SIGUSR2: case SIGPIPE: case SIGALRM:
+ case SIGCHLD:
+ i=(long) current->sig_fn[signal-1];
+ current->sig_fn[signal-1] = (fn_ptr) addr;
+ current->sig_restorer = (fn_ptr) restorer;
+ return i;
+ default: return -1;
+ }
+}
+
+void sched_init(void)
+{
+ int i;
+ struct desc_struct * p;
+
+ set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
+ set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
+ p = gdt+2+FIRST_TSS_ENTRY;
+ for(i=1;i<NR_TASKS;i++) {
+ task[i] = NULL;
+ p->a=p->b=0;
+ p++;
+ p->a=p->b=0;
+ p++;
+ }
+ ltr(0);
+ lldt(0);
+ outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
+ set_intr_gate(0x20,&timer_interrupt);
+ outb(inb_p(0x21)&~0x01,0x21);
+ set_system_gate(0x80,&system_call);
+}
diff --git a/linux/kernel/serial.c b/linux/kernel/serial.c
new file mode 100644
index 0000000..f542513
--- /dev/null
+++ b/linux/kernel/serial.c
@@ -0,0 +1,53 @@
+/*
+ * serial.c
+ *
+ * This module implements the rs232 io functions
+ * void rs_write(struct tty_struct * queue);
+ * void rs_init(void);
+ * and all interrupts pertaining to serial IO.
+ */
+
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#define WAKEUP_CHARS (TTY_BUF_SIZE/4)
+
+extern void rs1_interrupt(void);
+extern void rs2_interrupt(void);
+
+static void init(int port)
+{
+ outb_p(0x80,port+3); /* set DLAB of line control reg */
+ outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
+ outb_p(0x00,port+1); /* MS of divisor */
+ outb_p(0x03,port+3); /* reset DLAB */
+ outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */
+ outb_p(0x0d,port+1); /* enable all intrs but writes */
+ (void)inb(port); /* read data port to reset things (?) */
+}
+
+void rs_init(void)
+{
+ set_intr_gate(0x24,rs1_interrupt);
+ set_intr_gate(0x23,rs2_interrupt);
+ init(tty_table[1].read_q.data);
+ init(tty_table[2].read_q.data);
+ outb(inb_p(0x21)&0xE7,0x21);
+}
+
+/*
+ * This routine gets called when tty_write has put something into
+ * the write_queue. It must check wheter the queue is empty, and
+ * set the interrupt register accordingly
+ *
+ * void _rs_write(struct tty_struct * tty);
+ */
+void rs_write(struct tty_struct * tty)
+{
+ cli();
+ if (!EMPTY(tty->write_q))
+ outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1);
+ sti();
+}
diff --git a/linux/kernel/sys.c b/linux/kernel/sys.c
new file mode 100644
index 0000000..f18ee7e
--- /dev/null
+++ b/linux/kernel/sys.c
@@ -0,0 +1,216 @@
+#include <errno.h>
+
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <sys/times.h>
+#include <sys/utsname.h>
+
+int sys_ftime()
+{
+ return -ENOSYS;
+}
+
+int sys_mknod()
+{
+ return -ENOSYS;
+}
+
+int sys_break()
+{
+ return -ENOSYS;
+}
+
+int sys_mount()
+{
+ return -ENOSYS;
+}
+
+int sys_umount()
+{
+ return -ENOSYS;
+}
+
+int sys_ustat(int dev,struct ustat * ubuf)
+{
+ return -1;
+}
+
+int sys_ptrace()
+{
+ return -ENOSYS;
+}
+
+int sys_stty()
+{
+ return -ENOSYS;
+}
+
+int sys_gtty()
+{
+ return -ENOSYS;
+}
+
+int sys_rename()
+{
+ return -ENOSYS;
+}
+
+int sys_prof()
+{
+ return -ENOSYS;
+}
+
+int sys_setgid(int gid)
+{
+ if (current->euid && current->uid)
+ if (current->gid==gid || current->sgid==gid)
+ current->egid=gid;
+ else
+ return -EPERM;
+ else
+ current->gid=current->egid=gid;
+ return 0;
+}
+
+int sys_acct()
+{
+ return -ENOSYS;
+}
+
+int sys_phys()
+{
+ return -ENOSYS;
+}
+
+int sys_lock()
+{
+ return -ENOSYS;
+}
+
+int sys_mpx()
+{
+ return -ENOSYS;
+}
+
+int sys_ulimit()
+{
+ return -ENOSYS;
+}
+
+int sys_time(long * tloc)
+{
+ int i;
+
+ i = CURRENT_TIME;
+ if (tloc) {
+ verify_area(tloc,4);
+ put_fs_long(i,(unsigned long *)tloc);
+ }
+ return i;
+}
+
+int sys_setuid(int uid)
+{
+ if (current->euid && current->uid)
+ if (uid==current->uid || current->suid==current->uid)
+ current->euid=uid;
+ else
+ return -EPERM;
+ else
+ current->euid=current->uid=uid;
+ return 0;
+}
+
+int sys_stime(long * tptr)
+{
+ if (current->euid && current->uid)
+ return -1;
+ startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
+ return 0;
+}
+
+int sys_times(struct tms * tbuf)
+{
+ if (!tbuf)
+ return jiffies;
+ verify_area(tbuf,sizeof *tbuf);
+ put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
+ put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
+ put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
+ put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
+ return jiffies;
+}
+
+int sys_brk(unsigned long end_data_seg)
+{
+ if (end_data_seg >= current->end_code &&
+ end_data_seg < current->start_stack - 16384)
+ current->brk = end_data_seg;
+ return current->brk;
+}
+
+/*
+ * This needs some heave checking ...
+ * I just haven't get the stomach for it. I also don't fully
+ * understand sessions/pgrp etc. Let somebody who does explain it.
+ */
+int sys_setpgid(int pid, int pgid)
+{
+ int i;
+
+ if (!pid)
+ pid = current->pid;
+ if (!pgid)
+ pgid = pid;
+ for (i=0 ; i<NR_TASKS ; i++)
+ if (task[i] && task[i]->pid==pid) {
+ if (task[i]->leader)
+ return -EPERM;
+ if (task[i]->session != current->session)
+ return -EPERM;
+ task[i]->pgrp = pgid;
+ return 0;
+ }
+ return -ESRCH;
+}
+
+int sys_getpgrp(void)
+{
+ return current->pgrp;
+}
+
+int sys_setsid(void)
+{
+ if (current->uid && current->euid)
+ return -EPERM;
+ if (current->leader)
+ return -EPERM;
+ current->leader = 1;
+ current->session = current->pgrp = current->pid;
+ current->tty = -1;
+ return current->pgrp;
+}
+
+int sys_uname(struct utsname * name)
+{
+ static struct utsname thisname = {
+ "linux .0","nodename","release ","version ","machine "
+ };
+ int i;
+
+ if (!name) return -1;
+ verify_area(name,sizeof *name);
+ for(i=0;i<sizeof *name;i++)
+ put_fs_byte(((char *) &thisname)[i],i+(char *) name);
+ return (0);
+}
+
+int sys_umask(int mask)
+{
+ int old = current->umask;
+
+ current->umask = mask & 0777;
+ return (old);
+}
diff --git a/linux/kernel/system_call.s b/linux/kernel/system_call.s
new file mode 100644
index 0000000..df4f072
--- /dev/null
+++ b/linux/kernel/system_call.s
@@ -0,0 +1,219 @@
+/*
+ * system_call.s contains the system-call low-level handling routines.
+ * This also contains the timer-interrupt handler, as some of the code is
+ * the same. The hd-interrupt is also here.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call. Ordinary interrupts
+ * don't handle signal-recognition, as that would clutter them up totally
+ * unnecessarily.
+ *
+ * Stack layout in 'ret_from_system_call':
+ *
+ * 0(%esp) - %eax
+ * 4(%esp) - %ebx
+ * 8(%esp) - %ecx
+ * C(%esp) - %edx
+ * 10(%esp) - %fs
+ * 14(%esp) - %es
+ * 18(%esp) - %ds
+ * 1C(%esp) - %eip
+ * 20(%esp) - %cs
+ * 24(%esp) - %eflags
+ * 28(%esp) - %oldesp
+ * 2C(%esp) - %oldss
+ */
+
+SIG_CHLD = 17
+EAX = 0x00
+EBX = 0x04
+ECX = 0x08
+EDX = 0x0C
+FS = 0x10
+ES = 0x14
+DS = 0x18
+EIP = 0x1C
+CS = 0x20
+EFLAGS = 0x24
+OLDESP = 0x28
+OLDSS = 0x2C
+
+state = 0 # these are offsets into the task-struct.
+counter = 4
+priority = 8
+signal = 12
+restorer = 16 # address of info-restorer
+sig_fn = 20 # table of 32 signal addresses
+
+nr_system_calls = 67
+
+.globl _system_call,_sys_fork,_timer_interrupt,_hd_interrupt,_sys_execve
+
+.align 2
+bad_sys_call:
+ movl $-1,%eax
+ iret
+.align 2
+reschedule:
+ pushl $ret_from_sys_call
+ jmp _schedule
+.align 2
+_system_call:
+ cmpl $nr_system_calls-1,%eax
+ ja bad_sys_call
+ push %ds
+ push %es
+ push %fs
+ pushl %edx
+ pushl %ecx # push %ebx,%ecx,%edx as parameters
+ pushl %ebx # to the system call
+ movl $0x10,%edx # set up ds,es to kernel space
+ mov %dx,%ds
+ mov %dx,%es
+ movl $0x17,%edx # fs points to local data space
+ mov %dx,%fs
+ call _sys_call_table(,%eax,4)
+ pushl %eax
+ movl _current,%eax
+ cmpl $0,state(%eax) # state
+ jne reschedule
+ cmpl $0,counter(%eax) # counter
+ je reschedule
+ret_from_sys_call:
+ movl _current,%eax # task[0] cannot have signals
+ cmpl _task,%eax
+ je 3f
+ movl CS(%esp),%ebx # was old code segment supervisor
+ testl $3,%ebx # mode? If so - don't check signals
+ je 3f
+ cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
+ jne 3f
+2: movl signal(%eax),%ebx # signals (bitmap, 32 signals)
+ bsfl %ebx,%ecx # %ecx is signal nr, return if none
+ je 3f
+ btrl %ecx,%ebx # clear it
+ movl %ebx,signal(%eax)
+ movl sig_fn(%eax,%ecx,4),%ebx # %ebx is signal handler address
+ cmpl $1,%ebx
+ jb default_signal # 0 is default signal handler - exit
+ je 2b # 1 is ignore - find next signal
+ movl $0,sig_fn(%eax,%ecx,4) # reset signal handler address
+ incl %ecx
+ xchgl %ebx,EIP(%esp) # put new return address on stack
+ subl $28,OLDESP(%esp)
+ movl OLDESP(%esp),%edx # push old return address on stack
+ pushl %eax # but first check that it's ok.
+ pushl %ecx
+ pushl $28
+ pushl %edx
+ call _verify_area
+ popl %edx
+ addl $4,%esp
+ popl %ecx
+ popl %eax
+ movl restorer(%eax),%eax
+ movl %eax,%fs:(%edx) # flag/reg restorer
+ movl %ecx,%fs:4(%edx) # signal nr
+ movl EAX(%esp),%eax
+ movl %eax,%fs:8(%edx) # old eax
+ movl ECX(%esp),%eax
+ movl %eax,%fs:12(%edx) # old ecx
+ movl EDX(%esp),%eax
+ movl %eax,%fs:16(%edx) # old edx
+ movl EFLAGS(%esp),%eax
+ movl %eax,%fs:20(%edx) # old eflags
+ movl %ebx,%fs:24(%edx) # old return addr
+3: popl %eax
+ popl %ebx
+ popl %ecx
+ popl %edx
+ pop %fs
+ pop %es
+ pop %ds
+ iret
+
+default_signal:
+ incl %ecx
+ cmpl $SIG_CHLD,%ecx
+ je 2b
+ pushl %ecx
+ call _do_exit # remember to set bit 7 when dumping core
+ addl $4,%esp
+ jmp 3b
+
+.align 2
+_timer_interrupt:
+ push %ds # save ds,es and put kernel data space
+ push %es # into them. %fs is used by _system_call
+ push %fs
+ pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
+ pushl %ecx # save those across function calls. %ebx
+ pushl %ebx # is saved as we use that in ret_sys_call
+ pushl %eax
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ incl _jiffies
+ movb $0x20,%al # EOI to interrupt controller #1
+ outb %al,$0x20
+ movl CS(%esp),%eax
+ andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
+ pushl %eax
+ call _do_timer # 'do_timer(long CPL)' does everything from
+ addl $4,%esp # task switching to accounting ...
+ jmp ret_from_sys_call
+
+.align 2
+_sys_execve:
+ lea EIP(%esp),%eax
+ pushl %eax
+ call _do_execve
+ addl $4,%esp
+ ret
+
+.align 2
+_sys_fork:
+ call _find_empty_process
+ testl %eax,%eax
+ js 1f
+ push %gs
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+ pushl %eax
+ call _copy_process
+ addl $20,%esp
+1: ret
+
+_hd_interrupt:
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ movb $0x20,%al
+ outb %al,$0x20 # EOI to interrupt controller #1
+ jmp 1f # give port chance to breathe
+1: jmp 1f
+1: outb %al,$0xA0 # same to controller #2
+ movl _do_hd,%eax
+ testl %eax,%eax
+ jne 1f
+ movl $_unexpected_hd_interrupt,%eax
+1: call *%eax # "interesting" way of handling intr.
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+
diff --git a/linux/kernel/traps.c b/linux/kernel/traps.c
new file mode 100644
index 0000000..b6e8bdb
--- /dev/null
+++ b/linux/kernel/traps.c
@@ -0,0 +1,199 @@
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
+ * to mainly kill the offending process (probably by giving it a signal,
+ * but possibly by killing it outright if necessary).
+ */
+#include <string.h>
+
+#include <linux/head.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+
+#define get_seg_byte(seg,addr) ({ \
+register char __res; \
+__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \
+ :"=a" (__res):"0" (seg),"m" (*(addr))); \
+__res;})
+
+#define get_seg_long(seg,addr) ({ \
+register unsigned long __res; \
+__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \
+ :"=a" (__res):"0" (seg),"m" (*(addr))); \
+__res;})
+
+#define _fs() ({ \
+register unsigned short __res; \
+__asm__("mov %%fs,%%ax":"=a" (__res):); \
+__res;})
+
+int do_exit(long code);
+
+void page_exception(void);
+
+void divide_error(void);
+void debug(void);
+void nmi(void);
+void int3(void);
+void overflow(void);
+void bounds(void);
+void invalid_op(void);
+void device_not_available(void);
+void double_fault(void);
+void coprocessor_segment_overrun(void);
+void invalid_TSS(void);
+void segment_not_present(void);
+void stack_segment(void);
+void general_protection(void);
+void page_fault(void);
+void coprocessor_error(void);
+void reserved(void);
+
+static void die(char * str,long esp_ptr,long nr)
+{
+ long * esp = (long *) esp_ptr;
+ int i;
+
+ printk("%s: %04x\n\r",str,nr&0xffff);
+ printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n",
+ esp[1],esp[0],esp[2],esp[4],esp[3]);
+ printk("fs: %04x\n",_fs());
+ printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17));
+ if (esp[4] == 0x17) {
+ printk("Stack: ");
+ for (i=0;i<4;i++)
+ printk("%p ",get_seg_long(0x17,i+(long *)esp[3]));
+ printk("\n");
+ }
+ str(i);
+ printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i);
+ for(i=0;i<10;i++)
+ printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0])));
+ printk("\n\r");
+ do_exit(11); /* play segment exception */
+}
+
+void do_double_fault(long esp, long error_code)
+{
+ die("double fault",esp,error_code);
+}
+
+void do_general_protection(long esp, long error_code)
+{
+ die("general protection",esp,error_code);
+}
+
+void do_divide_error(long esp, long error_code)
+{
+ die("divide error",esp,error_code);
+}
+
+void do_int3(long * esp, long error_code,
+ long fs,long es,long ds,
+ long ebp,long esi,long edi,
+ long edx,long ecx,long ebx,long eax)
+{
+ int tr;
+
+ __asm__("str %%ax":"=a" (tr):"0" (0));
+ printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r",
+ eax,ebx,ecx,edx);
+ printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r",
+ esi,edi,ebp,(long) esp);
+ printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r",
+ ds,es,fs,tr);
+ printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]);
+}
+
+void do_nmi(long esp, long error_code)
+{
+ die("nmi",esp,error_code);
+}
+
+void do_debug(long esp, long error_code)
+{
+ die("debug",esp,error_code);
+}
+
+void do_overflow(long esp, long error_code)
+{
+ die("overflow",esp,error_code);
+}
+
+void do_bounds(long esp, long error_code)
+{
+ die("bounds",esp,error_code);
+}
+
+void do_invalid_op(long esp, long error_code)
+{
+ die("invalid operand",esp,error_code);
+}
+
+void do_device_not_available(long esp, long error_code)
+{
+ die("device not available",esp,error_code);
+}
+
+void do_coprocessor_segment_overrun(long esp, long error_code)
+{
+ die("coprocessor segment overrun",esp,error_code);
+}
+
+void do_invalid_TSS(long esp,long error_code)
+{
+ die("invalid TSS",esp,error_code);
+}
+
+void do_segment_not_present(long esp,long error_code)
+{
+ die("segment not present",esp,error_code);
+}
+
+void do_stack_segment(long esp,long error_code)
+{
+ die("stack segment",esp,error_code);
+}
+
+void do_coprocessor_error(long esp, long error_code)
+{
+ die("coprocessor error",esp,error_code);
+}
+
+void do_reserved(long esp, long error_code)
+{
+ die("reserved (15,17-31) error",esp,error_code);
+}
+
+void trap_init(void)
+{
+ int i;
+
+ set_trap_gate(0,&divide_error);
+ set_trap_gate(1,&debug);
+ set_trap_gate(2,&nmi);
+ set_system_gate(3,&int3); /* int3-5 can be called from all */
+ set_system_gate(4,&overflow);
+ set_system_gate(5,&bounds);
+ set_trap_gate(6,&invalid_op);
+ set_trap_gate(7,&device_not_available);
+ set_trap_gate(8,&double_fault);
+ set_trap_gate(9,&coprocessor_segment_overrun);
+ set_trap_gate(10,&invalid_TSS);
+ set_trap_gate(11,&segment_not_present);
+ set_trap_gate(12,&stack_segment);
+ set_trap_gate(13,&general_protection);
+ set_trap_gate(14,&page_fault);
+ set_trap_gate(15,&reserved);
+ set_trap_gate(16,&coprocessor_error);
+ for (i=17;i<32;i++)
+ set_trap_gate(i,&reserved);
+/* __asm__("movl $0x3ff000,%%eax\n\t"
+ "movl %%eax,%%db0\n\t"
+ "movl $0x000d0303,%%eax\n\t"
+ "movl %%eax,%%db7"
+ :::"ax");*/
+}
+
diff --git a/linux/kernel/tty_io.c b/linux/kernel/tty_io.c
new file mode 100644
index 0000000..68a390c
--- /dev/null
+++ b/linux/kernel/tty_io.c
@@ -0,0 +1,306 @@
+/*
+ * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
+ * or rs-channels. It also implements echoing, cooked mode etc (well,
+ * not currently, but ...)
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+
+#define ALRMMASK (1<<(SIGALRM-1))
+
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
+#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
+#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
+
+#define L_CANON(tty) _L_FLAG((tty),ICANON)
+#define L_ISIG(tty) _L_FLAG((tty),ISIG)
+#define L_ECHO(tty) _L_FLAG((tty),ECHO)
+#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
+#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
+#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
+#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
+
+#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
+#define I_NLCR(tty) _I_FLAG((tty),INLCR)
+#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
+#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
+
+#define O_POST(tty) _O_FLAG((tty),OPOST)
+#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
+#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
+#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
+#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
+
+struct tty_struct tty_table[] = {
+ {
+ {0,
+ OPOST|ONLCR, /* change outgoing NL to CRNL */
+ 0,
+ ICANON | ECHO | ECHOCTL | ECHOKE,
+ 0, /* console termio */
+ INIT_C_CC},
+ 0, /* initial pgrp */
+ 0, /* initial stopped */
+ con_write,
+ {0,0,0,0,""}, /* console read-queue */
+ {0,0,0,0,""}, /* console write-queue */
+ {0,0,0,0,""} /* console secondary queue */
+ },{
+ {0, /*IGNCR*/
+ OPOST | ONLRET, /* change outgoing NL to CR */
+ B2400 | CS8,
+ 0,
+ 0,
+ INIT_C_CC},
+ 0,
+ 0,
+ rs_write,
+ {0x3f8,0,0,0,""}, /* rs 1 */
+ {0x3f8,0,0,0,""},
+ {0,0,0,0,""}
+ },{
+ {0, /*IGNCR*/
+ OPOST | ONLRET, /* change outgoing NL to CR */
+ B2400 | CS8,
+ 0,
+ 0,
+ INIT_C_CC},
+ 0,
+ 0,
+ rs_write,
+ {0x2f8,0,0,0,""}, /* rs 2 */
+ {0x2f8,0,0,0,""},
+ {0,0,0,0,""}
+ }
+};
+
+/*
+ * these are the tables used by the machine code handlers.
+ * you can implement pseudo-tty's or something by changing
+ * them. Currently not done.
+ */
+struct tty_queue * table_list[]={
+ &tty_table[0].read_q, &tty_table[0].write_q,
+ &tty_table[1].read_q, &tty_table[1].write_q,
+ &tty_table[2].read_q, &tty_table[2].write_q
+ };
+
+void tty_init(void)
+{
+ rs_init();
+ con_init();
+}
+
+void tty_intr(struct tty_struct * tty, int signal)
+{
+ int i;
+
+ if (tty->pgrp <= 0)
+ return;
+ for (i=0;i<NR_TASKS;i++)
+ if (task[i] && task[i]->pgrp==tty->pgrp)
+ task[i]->signal |= 1<<(signal-1);
+}
+
+static void sleep_if_empty(struct tty_queue * queue)
+{
+ cli();
+ while (!current->signal && EMPTY(*queue))
+ interruptible_sleep_on(&queue->proc_list);
+ sti();
+}
+
+static void sleep_if_full(struct tty_queue * queue)
+{
+ if (!FULL(*queue))
+ return;
+ cli();
+ while (!current->signal && LEFT(*queue)<128)
+ interruptible_sleep_on(&queue->proc_list);
+ sti();
+}
+
+void copy_to_cooked(struct tty_struct * tty)
+{
+ signed char c;
+
+ while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
+ GETCH(tty->read_q,c);
+ if (c==13)
+ if (I_CRNL(tty))
+ c=10;
+ else if (I_NOCR(tty))
+ continue;
+ else ;
+ else if (c==10 && I_NLCR(tty))
+ c=13;
+ if (I_UCLC(tty))
+ c=tolower(c);
+ if (L_CANON(tty)) {
+ if (c==ERASE_CHAR(tty)) {
+ if (EMPTY(tty->secondary) ||
+ (c=LAST(tty->secondary))==10 ||
+ c==EOF_CHAR(tty))
+ continue;
+ if (L_ECHO(tty)) {
+ if (c<32)
+ PUTCH(127,tty->write_q);
+ PUTCH(127,tty->write_q);
+ tty->write(tty);
+ }
+ DEC(tty->secondary.head);
+ continue;
+ }
+ if (c==STOP_CHAR(tty)) {
+ tty->stopped=1;
+ continue;
+ }
+ if (c==START_CHAR(tty)) {
+ tty->stopped=0;
+ continue;
+ }
+ }
+ if (!L_ISIG(tty)) {
+ if (c==INTR_CHAR(tty)) {
+ tty_intr(tty,SIGINT);
+ continue;
+ }
+ }
+ if (c==10 || c==EOF_CHAR(tty))
+ tty->secondary.data++;
+ if (L_ECHO(tty)) {
+ if (c==10) {
+ PUTCH(10,tty->write_q);
+ PUTCH(13,tty->write_q);
+ } else if (c<32) {
+ if (L_ECHOCTL(tty)) {
+ PUTCH('^',tty->write_q);
+ PUTCH(c+64,tty->write_q);
+ }
+ } else
+ PUTCH(c,tty->write_q);
+ tty->write(tty);
+ }
+ PUTCH(c,tty->secondary);
+ }
+ wake_up(&tty->secondary.proc_list);
+}
+
+int tty_read(unsigned channel, char * buf, int nr)
+{
+ struct tty_struct * tty;
+ char c, * b=buf;
+ int minimum,time,flag=0;
+ long oldalarm;
+
+ if (channel>2 || nr<0) return -1;
+ tty = &tty_table[channel];
+ oldalarm = current->alarm;
+ time = (unsigned) 10*tty->termios.c_cc[VTIME];
+ minimum = (unsigned) tty->termios.c_cc[VMIN];
+ if (time && !minimum) {
+ minimum=1;
+ if (flag=(!oldalarm || time+jiffies<oldalarm))
+ current->alarm = time+jiffies;
+ }
+ if (minimum>nr)
+ minimum=nr;
+ while (nr>0) {
+ if (flag && (current->signal & ALRMMASK)) {
+ current->signal &= ~ALRMMASK;
+ break;
+ }
+ if (current->signal)
+ break;
+ if (EMPTY(tty->secondary) || (L_CANON(tty) &&
+ !tty->secondary.data && LEFT(tty->secondary)>20)) {
+ sleep_if_empty(&tty->secondary);
+ continue;
+ }
+ do {
+ GETCH(tty->secondary,c);
+ if (c==EOF_CHAR(tty) || c==10)
+ tty->secondary.data--;
+ if (c==EOF_CHAR(tty) && L_CANON(tty))
+ return (b-buf);
+ else {
+ put_fs_byte(c,b++);
+ if (!--nr)
+ break;
+ }
+ } while (nr>0 && !EMPTY(tty->secondary));
+ if (time && !L_CANON(tty))
+ if (flag=(!oldalarm || time+jiffies<oldalarm))
+ current->alarm = time+jiffies;
+ else
+ current->alarm = oldalarm;
+ if (L_CANON(tty)) {
+ if (b-buf)
+ break;
+ } else if (b-buf >= minimum)
+ break;
+ }
+ current->alarm = oldalarm;
+ if (current->signal && !(b-buf))
+ return -EINTR;
+ return (b-buf);
+}
+
+int tty_write(unsigned channel, char * buf, int nr)
+{
+ static cr_flag=0;
+ struct tty_struct * tty;
+ char c, *b=buf;
+
+ if (channel>2 || nr<0) return -1;
+ tty = channel + tty_table;
+ while (nr>0) {
+ sleep_if_full(&tty->write_q);
+ if (current->signal)
+ break;
+ while (nr>0 && !FULL(tty->write_q)) {
+ c=get_fs_byte(b);
+ if (O_POST(tty)) {
+ if (c=='\r' && O_CRNL(tty))
+ c='\n';
+ else if (c=='\n' && O_NLRET(tty))
+ c='\r';
+ if (c=='\n' && !cr_flag && O_NLCR(tty)) {
+ cr_flag = 1;
+ PUTCH(13,tty->write_q);
+ continue;
+ }
+ if (O_LCUC(tty))
+ c=toupper(c);
+ }
+ b++; nr--;
+ cr_flag = 0;
+ PUTCH(c,tty->write_q);
+ }
+ tty->write(tty);
+ if (nr>0)
+ schedule();
+ }
+ return (b-buf);
+}
+
+/*
+ * Jeh, sometimes I really like the 386.
+ * This routine is called from an interrupt,
+ * and there should be absolutely no problem
+ * with sleeping even in an interrupt (I hope).
+ * Of course, if somebody proves me wrong, I'll
+ * hate intel for all time :-). We'll have to
+ * be careful and see to reinstating the interrupt
+ * chips before calling this, though.
+ */
+void do_tty_interrupt(int tty)
+{
+ copy_to_cooked(tty_table+tty);
+}
diff --git a/linux/kernel/vsprintf.c b/linux/kernel/vsprintf.c
new file mode 100644
index 0000000..69c0578
--- /dev/null
+++ b/linux/kernel/vsprintf.c
@@ -0,0 +1,227 @@
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+/* we use this so that we can do without the ctype library */
+#define is_digit(c) ((c) >= '0' && (c) <= '9')
+
+static int skip_atoi(const char **s)
+{
+ int i=0;
+
+ while (is_digit(**s))
+ i = i*10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
+__res; })
+
+static char * number(char * str, int num, int base, int size, int precision
+ ,int type)
+{
+ char c,sign,tmp[36];
+ const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i;
+
+ if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
+ if (type&LEFT) type &= ~ZEROPAD;
+ if (base<2 || base>36)
+ return 0;
+ c = (type & ZEROPAD) ? '0' : ' ' ;
+ if (type&SIGN && num<0) {
+ sign='-';
+ num = -num;
+ } else
+ sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);
+ if (sign) size--;
+ if (type&SPECIAL)
+ if (base==16) size -= 2;
+ else if (base==8) size--;
+ i=0;
+ if (num==0)
+ tmp[i++]='0';
+ else while (num!=0)
+ tmp[i++]=digits[do_div(num,base)];
+ if (i>precision) precision=i;
+ size -= precision;
+ if (!(type&(ZEROPAD+LEFT)))
+ while(size-->0)
+ *str++ = ' ';
+ if (sign)
+ *str++ = sign;
+ if (type&SPECIAL)
+ if (base==8)
+ *str++ = '0';
+ else if (base==16) {
+ *str++ = '0';
+ *str++ = digits[33];
+ }
+ if (!(type&LEFT))
+ while(size-->0)
+ *str++ = c;
+ while(i<precision--)
+ *str++ = '0';
+ while(i-->0)
+ *str++ = tmp[i];
+ while(size-->0)
+ *str++ = ' ';
+ return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ int len;
+ int i;
+ char * str;
+ char *s;
+ int *ip;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+
+ for (str=buf ; *fmt ; ++fmt) {
+ if (*fmt != '%') {
+ *str++ = *fmt;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-': flags |= LEFT; goto repeat;
+ case '+': flags |= PLUS; goto repeat;
+ case ' ': flags |= SPACE; goto repeat;
+ case '#': flags |= SPECIAL; goto repeat;
+ case '0': flags |= ZEROPAD; goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (is_digit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (is_digit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ qualifier = *fmt;
+ ++fmt;
+ }
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT))
+ while (--field_width > 0)
+ *str++ = ' ';
+ *str++ = (unsigned char) va_arg(args, int);
+ while (--field_width > 0)
+ *str++ = ' ';
+ break;
+
+ case 's':
+ s = va_arg(args, char *);
+ len = strlen(s);
+ if (precision < 0)
+ precision = len;
+ else if (len > precision)
+ len = precision;
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ *str++ = ' ';
+ for (i = 0; i < len; ++i)
+ *str++ = *s++;
+ while (len < field_width--)
+ *str++ = ' ';
+ break;
+
+ case 'o':
+ str = number(str, va_arg(args, unsigned long), 8,
+ field_width, precision, flags);
+ break;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 8;
+ flags |= ZEROPAD;
+ }
+ str = number(str,
+ (unsigned long) va_arg(args, void *), 16,
+ field_width, precision, flags);
+ break;
+
+ case 'x':
+ flags |= SMALL;
+ case 'X':
+ str = number(str, va_arg(args, unsigned long), 16,
+ field_width, precision, flags);
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ str = number(str, va_arg(args, unsigned long), 10,
+ field_width, precision, flags);
+ break;
+
+ case 'n':
+ ip = va_arg(args, int *);
+ *ip = (str - buf);
+ break;
+
+ default:
+ if (*fmt != '%')
+ *str++ = '%';
+ if (*fmt)
+ *str++ = *fmt;
+ else
+ --fmt;
+ break;
+ }
+ }
+ *str = '\0';
+ return str-buf;
+}
diff --git a/linux/lib/Makefile b/linux/lib/Makefile
new file mode 100644
index 0000000..a06698d
--- /dev/null
+++ b/linux/lib/Makefile
@@ -0,0 +1,44 @@
+#
+# Makefile for some libs needed in the kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+AR =gar
+AS =gas
+LD =gld
+LDFLAGS =-s -x
+CC =gcc
+CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
+ -finline-functions -mstring-insns -nostdinc -I../include
+CPP =gcc -E -nostdinc -I../include
+
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) \
+ -c -o $*.o $<
+
+OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \
+ execve.o wait.o string.o
+
+lib.a: $(OBJS)
+ $(AR) rcs lib.a $(OBJS)
+ sync
+
+clean:
+ rm -f core *.o *.a tmp_make
+ for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
+ $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
diff --git a/linux/lib/_exit.c b/linux/lib/_exit.c
new file mode 100644
index 0000000..44a74e1
--- /dev/null
+++ b/linux/lib/_exit.c
@@ -0,0 +1,7 @@
+#define __LIBRARY__
+#include <unistd.h>
+
+volatile void _exit(int exit_code)
+{
+ __asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code));
+}
diff --git a/linux/lib/close.c b/linux/lib/close.c
new file mode 100644
index 0000000..182d7eb
--- /dev/null
+++ b/linux/lib/close.c
@@ -0,0 +1,4 @@
+#define __LIBRARY__
+#include <unistd.h>
+
+_syscall1(int,close,int,fd)
diff --git a/linux/lib/ctype.c b/linux/lib/ctype.c
new file mode 100644
index 0000000..bf58aac
--- /dev/null
+++ b/linux/lib/ctype.c
@@ -0,0 +1,29 @@
+#include <ctype.h>
+
+char _ctmp;
+unsigned char _ctype[] = {0x00, /* EOF */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */
+
diff --git a/linux/lib/dup.c b/linux/lib/dup.c
new file mode 100644
index 0000000..03bd5d0
--- /dev/null
+++ b/linux/lib/dup.c
@@ -0,0 +1,4 @@
+#define __LIBRARY__
+#include <unistd.h>
+
+_syscall1(int,dup,int,fd)
diff --git a/linux/lib/errno.c b/linux/lib/errno.c
new file mode 100644
index 0000000..6e7bb62
--- /dev/null
+++ b/linux/lib/errno.c
@@ -0,0 +1 @@
+int errno;
diff --git a/linux/lib/execve.c b/linux/lib/execve.c
new file mode 100644
index 0000000..03772e3
--- /dev/null
+++ b/linux/lib/execve.c
@@ -0,0 +1,4 @@
+#define __LIBRARY__
+#include <unistd.h>
+
+_syscall3(int,execve,const char *,file,char **,argv,char **,envp)
diff --git a/linux/lib/open.c b/linux/lib/open.c
new file mode 100644
index 0000000..057039c
--- /dev/null
+++ b/linux/lib/open.c
@@ -0,0 +1,19 @@
+#define __LIBRARY__
+#include <unistd.h>
+#include <stdarg.h>
+
+int open(const char * filename, int flag, ...)
+{
+ register int res;
+ va_list arg;
+
+ va_start(arg,flag);
+ __asm__("int $0x80"
+ :"=a" (res)
+ :"0" (__NR_open),"b" (filename),"c" (flag),
+ "d" (va_arg(arg,int)));
+ if (res>=0)
+ return res;
+ errno = -res;
+ return -1;
+}
diff --git a/linux/lib/setsid.c b/linux/lib/setsid.c
new file mode 100644
index 0000000..730abf0
--- /dev/null
+++ b/linux/lib/setsid.c
@@ -0,0 +1,4 @@
+#define __LIBRARY__
+#include <unistd.h>
+
+_syscall0(pid_t,setsid)
diff --git a/linux/lib/string.c b/linux/lib/string.c
new file mode 100644
index 0000000..f6befd9
--- /dev/null
+++ b/linux/lib/string.c
@@ -0,0 +1,8 @@
+#ifndef __GNUC__
+#error I want gcc!
+#endif
+
+#define extern
+#define inline
+#define __LIBRARY__
+#include <string.h>
diff --git a/linux/lib/wait.c b/linux/lib/wait.c
new file mode 100644
index 0000000..a14555c
--- /dev/null
+++ b/linux/lib/wait.c
@@ -0,0 +1,10 @@
+#define __LIBRARY__
+#include <unistd.h>
+#include <sys/wait.h>
+
+_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+
+pid_t wait(int * wait_stat)
+{
+ return waitpid(-1,wait_stat,0);
+}
diff --git a/linux/lib/write.c b/linux/lib/write.c
new file mode 100644
index 0000000..2613f17
--- /dev/null
+++ b/linux/lib/write.c
@@ -0,0 +1,4 @@
+#define __LIBRARY__
+#include <unistd.h>
+
+_syscall3(int,write,int,fd,const char *,buf,off_t,count)
diff --git a/linux/mm/Makefile b/linux/mm/Makefile
new file mode 100644
index 0000000..cee1f09
--- /dev/null
+++ b/linux/mm/Makefile
@@ -0,0 +1,37 @@
+CC =gcc
+CFLAGS =-O -Wall -fstrength-reduce -fcombine-regs -fomit-frame-pointer \
+ -finline-functions -nostdinc -I../include
+AS =gas
+AR =gar
+LD =gld
+CPP =gcc -E -nostdinc -I../include
+
+.c.o:
+ $(CC) $(CFLAGS) \
+ -c -o $*.o $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+
+OBJS = memory.o page.o
+
+all: mm.o
+
+mm.o: $(OBJS)
+ $(LD) -r -o mm.o $(OBJS)
+
+clean:
+ rm -f core *.o *.a tmp_make
+ for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
+memory.o : memory.c ../include/signal.h ../include/sys/types.h \
+ ../include/linux/config.h ../include/linux/head.h ../include/linux/kernel.h \
+ ../include/asm/system.h
diff --git a/linux/mm/memory.c b/linux/mm/memory.c
new file mode 100644
index 0000000..7cdcfb6
--- /dev/null
+++ b/linux/mm/memory.c
@@ -0,0 +1,264 @@
+#include <signal.h>
+
+#include <linux/config.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+int do_exit(long code);
+
+#define invalidate() \
+__asm__("movl %%eax,%%cr3"::"a" (0))
+
+#if (BUFFER_END < 0x100000)
+#define LOW_MEM 0x100000
+#else
+#define LOW_MEM BUFFER_END
+#endif
+
+/* these are not to be changed - thay are calculated from the above */
+#define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM)
+#define PAGING_PAGES (PAGING_MEMORY/4096)
+#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
+
+#if (PAGING_PAGES < 10)
+#error "Won't work"
+#endif
+
+#define copy_page(from,to) \
+__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
+
+static unsigned short mem_map [ PAGING_PAGES ] = {0,};
+
+/*
+ * Get physical address of first (actually last :-) free page, and mark it
+ * used. If no free pages left, return 0.
+ */
+unsigned long get_free_page(void)
+{
+register unsigned long __res asm("ax");
+
+__asm__("std ; repne ; scasw\n\t"
+ "jne 1f\n\t"
+ "movw $1,2(%%edi)\n\t"
+ "sall $12,%%ecx\n\t"
+ "movl %%ecx,%%edx\n\t"
+ "addl %2,%%edx\n\t"
+ "movl $1024,%%ecx\n\t"
+ "leal 4092(%%edx),%%edi\n\t"
+ "rep ; stosl\n\t"
+ "movl %%edx,%%eax\n"
+ "1:"
+ :"=a" (__res)
+ :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
+ "D" (mem_map+PAGING_PAGES-1)
+ :"di","cx","dx");
+return __res;
+}
+
+/*
+ * Free a page of memory at physical address 'addr'. Used by
+ * 'free_page_tables()'
+ */
+void free_page(unsigned long addr)
+{
+ if (addr<LOW_MEM) return;
+ if (addr>HIGH_MEMORY)
+ panic("trying to free nonexistent page");
+ addr -= LOW_MEM;
+ addr >>= 12;
+ if (mem_map[addr]--) return;
+ mem_map[addr]=0;
+ panic("trying to free free page");
+}
+
+/*
+ * This function frees a continuos block of page tables, as needed
+ * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
+ */
+int free_page_tables(unsigned long from,unsigned long size)
+{
+ unsigned long *pg_table;
+ unsigned long * dir, nr;
+
+ if (from & 0x3fffff)
+ panic("free_page_tables called with wrong alignment");
+ if (!from)
+ panic("Trying to free up swapper memory space");
+ size = (size + 0x3fffff) >> 22;
+ dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
+ for ( ; size-->0 ; dir++) {
+ if (!(1 & *dir))
+ continue;
+ pg_table = (unsigned long *) (0xfffff000 & *dir);
+ for (nr=0 ; nr<1024 ; nr++) {
+ if (1 & *pg_table)
+ free_page(0xfffff000 & *pg_table);
+ *pg_table = 0;
+ pg_table++;
+ }
+ free_page(0xfffff000 & *dir);
+ *dir = 0;
+ }
+ invalidate();
+ return 0;
+}
+
+/*
+ * Well, here is one of the most complicated functions in mm. It
+ * copies a range of linerar addresses by copying only the pages.
+ * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
+ *
+ * Note! We don't copy just any chunks of memory - addresses have to
+ * be divisible by 4Mb (one page-directory entry), as this makes the
+ * function easier. It's used only by fork anyway.
+ *
+ * NOTE 2!! When from==0 we are copying kernel space for the first
+ * fork(). Then we DONT want to copy a full page-directory entry, as
+ * that would lead to some serious memory waste - we just copy the
+ * first 160 pages - 640kB. Even that is more than we need, but it
+ * doesn't take any more memory - we don't copy-on-write in the low
+ * 1 Mb-range, so the pages can be shared with the kernel. Thus the
+ * special case for nr=xxxx.
+ */
+int copy_page_tables(unsigned long from,unsigned long to,long size)
+{
+ unsigned long * from_page_table;
+ unsigned long * to_page_table;
+ unsigned long this_page;
+ unsigned long * from_dir, * to_dir;
+ unsigned long nr;
+
+ if ((from&0x3fffff) || (to&0x3fffff))
+ panic("copy_page_tables called with wrong alignment");
+ from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
+ to_dir = (unsigned long *) ((to>>20) & 0xffc);
+ size = ((unsigned) (size+0x3fffff)) >> 22;
+ for( ; size-->0 ; from_dir++,to_dir++) {
+ if (1 & *to_dir)
+ panic("copy_page_tables: already exist");
+ if (!(1 & *from_dir))
+ continue;
+ from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
+ if (!(to_page_table = (unsigned long *) get_free_page()))
+ return -1; /* Out of memory, see freeing */
+ *to_dir = ((unsigned long) to_page_table) | 7;
+ nr = (from==0)?0xA0:1024;
+ for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
+ this_page = *from_page_table;
+ if (!(1 & this_page))
+ continue;
+ this_page &= ~2;
+ *to_page_table = this_page;
+ if (this_page > LOW_MEM) {
+ *from_page_table = this_page;
+ this_page -= LOW_MEM;
+ this_page >>= 12;
+ mem_map[this_page]++;
+ }
+ }
+ }
+ invalidate();
+ return 0;
+}
+
+/*
+ * This function puts a page in memory at the wanted address.
+ * It returns the physical address of the page gotten, 0 if
+ * out of memory (either when trying to access page-table or
+ * page.)
+ */
+unsigned long put_page(unsigned long page,unsigned long address)
+{
+ unsigned long tmp, *page_table;
+
+/* NOTE !!! This uses the fact that _pg_dir=0 */
+
+ if (page < LOW_MEM || page > HIGH_MEMORY)
+ printk("Trying to put page %p at %p\n",page,address);
+ if (mem_map[(page-LOW_MEM)>>12] != 1)
+ printk("mem_map disagrees with %p at %p\n",page,address);
+ page_table = (unsigned long *) ((address>>20) & 0xffc);
+ if ((*page_table)&1)
+ page_table = (unsigned long *) (0xfffff000 & *page_table);
+ else {
+ if (!(tmp=get_free_page()))
+ return 0;
+ *page_table = tmp|7;
+ page_table = (unsigned long *) tmp;
+ }
+ page_table[(address>>12) & 0x3ff] = page | 7;
+ return page;
+}
+
+void un_wp_page(unsigned long * table_entry)
+{
+ unsigned long old_page,new_page;
+
+ old_page = 0xfffff000 & *table_entry;
+ if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
+ *table_entry |= 2;
+ return;
+ }
+ if (!(new_page=get_free_page()))
+ do_exit(SIGSEGV);
+ if (old_page >= LOW_MEM)
+ mem_map[MAP_NR(old_page)]--;
+ *table_entry = new_page | 7;
+ copy_page(old_page,new_page);
+}
+
+/*
+ * This routine handles present pages, when users try to write
+ * to a shared page. It is done by copying the page to a new address
+ * and decrementing the shared-page counter for the old page.
+ */
+void do_wp_page(unsigned long error_code,unsigned long address)
+{
+ un_wp_page((unsigned long *)
+ (((address>>10) & 0xffc) + (0xfffff000 &
+ *((unsigned long *) ((address>>20) &0xffc)))));
+
+}
+
+void write_verify(unsigned long address)
+{
+ unsigned long page;
+
+ if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
+ return;
+ page &= 0xfffff000;
+ page += ((address>>10) & 0xffc);
+ if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */
+ un_wp_page((unsigned long *) page);
+ return;
+}
+
+void do_no_page(unsigned long error_code,unsigned long address)
+{
+ unsigned long tmp;
+
+ if (tmp=get_free_page())
+ if (put_page(tmp,address))
+ return;
+ do_exit(SIGSEGV);
+}
+
+void calc_mem(void)
+{
+ int i,j,k,free=0;
+ long * pg_tbl;
+
+ for(i=0 ; i<PAGING_PAGES ; i++)
+ if (!mem_map[i]) free++;
+ printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);
+ for(i=2 ; i<1024 ; i++) {
+ if (1&pg_dir[i]) {
+ pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
+ for(j=k=0 ; j<1024 ; j++)
+ if (pg_tbl[j]&1)
+ k++;
+ printk("Pg-dir[%d] uses %d pages\n",i,k);
+ }
+ }
+}
diff --git a/linux/mm/page.s b/linux/mm/page.s
new file mode 100644
index 0000000..27488c2
--- /dev/null
+++ b/linux/mm/page.s
@@ -0,0 +1,34 @@
+/*
+ * page.s contains the low-level page-exception code.
+ * the real work is done in mm.c
+ */
+
+.globl _page_fault
+
+_page_fault:
+ xchgl %eax,(%esp)
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%edx
+ mov %dx,%ds
+ mov %dx,%es
+ mov %dx,%fs
+ movl %cr2,%edx
+ pushl %edx
+ pushl %eax
+ testl $1,%eax
+ jne 1f
+ call _do_no_page
+ jmp 2f
+1: call _do_wp_page
+2: addl $8,%esp
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
diff --git a/linux/tools/build.c b/linux/tools/build.c
new file mode 100644
index 0000000..6afe58c
--- /dev/null
+++ b/linux/tools/build.c
@@ -0,0 +1,68 @@
+#include <stdio.h> /* fprintf */
+#include <stdlib.h> /* contains exit */
+#include <sys/types.h> /* unistd.h needs this */
+#include <unistd.h> /* contains read/write */
+#include <fcntl.h>
+
+#define MINIX_HEADER 32
+#define GCC_HEADER 1024
+
+void die(char * str)
+{
+ fprintf(stderr,"%s\n",str);
+ exit(1);
+}
+
+void usage(void)
+{
+ die("Usage: build boot system [> image]");
+}
+
+int main(int argc, char ** argv)
+{
+ int i,c,id;
+ char buf[1024];
+
+ if (argc != 3)
+ usage();
+ for (i=0;i<sizeof buf; i++) buf[i]=0;
+ if ((id=open(argv[1],O_RDONLY,0))<0)
+ die("Unable to open 'boot'");
+ if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+ die("Unable to read header of 'boot'");
+ if (((long *) buf)[0]!=0x04100301)
+ die("Non-Minix header of 'boot'");
+ if (((long *) buf)[1]!=MINIX_HEADER)
+ die("Non-Minix header of 'boot'");
+ if (((long *) buf)[3]!=0)
+ die("Illegal data segment in 'boot'");
+ if (((long *) buf)[4]!=0)
+ die("Illegal bss in 'boot'");
+ if (((long *) buf)[5] != 0)
+ die("Non-Minix header of 'boot'");
+ if (((long *) buf)[7] != 0)
+ die("Illegal symbol table in 'boot'");
+ i=read(id,buf,sizeof buf);
+ fprintf(stderr,"Boot sector %d bytes.\n",i);
+ if (i>510)
+ die("Boot block may not exceed 510 bytes");
+ buf[510]=0x55;
+ buf[511]=0xAA;
+ i=write(1,buf,512);
+ if (i!=512)
+ die("Write call failed");
+ close (id);
+
+ if ((id=open(argv[2],O_RDONLY,0))<0)
+ die("Unable to open 'system'");
+ if (read(id,buf,GCC_HEADER) != GCC_HEADER)
+ die("Unable to read header of 'system'");
+ if (((long *) buf)[5] != 0)
+ die("Non-GCC header of 'system'");
+ for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
+ if (write(1,buf,c)!=c)
+ die("Write call failed");
+ close(id);
+ fprintf(stderr,"System %d bytes.\n",i);
+ return(0);
+}