Full switch to clang/ELF. Drop ack. Simplify.
There is important information about booting non-ack images in docs/UPDATING. ack/aout-format images can't be built any more, and booting clang/ELF-format ones is a little different. Updating to the new boot monitor is recommended. Changes in this commit: . drop boot monitor -> allowing dropping ack support . facility to copy ELF boot files to /boot so that old boot monitor can still boot fairly easily, see UPDATING . no more ack-format libraries -> single-case libraries . some cleanup of OBJECT_FMT, COMPILER_TYPE, etc cases . drop several ack toolchain commands, but not all support commands (e.g. aal is gone but acksize is not yet). . a few libc files moved to netbsd libc dir . new /bin/date as minix date used code in libc/ . test compile fix . harmonize includes . /usr/lib is no longer special: without ack, /usr/lib plays no kind of special bootstrapping role any more and bootstrapping is done exclusively through packages, so releases depend even less on the state of the machine making them now. . rename nbsd_lib* to lib* . reduce mtree
This commit is contained in:
parent
2487445f5f
commit
2fe8fb192f
5056 changed files with 16216 additions and 133169 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -14,11 +14,6 @@ cscope.*
|
|||
*.d
|
||||
.depend
|
||||
nbsdsrc/*
|
||||
obj-ack
|
||||
obj-gnu
|
||||
obj-elf-base
|
||||
obj-elfbase-nbsd
|
||||
obj-gnu-nbsd
|
||||
tools/revision
|
||||
TAGS
|
||||
tags
|
||||
|
@ -41,3 +36,4 @@ etc/spwd.db
|
|||
tools/image
|
||||
tools/kernel
|
||||
share/zoneinfo/builddir
|
||||
lib/libc/compat__*
|
||||
|
|
40
Makefile
40
Makefile
|
@ -12,8 +12,7 @@ usage:
|
|||
@echo "Usage:"
|
||||
@echo " make world # Compile everything (libraries & commands)"
|
||||
@echo " make includes # Install include files from src/"
|
||||
@echo " make libraries # Compile and install libraries (ack)"
|
||||
@echo " make elf-libraries # Compile and install gcc/clang elf libs"
|
||||
@echo " make libraries # Compile and install libraries"
|
||||
@echo " make commands # Compile all, commands, but don't install"
|
||||
@echo " make install # Compile and install commands"
|
||||
@echo " make gnu-includes # Install include files for GCC"
|
||||
|
@ -30,32 +29,21 @@ usage:
|
|||
# 'make install' target.
|
||||
#
|
||||
# etcfiles has to be done first.
|
||||
.if ${COMPILER_TYPE} == "ack"
|
||||
world: mkfiles etcfiles includes libraries elf-libraries dep-all install etcforce
|
||||
.else
|
||||
world: mkfiles etcfiles includes elf-libraries dep-all install etcforce
|
||||
.endif
|
||||
world: mkfiles etcfiles includes libraries dep-all install etcforce
|
||||
|
||||
mkfiles:
|
||||
make -C share/mk install
|
||||
|
||||
includes:
|
||||
$(MAKE) -C nbsd_include includes
|
||||
$(MAKE) -C include includes
|
||||
$(MAKE) -C lib includes NBSD_LIBC=yes
|
||||
.if ${COMPILER_TYPE} == "ack"
|
||||
$(MAKE) -C lib includes NBSD_LIBC=no
|
||||
.endif
|
||||
|
||||
libraries: includes
|
||||
$(MAKE) -C lib build_ack
|
||||
|
||||
MKHEADERSS=/usr/pkg/gcc*/libexec/gcc/*/*/install-tools/mkheaders
|
||||
gnu-includes: includes
|
||||
SHELL=/bin/sh; for d in $(MKHEADERSS); do if [ -f $$d ] ; then sh -e $$d ; fi; done
|
||||
|
||||
elf-libraries: includes
|
||||
$(MAKE) -C lib build_elf
|
||||
libraries: includes
|
||||
$(MAKE) -C lib dependall install
|
||||
|
||||
commands: includes libraries
|
||||
$(MAKE) -C commands all
|
||||
|
@ -66,8 +54,7 @@ commands: includes libraries
|
|||
$(MAKE) -C usr.sbin all
|
||||
|
||||
dep-all:
|
||||
$(MAKE) CC=cc -C boot dependall
|
||||
$(MAKE) CC=clang -C sys dependall
|
||||
$(MAKE) -C sys dependall
|
||||
$(MAKE) -C commands dependall
|
||||
$(MAKE) -C bin dependall
|
||||
$(MAKE) -C sbin dependall
|
||||
|
@ -85,8 +72,7 @@ etcforce:
|
|||
$(MAKE) -C etc installforce
|
||||
|
||||
all:
|
||||
$(MAKE) CC=cc -C boot all
|
||||
$(MAKE) CC=clang -C sys all
|
||||
$(MAKE) -C sys all
|
||||
$(MAKE) -C commands all
|
||||
$(MAKE) -C bin all
|
||||
$(MAKE) -C sbin all
|
||||
|
@ -96,8 +82,7 @@ all:
|
|||
$(MAKE) -C tools all
|
||||
|
||||
install:
|
||||
$(MAKE) CC=cc -C boot install
|
||||
$(MAKE) CC=clang -C sys install
|
||||
$(MAKE) -C sys install
|
||||
$(MAKE) -C libexec install
|
||||
$(MAKE) -C man install makedb
|
||||
$(MAKE) -C commands install
|
||||
|
@ -110,7 +95,6 @@ install:
|
|||
$(MAKE) -C tools install
|
||||
|
||||
clean: mkfiles
|
||||
$(MAKE) -C boot clean
|
||||
$(MAKE) -C sys clean
|
||||
$(MAKE) -C commands clean
|
||||
$(MAKE) -C bin clean
|
||||
|
@ -120,12 +104,11 @@ clean: mkfiles
|
|||
$(MAKE) -C usr.sbin clean
|
||||
$(MAKE) -C share clean
|
||||
$(MAKE) -C tools clean
|
||||
$(MAKE) -C lib clean_all
|
||||
$(MAKE) -C lib clean
|
||||
$(MAKE) -C test clean
|
||||
|
||||
cleandepend: mkfiles
|
||||
$(MAKE) -C lib cleandepend_all
|
||||
$(MAKE) -C boot cleandepend
|
||||
$(MAKE) -C lib cleandepend
|
||||
$(MAKE) -C sys cleandepend
|
||||
$(MAKE) -C commands cleandepend
|
||||
$(MAKE) -C bin cleandepend
|
||||
|
@ -134,3 +117,8 @@ cleandepend: mkfiles
|
|||
$(MAKE) -C libexec cleandepend
|
||||
$(MAKE) -C usr.sbin cleandepend
|
||||
$(MAKE) -C tools cleandepend
|
||||
|
||||
# Warn usage change
|
||||
elf-libraries:
|
||||
echo "That target is just libraries now."
|
||||
false
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= mkdir rm rmdir
|
||||
SUBDIR= mkdir rm rmdir date
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
.include <minix.newlibc.mk>
|
||||
|
||||
CPPFLAGS+= -D_NETBSD_SOURCE
|
||||
|
||||
BINDIR?=/bin
|
||||
|
|
15
bin/date/Makefile
Normal file
15
bin/date/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# $NetBSD: Makefile,v 1.15 2011/08/14 10:53:16 christos Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
PROG= date
|
||||
SRCS= date.c netdate.c
|
||||
DPADD+= ${LIBUTIL}
|
||||
LDADD+= -lutil
|
||||
CPPFLAGS+=-I${.CURDIR}
|
||||
|
||||
TZDIR= /usr/share/zoneinfo
|
||||
CPPFLAGS+= -DHAVE_ADJTIME=0 -DTZDIR=\"$(TZDIR)\"
|
||||
|
||||
COPTS.date.c = -Wno-format-nonliteral
|
||||
|
||||
.include <bsd.prog.mk>
|
244
bin/date/date.1
Normal file
244
bin/date/date.1
Normal file
|
@ -0,0 +1,244 @@
|
|||
.\" $NetBSD: date.1,v 1.41 2010/02/04 22:56:11 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" the Institute of Electrical and Electronics Engineers, Inc.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
|
||||
.\"
|
||||
.Dd November 15, 2006
|
||||
.Dt DATE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm date
|
||||
.Nd display or set date and time
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl ajnu
|
||||
.Op Fl d Ar date
|
||||
.Op Fl r Ar seconds
|
||||
.Op Cm + Ns Ar format
|
||||
.Sm off
|
||||
.Oo Oo Oo Oo Oo Oo
|
||||
.Ar CC Oc
|
||||
.Ar yy Oc
|
||||
.Ar mm Oc
|
||||
.Ar dd Oc
|
||||
.Ar HH Oc Ar MM Oo
|
||||
.Li \&. Ar SS Oc Oc
|
||||
.Sm on
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
displays the current date and time when invoked without arguments.
|
||||
Providing arguments will format the date and time in a user-defined
|
||||
way or set the date.
|
||||
Only the superuser may set the date.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl a
|
||||
Use
|
||||
.Xr adjtime 2
|
||||
to change the local system time slowly,
|
||||
maintaining it as a monotonically increasing function.
|
||||
.Fl a
|
||||
implies
|
||||
.Fl n .
|
||||
.It Fl d Ar date
|
||||
Parse the provided human-described date and time and display the result without
|
||||
actually changing the system clock.
|
||||
(See
|
||||
.Xr parsedate 3
|
||||
for examples.)
|
||||
.It Fl j
|
||||
Parse the provided canonical representation of date and time (described below)
|
||||
and display the result without actually changing the system clock.
|
||||
.It Fl n
|
||||
The utility
|
||||
.Xr timed 8
|
||||
is used to synchronize the clocks on groups of machines.
|
||||
By default, if
|
||||
timed
|
||||
is running,
|
||||
.Nm
|
||||
will set the time on all of the machines in the local group.
|
||||
The
|
||||
.Fl n
|
||||
option stops
|
||||
.Nm
|
||||
from setting the time for other than the current machine.
|
||||
.It Fl r Ar seconds
|
||||
Print out the date and time that is
|
||||
.Ar seconds
|
||||
from the Epoch.
|
||||
.It Fl u
|
||||
Display or set the date in
|
||||
.Tn UTC
|
||||
(universal) time.
|
||||
.El
|
||||
.Pp
|
||||
An operand with a leading plus
|
||||
.Pq Cm +
|
||||
sign signals a user-defined format
|
||||
string which specifies the format in which to display the date and time.
|
||||
The format string may contain any of the conversion specifications described
|
||||
in the
|
||||
.Xr strftime 3
|
||||
manual page, as well as any arbitrary text.
|
||||
A \*[Lt]newline\*[Gt] character is always output after the characters
|
||||
specified by the format string.
|
||||
The format string for the default display is:
|
||||
.Bd -literal -offset indent
|
||||
%a %b %e %H:%M:%S %Z %Y
|
||||
.Ed
|
||||
.Pp
|
||||
If an operand does not have a leading plus sign, it is interpreted as
|
||||
a value for setting the system's notion of the current date and time.
|
||||
The canonical representation for setting the date and time is:
|
||||
.Pp
|
||||
.Bl -tag -width Ds -compact -offset indent
|
||||
.It Ar CC
|
||||
The first two digits of the year (the century).
|
||||
.It Ar yy
|
||||
The second two digits of the year.
|
||||
If
|
||||
.Ar yy
|
||||
is specified, but
|
||||
.Ar CC
|
||||
is not, a value for
|
||||
.Ar yy
|
||||
between 69 and 99 results in a
|
||||
.Ar CC
|
||||
value of 19.
|
||||
Otherwise, a
|
||||
.Ar CC
|
||||
value of 20 is used.
|
||||
.It Ar mm
|
||||
The month of the year, from 01 to 12.
|
||||
.It Ar dd
|
||||
The day of the month, from 01 to 31.
|
||||
.It Ar HH
|
||||
The hour of the day, from 00 to 23.
|
||||
.It Ar MM
|
||||
The minute of the hour, from 00 to 59.
|
||||
.It Ar SS
|
||||
The second of the minute, from 00 to 61.
|
||||
.El
|
||||
.Pp
|
||||
Everything but the minutes is optional.
|
||||
.Pp
|
||||
Time changes for Daylight Saving and Standard time and leap seconds
|
||||
and years are handled automatically.
|
||||
.Sh ENVIRONMENT
|
||||
The following environment variables affect the execution of
|
||||
.Nm :
|
||||
.Bl -tag -width iTZ
|
||||
.It Ev TZ
|
||||
The timezone to use when displaying dates.
|
||||
See
|
||||
.Xr environ 7
|
||||
for more information.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /var/log/messages -compact
|
||||
.It Pa /etc/localtime
|
||||
Symlink pointing to system's default timezone information file in
|
||||
.Pa /usr/share/zoneinfo
|
||||
directory.
|
||||
.It Pa /var/log/wtmp
|
||||
A record of date resets and time changes.
|
||||
.It Pa /var/log/messages
|
||||
A record of the user setting the time.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date '+DATE: %m/%d/%y%nTIME: %H:%M:%S'
|
||||
.Ed
|
||||
.Pp
|
||||
will display:
|
||||
.Bd -literal -offset indent
|
||||
DATE: 11/21/87
|
||||
TIME: 13:36:16
|
||||
.Ed
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date 8506131627
|
||||
.Ed
|
||||
.Pp
|
||||
sets the date to
|
||||
.Dq Li "June 13, 1985, 4:27 PM" .
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date 1432
|
||||
.Ed
|
||||
.Pp
|
||||
sets the time to
|
||||
.Li "2:32 PM" ,
|
||||
without modifying the date.
|
||||
.Sh DIAGNOSTICS
|
||||
Exit status is 0 on success, 1 if unable to set the date, and 2
|
||||
if able to set the local date, but unable to set it globally.
|
||||
.Pp
|
||||
Occasionally, when
|
||||
.Xr timed 8
|
||||
synchronizes the time on many hosts, the setting of a new time value may
|
||||
require more than a few seconds.
|
||||
On these occasions,
|
||||
.Nm
|
||||
prints:
|
||||
.Ql Network time being set .
|
||||
The message
|
||||
.Ql Communication error with timed
|
||||
occurs when the communication
|
||||
between
|
||||
.Nm
|
||||
and
|
||||
timed
|
||||
fails.
|
||||
.Sh SEE ALSO
|
||||
.Xr adjtime 2 ,
|
||||
.Xr gettimeofday 2 ,
|
||||
.Xr settimeofday 2 ,
|
||||
.Xr parsedate 3 ,
|
||||
.Xr strftime 3 ,
|
||||
.Xr utmp 5 ,
|
||||
.Xr timed 8
|
||||
.Rs
|
||||
.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
|
||||
.%A R. Gusella
|
||||
.%A S. Zatti
|
||||
.Re
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is expected to be compatible with
|
||||
.St -p1003.2 .
|
350
bin/date/date.c
Normal file
350
bin/date/date.c
Normal file
|
@ -0,0 +1,350 @@
|
|||
/* $NetBSD: date.c,v 1.60 2011/08/27 12:55:09 joerg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985, 1987, 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT(
|
||||
"@(#) Copyright (c) 1985, 1987, 1988, 1993\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: date.c,v 1.60 2011/08/27 12:55:09 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <tzfile.h>
|
||||
#include <unistd.h>
|
||||
#include <util.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
static time_t tval;
|
||||
static int aflag, jflag, rflag, nflag;
|
||||
|
||||
__dead static void badformat(void);
|
||||
__dead static void badtime(void);
|
||||
__dead static void badvalue(const char *);
|
||||
static void setthetime(const char *);
|
||||
__dead static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *buf;
|
||||
size_t bufsiz;
|
||||
const char *format;
|
||||
int ch;
|
||||
long long val;
|
||||
struct tm *tm;
|
||||
|
||||
setprogname(argv[0]);
|
||||
(void)setlocale(LC_ALL, "");
|
||||
|
||||
while ((ch = getopt(argc, argv, "ad:jnr:u")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a': /* adjust time slowly */
|
||||
aflag = 1;
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'd':
|
||||
#ifndef __minix
|
||||
rflag = 1;
|
||||
tval = parsedate(optarg, NULL, NULL);
|
||||
if (tval == -1)
|
||||
#endif
|
||||
badarg: errx(EXIT_FAILURE,
|
||||
"Cannot parse `%s'", optarg);
|
||||
break;
|
||||
case 'j': /* don't set time */
|
||||
jflag = 1;
|
||||
break;
|
||||
case 'n': /* don't set network */
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'r': /* user specified seconds */
|
||||
errno = 0;
|
||||
val = strtoll(optarg, &buf, 0);
|
||||
if (optarg[0] == '\0' || *buf != '\0')
|
||||
goto badarg;
|
||||
if (errno == ERANGE && (val == LLONG_MAX ||
|
||||
val == LLONG_MIN))
|
||||
err(EXIT_FAILURE, "Bad number `%s'", optarg);
|
||||
rflag = 1;
|
||||
tval = (time_t)val;
|
||||
break;
|
||||
case 'u': /* do everything in UTC */
|
||||
(void)setenv("TZ", "UTC0", 1);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!rflag && time(&tval) == -1)
|
||||
err(EXIT_FAILURE, "time");
|
||||
|
||||
|
||||
/* allow the operands in any order */
|
||||
if (*argv && **argv == '+') {
|
||||
format = *argv;
|
||||
++argv;
|
||||
} else
|
||||
format = "+%a %b %e %H:%M:%S %Z %Y";
|
||||
|
||||
if (*argv) {
|
||||
setthetime(*argv);
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (*argv && **argv == '+')
|
||||
format = *argv;
|
||||
|
||||
if ((buf = malloc(bufsiz = 1024)) == NULL)
|
||||
goto bad;
|
||||
|
||||
if ((tm = localtime(&tval)) == NULL)
|
||||
err(EXIT_FAILURE, "localtime %lld failed", (long long)tval);
|
||||
|
||||
while (strftime(buf, bufsiz, format, tm) == 0)
|
||||
if ((buf = realloc(buf, bufsiz <<= 1)) == NULL)
|
||||
goto bad;
|
||||
|
||||
(void)printf("%s\n", buf + 1);
|
||||
free(buf);
|
||||
return 0;
|
||||
bad:
|
||||
err(EXIT_FAILURE, "Cannot allocate format buffer");
|
||||
}
|
||||
|
||||
static void
|
||||
badformat(void)
|
||||
{
|
||||
warnx("illegal time format");
|
||||
usage();
|
||||
}
|
||||
|
||||
static void
|
||||
badtime(void)
|
||||
{
|
||||
errx(EXIT_FAILURE, "illegal time");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
badvalue(const char *param)
|
||||
{
|
||||
warnx("invalid %s supplied", param);
|
||||
usage();
|
||||
}
|
||||
|
||||
#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
|
||||
|
||||
static void
|
||||
setthetime(const char *p)
|
||||
{
|
||||
struct timeval tv;
|
||||
time_t new_time;
|
||||
struct tm *lt;
|
||||
const char *dot, *t;
|
||||
size_t len;
|
||||
int yearset;
|
||||
|
||||
for (t = p, dot = NULL; *t; ++t) {
|
||||
if (isdigit((unsigned char)*t))
|
||||
continue;
|
||||
if (*t == '.' && dot == NULL) {
|
||||
dot = t;
|
||||
continue;
|
||||
}
|
||||
badformat();
|
||||
}
|
||||
|
||||
if ((lt = localtime(&tval)) == NULL)
|
||||
err(EXIT_FAILURE, "localtime %lld failed", (long long)tval);
|
||||
|
||||
lt->tm_isdst = -1; /* Divine correct DST */
|
||||
|
||||
if (dot != NULL) { /* .ss */
|
||||
len = strlen(dot);
|
||||
if (len != 3)
|
||||
badformat();
|
||||
++dot;
|
||||
lt->tm_sec = ATOI2(dot);
|
||||
if (lt->tm_sec > 61)
|
||||
badvalue("seconds");
|
||||
} else {
|
||||
len = 0;
|
||||
lt->tm_sec = 0;
|
||||
}
|
||||
|
||||
yearset = 0;
|
||||
switch (strlen(p) - len) {
|
||||
case 12: /* cc */
|
||||
lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;
|
||||
if (lt->tm_year < 0)
|
||||
badtime();
|
||||
yearset = 1;
|
||||
/* FALLTHROUGH */
|
||||
case 10: /* yy */
|
||||
if (yearset) {
|
||||
lt->tm_year += ATOI2(p);
|
||||
} else {
|
||||
yearset = ATOI2(p);
|
||||
if (yearset < 69)
|
||||
lt->tm_year = yearset + 2000 - TM_YEAR_BASE;
|
||||
else
|
||||
lt->tm_year = yearset + 1900 - TM_YEAR_BASE;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 8: /* mm */
|
||||
lt->tm_mon = ATOI2(p);
|
||||
if (lt->tm_mon > 12 || lt->tm_mon == 0)
|
||||
badvalue("month");
|
||||
--lt->tm_mon; /* time struct is 0 - 11 */
|
||||
/* FALLTHROUGH */
|
||||
case 6: /* dd */
|
||||
lt->tm_mday = ATOI2(p);
|
||||
switch (lt->tm_mon) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 9:
|
||||
case 11:
|
||||
if (lt->tm_mday > 31 || lt->tm_mday == 0)
|
||||
badvalue("day of month");
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
case 8:
|
||||
case 10:
|
||||
if (lt->tm_mday > 30 || lt->tm_mday == 0)
|
||||
badvalue("day of month");
|
||||
break;
|
||||
case 1:
|
||||
if (lt->tm_mday > 29 || lt->tm_mday == 0 ||
|
||||
(lt->tm_mday == 29 &&
|
||||
!isleap(lt->tm_year + TM_YEAR_BASE)))
|
||||
badvalue("day of month");
|
||||
break;
|
||||
default:
|
||||
badvalue("month");
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 4: /* hh */
|
||||
lt->tm_hour = ATOI2(p);
|
||||
if (lt->tm_hour > 23)
|
||||
badvalue("hour");
|
||||
/* FALLTHROUGH */
|
||||
case 2: /* mm */
|
||||
lt->tm_min = ATOI2(p);
|
||||
if (lt->tm_min > 59)
|
||||
badvalue("minute");
|
||||
break;
|
||||
case 0: /* was just .sss */
|
||||
if (len != 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
badformat();
|
||||
}
|
||||
|
||||
/* convert broken-down time to UTC clock time */
|
||||
if ((new_time = mktime(lt)) == -1)
|
||||
badtime();
|
||||
|
||||
/* if jflag is set, don't actually change the time, just return */
|
||||
if (jflag) {
|
||||
tval = new_time;
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the time */
|
||||
if (nflag || netsettime(new_time)) {
|
||||
logwtmp("|", "date", "");
|
||||
#if HAVE_ADJTIME
|
||||
if (aflag) {
|
||||
tv.tv_sec = new_time - tval;
|
||||
tv.tv_usec = 0;
|
||||
if (adjtime(&tv, NULL))
|
||||
err(EXIT_FAILURE, "adjtime");
|
||||
}
|
||||
#else
|
||||
if (aflag) {
|
||||
err(EXIT_FAILURE, "no adjtime");
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
tval = new_time;
|
||||
tv.tv_sec = tval;
|
||||
tv.tv_usec = 0;
|
||||
if (settimeofday(&tv, NULL))
|
||||
err(EXIT_FAILURE, "settimeofday");
|
||||
}
|
||||
logwtmp("{", "date", "");
|
||||
}
|
||||
|
||||
if ((p = getlogin()) == NULL)
|
||||
p = "???";
|
||||
syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s [-ajnu] [-d date] [-r seconds] [+format]",
|
||||
getprogname());
|
||||
(void)fprintf(stderr, " [[[[[[CC]yy]mm]dd]HH]MM[.SS]]\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* NOTREACHED */
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: memory.h,v 1.5 2003/08/07 09:44:10 agc Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.8 2006/11/17 22:11:28 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1993
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -28,7 +28,12 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)memory.h 8.1 (Berkeley) 6/2/93
|
||||
* @(#)extern.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#ifndef _EXTERN_H_
|
||||
#define _EXTERN_H_
|
||||
|
||||
int netsettime(time_t);
|
||||
|
||||
#endif /* !_EXTERN_H_ */
|
200
bin/date/netdate.c
Normal file
200
bin/date/netdate.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
/* $NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)netdate.c 8.2 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define TSPTYPES
|
||||
#include <protocols/timed.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
#define WAITACK 2000 /* milliseconds */
|
||||
#define WAITDATEACK 5000 /* milliseconds */
|
||||
|
||||
static const char *
|
||||
tsp_type_to_string(const struct tsp *msg)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
i = msg->tsp_type;
|
||||
return i < TSPTYPENUMBER ? tsptype[i] : "unknown";
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the date in the machines controlled by timedaemons by communicating the
|
||||
* new date to the local timedaemon. If the timedaemon is in the master state,
|
||||
* it performs the correction on all slaves. If it is in the slave state, it
|
||||
* notifies the master that a correction is needed.
|
||||
* Returns 0 on success. Returns > 0 on failure.
|
||||
*/
|
||||
int
|
||||
netsettime(time_t tval)
|
||||
{
|
||||
struct sockaddr_in dest;
|
||||
struct tsp msg;
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
struct servent *sp;
|
||||
struct pollfd ready;
|
||||
int found, s, timed_ack, waittime;
|
||||
|
||||
if ((sp = getservbyname("timed", "udp")) == NULL) {
|
||||
warnx("udp/timed: unknown service");
|
||||
return 2;
|
||||
}
|
||||
|
||||
(void)memset(&dest, 0, sizeof(dest));
|
||||
#ifdef BSD4_4
|
||||
dest.sin_len = sizeof(dest);
|
||||
#endif
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = sp->s_port;
|
||||
dest.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s == -1) {
|
||||
if (errno != EAFNOSUPPORT)
|
||||
warn("timed");
|
||||
return 2;
|
||||
}
|
||||
|
||||
#ifdef IP_PORTRANGE
|
||||
{
|
||||
static const int on = IP_PORTRANGE_LOW;
|
||||
|
||||
if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &on,
|
||||
sizeof(on)) == -1) {
|
||||
warn("setsockopt");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
msg.tsp_type = TSP_SETDATE;
|
||||
msg.tsp_vers = TSPVERSION;
|
||||
if (gethostname(hostname, sizeof(hostname)) == -1) {
|
||||
warn("gethostname");
|
||||
goto bad;
|
||||
}
|
||||
(void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
|
||||
msg.tsp_seq = htons((in_port_t)0);
|
||||
msg.tsp_time.tv_sec = htonl((in_addr_t)tval); /* XXX: y2038 */
|
||||
msg.tsp_time.tv_usec = htonl((in_addr_t)0);
|
||||
if (connect(s, (const void *)&dest, sizeof(dest)) == -1) {
|
||||
warn("connect");
|
||||
goto bad;
|
||||
}
|
||||
if (send(s, &msg, sizeof(msg), 0) == -1) {
|
||||
if (errno != ECONNREFUSED)
|
||||
warn("send");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
timed_ack = -1;
|
||||
waittime = WAITACK;
|
||||
ready.fd = s;
|
||||
ready.events = POLLIN;
|
||||
loop:
|
||||
found = poll(&ready, 1, waittime);
|
||||
|
||||
{
|
||||
socklen_t len;
|
||||
int error;
|
||||
|
||||
len = sizeof(error);
|
||||
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
|
||||
warn("getsockopt");
|
||||
goto bad;
|
||||
}
|
||||
if (error) {
|
||||
if (error != ECONNREFUSED) {
|
||||
errno = error;
|
||||
warn("send (delayed error)");
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (found > 0 && ready.revents & POLLIN) {
|
||||
ssize_t ret;
|
||||
|
||||
if ((ret = recv(s, &msg, sizeof(msg), 0)) == -1) {
|
||||
if (errno != ECONNREFUSED)
|
||||
warn("recv");
|
||||
goto bad;
|
||||
} else if ((size_t)ret < sizeof(msg)) {
|
||||
warnx("recv: incomplete packet");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
msg.tsp_seq = ntohs(msg.tsp_seq);
|
||||
msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
|
||||
msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
|
||||
switch (msg.tsp_type) {
|
||||
case TSP_ACK:
|
||||
timed_ack = TSP_ACK;
|
||||
waittime = WAITDATEACK;
|
||||
goto loop;
|
||||
case TSP_DATEACK:
|
||||
(void)close(s);
|
||||
return 0;
|
||||
default:
|
||||
warnx("wrong ack received from timed: %s",
|
||||
tsp_type_to_string(&msg));
|
||||
timed_ack = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (timed_ack == -1)
|
||||
warnx("can't reach time daemon, time set locally");
|
||||
|
||||
bad:
|
||||
(void)close(s);
|
||||
return 2;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
# Makefile for the boot monitor package.
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
# 16-bit code; various boot blocks
|
||||
SUBDIR= masterboot bootblock cdbootblock
|
||||
|
||||
# Supplementary MBR code (alternate to masterboot)
|
||||
SUBDIR+= jumpboot
|
||||
|
||||
# 16-bit code; needs the i86 ACK library
|
||||
SUBDIR+= boot
|
||||
|
||||
# Userland MINIX code
|
||||
SUBDIR+= installboot edparams
|
||||
|
||||
.include <bsd.subdir.mk>
|
220
boot/boot.h
220
boot/boot.h
|
@ -1,220 +0,0 @@
|
|||
/* boot.h - Info between different parts of boot. Author: Kees J. Bot
|
||||
*/
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
|
||||
/* Constants describing the metal: */
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define SECTOR_SHIFT 9
|
||||
#define RATIO(b) ((b) / SECTOR_SIZE)
|
||||
|
||||
#define PARAMSEC 1 /* Sector containing boot parameters. */
|
||||
|
||||
#define DSKBASE 0x1E /* Floppy disk parameter vector. */
|
||||
#define DSKPARSIZE 11 /* There are this many bytes of parameters. */
|
||||
|
||||
#define ESC '\33' /* Escape key. */
|
||||
|
||||
#define HEADERPOS 0x00600L /* Place for an array of struct exec's. */
|
||||
|
||||
#define FREEPOS 0x08000L /* Memory from FREEPOS to caddr is free to
|
||||
* play with.
|
||||
*/
|
||||
#if BIOS
|
||||
#define MSEC_PER_TICK 55 /* Clock does 18.2 ticks per second. */
|
||||
#define TICKS_PER_DAY 0x1800B0L /* After 24 hours it wraps. */
|
||||
#endif
|
||||
|
||||
#if UNIX
|
||||
#define MSEC_PER_TICK 1000 /* Clock does 18.2 ticks per second. */
|
||||
#define TICKS_PER_DAY 86400L /* Doesn't wrap, but that doesn't matter. */
|
||||
#endif
|
||||
|
||||
#define BOOTPOS 0x07C00L /* Bootstraps are loaded here. */
|
||||
#define SIGNATURE 0xAA55 /* Proper bootstraps have this signature. */
|
||||
#define SIGNATOFF 510 /* Offset within bootblock. */
|
||||
|
||||
/* BIOS video modes. */
|
||||
#define MONO_MODE 0x07 /* 80x25 monochrome. */
|
||||
#define COLOR_MODE 0x03 /* 80x25 color. */
|
||||
|
||||
|
||||
/* Variables shared with boothead.s: */
|
||||
#ifndef EXTERN
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
typedef struct vector { /* 8086 vector */
|
||||
u16_t offset;
|
||||
u16_t segment;
|
||||
} vector;
|
||||
|
||||
EXTERN vector rem_part; /* Boot partition table entry. */
|
||||
|
||||
EXTERN u32_t caddr, daddr; /* Code and data address of the boot program. */
|
||||
EXTERN u32_t runsize; /* Size of this program. */
|
||||
|
||||
EXTERN u16_t device; /* Drive being booted from. */
|
||||
EXTERN u16_t cddevice; /* Drive that is CD if known. */
|
||||
|
||||
#define CDNAME "cd" /* Name of the CD device. */
|
||||
|
||||
EXTERN int mon_return; /* Monitor stays in memory? */
|
||||
EXTERN int cdbooted; /* Did we boot from CD? (Set by boothead.s.) */
|
||||
|
||||
typedef struct bios_env
|
||||
{
|
||||
u16_t ax;
|
||||
u16_t bx;
|
||||
u16_t cx;
|
||||
u16_t flags;
|
||||
} bios_env_t;
|
||||
|
||||
#define FL_CARRY 0x0001 /* carry flag */
|
||||
|
||||
/* Functions defined by boothead.s: */
|
||||
|
||||
void exit(int code);
|
||||
/* Exit the monitor. */
|
||||
u32_t mon2abs(void *ptr);
|
||||
/* Local monitor address to absolute address. */
|
||||
u32_t vec2abs(vector *vec);
|
||||
/* Vector to absolute address. */
|
||||
void raw_copy(u32_t dstaddr, u32_t srcaddr, u32_t count);
|
||||
/* Copy bytes from anywhere to anywhere. */
|
||||
u16_t get_word(u32_t addr);
|
||||
/* Get a word from anywhere. */
|
||||
void put_word(u32_t addr, u16_t word);
|
||||
/* Put a word anywhere. */
|
||||
void relocate(void);
|
||||
/* Switch to a copy of this program. */
|
||||
int dev_open(void), dev_close(void);
|
||||
/* Open device and determine params / close device. */
|
||||
int dev_boundary(u32_t sector);
|
||||
/* True if sector is on a track boundary. */
|
||||
int readsectors(u32_t bufaddr, u32_t sector, u8_t count);
|
||||
/* Read 1 or more sectors from "device". */
|
||||
int writesectors(u32_t bufaddr, u32_t sector, u8_t count);
|
||||
/* Write 1 or more sectors to "device". */
|
||||
|
||||
int biosreadsectors(u32_t bufaddr, u32_t sector, u8_t count);
|
||||
|
||||
int getch(void);
|
||||
/* Read a keypress. */
|
||||
void scan_keyboard(void);
|
||||
/* Read keypress directly from kb controller. */
|
||||
void ungetch(int c);
|
||||
/* Undo a keypress. */
|
||||
int escape(void);
|
||||
/* True if escape typed. */
|
||||
void putch(int c);
|
||||
/* Send a character to the screen. */
|
||||
#if BIOS
|
||||
void pause(void);
|
||||
/* Wait for an interrupt. */
|
||||
void serial_init(int line);
|
||||
#endif /* Enable copying console I/O to a serial line. */
|
||||
|
||||
void set_mode(unsigned mode);
|
||||
void clear_screen(void);
|
||||
/* Set video mode / clear the screen. */
|
||||
|
||||
u16_t get_bus(void);
|
||||
/* System bus type, XT, AT, or MCA. */
|
||||
u16_t get_video(void);
|
||||
/* Display type, MDA to VGA. */
|
||||
u32_t get_tick(void);
|
||||
/* Current value of the clock tick counter. */
|
||||
|
||||
void bootstrap(int device, struct part_entry *entry);
|
||||
/* Execute a bootstrap routine for a different O.S. */
|
||||
void minix(u32_t koff, u32_t kcs, u32_t kds,
|
||||
char *bootparams, size_t paramsize, u32_t aout);
|
||||
/* Start Minix. */
|
||||
|
||||
void int15(bios_env_t *);
|
||||
/* Do an "INT 15" call, primarily for APM. */
|
||||
void scan_keyboard(void);
|
||||
/* Read keyboard character.
|
||||
* Needs to be done in case one is waiting. */
|
||||
void reset(void);
|
||||
/* */
|
||||
|
||||
/* Shared between boot.c and bootimage.c: */
|
||||
|
||||
/* Sticky attributes. */
|
||||
#define E_SPECIAL 0x01 /* These are known to the program. */
|
||||
#define E_DEV 0x02 /* The value is a device name. */
|
||||
#define E_RESERVED 0x04 /* May not be set by user, e.g. 'boot' */
|
||||
#define E_STICKY 0x07 /* Don't go once set. */
|
||||
|
||||
/* Volatile attributes. */
|
||||
#define E_VAR 0x08 /* Variable */
|
||||
#define E_FUNCTION 0x10 /* Function definition. */
|
||||
|
||||
/* Variables, functions, and commands. */
|
||||
typedef struct environment {
|
||||
struct environment *next;
|
||||
char flags;
|
||||
char *name; /* name = value */
|
||||
char *arg; /* name(arg) {value} */
|
||||
char *value;
|
||||
char *defval; /* Safehouse for default values. */
|
||||
} environment;
|
||||
|
||||
EXTERN environment *env; /* Lists the environment. */
|
||||
|
||||
char *b_value(const char *name); /* Get/set the value of a variable. */
|
||||
int b_setvar(int flags, char *name, char *value);
|
||||
void b_unset(const char *name);
|
||||
|
||||
void parse_code(char *code); /* Parse boot monitor commands. */
|
||||
|
||||
extern int fsok; /* True if the boot device contains an FS. */
|
||||
EXTERN u32_t lowsec; /* Offset to the file system on the boot device. */
|
||||
|
||||
/* Called by boot.c: */
|
||||
|
||||
void bootminix(void); /* Load and start a Minix image. */
|
||||
|
||||
|
||||
/* Called by bootimage.c: */
|
||||
|
||||
void readerr(off_t sec, int err);
|
||||
/* Report a read error. */
|
||||
char *ul2a(u32_t n, unsigned b), *ul2a10(u32_t n);
|
||||
/* Transform u32_t to ASCII at base b or base 10. */
|
||||
long a2l(const char *a);
|
||||
/* Cheap atol(). */
|
||||
unsigned a2x(const char *a);
|
||||
/* ASCII to hex. */
|
||||
dev_t name2dev(char *name);
|
||||
/* Translate a device name to a device number. */
|
||||
int numprefix(char *s, char **ps);
|
||||
/* True for a numeric prefix. */
|
||||
int numeric(char *s);
|
||||
/* True for a numeric string. */
|
||||
char *unix_err(int err);
|
||||
/* Give a descriptive text for some UNIX errors. */
|
||||
int run_trailer(void);
|
||||
/* Run the trailer function. */
|
||||
|
||||
#if DOS
|
||||
/* The monitor runs under MS-DOS. */
|
||||
extern char PSP[256]; /* Program Segment Prefix. */
|
||||
EXTERN char *vdisk; /* Name of the virtual disk. */
|
||||
EXTERN char *drun; /* Initial command from DOS command line. */
|
||||
#else
|
||||
/* The monitor uses only the BIOS. */
|
||||
#define DOS 0
|
||||
#endif
|
||||
|
||||
void readblock(off_t, char *, int);
|
||||
void delay(const char *);
|
||||
|
||||
/*
|
||||
* $PchId: boot.h,v 1.12 2002/02/27 19:42:45 philip Exp $
|
||||
*/
|
|
@ -1,30 +0,0 @@
|
|||
# boot monitor: runs in 16-bit mode
|
||||
.include <bsd.own.mk>
|
||||
|
||||
# XXX: Can only be built with ACK currently
|
||||
MINIXID= -sep
|
||||
.include "${.CURDIR}/../minix.ack16.mk"
|
||||
AFLAGS+= -Was-ncc
|
||||
STRIPFLAG= -s
|
||||
LIBDIR?= /usr/lib/i86
|
||||
|
||||
PROG= boot
|
||||
|
||||
SRCS= boothead.s boot.c bootimage.c rawfs.c
|
||||
# Need exec_elf.c from libexec
|
||||
SRCS+= exec_elf.c
|
||||
.PATH: ${.CURDIR}/.. ${MINIXSRCDIR}/lib/libexec
|
||||
|
||||
CPPFLAGS+= -I${MINIXSRCDIR} -I${.CURDIR} -I${.CURDIR}/..
|
||||
|
||||
DPADD+= ${LIBSYS} # for kprintf, kmalloc
|
||||
LDADD+= -lsys
|
||||
|
||||
BINDIR= /usr/mdec
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
realall: .PHONY bootsize
|
||||
bootsize: boot
|
||||
${INSTALL} -S 12kb boot
|
2092
boot/boot/boot.c
2092
boot/boot/boot.c
File diff suppressed because it is too large
Load diff
1638
boot/boot/boothead.s
1638
boot/boot/boothead.s
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,26 +0,0 @@
|
|||
|
||||
#define EMEM_ENTRIES 16
|
||||
#define EMEM_SIZE 24 /* size in bytes of e820_memory struct */
|
||||
#define MEM_ENTRIES 3
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
typedef struct { /* One chunk of free memory. */
|
||||
u32_t base; /* Start byte. */
|
||||
u32_t size; /* Number of bytes. */
|
||||
} memory;
|
||||
|
||||
EXTERN memory mem[MEM_ENTRIES]; /* List of available memory. */
|
||||
|
||||
typedef struct { /* One chunk of free memory. */
|
||||
u32_t base_lo; /* Start byte. */
|
||||
u32_t base_hi;
|
||||
u32_t size_lo; /* Number of bytes. */
|
||||
u32_t size_hi; /* Number of bytes. */
|
||||
u32_t type;
|
||||
u32_t acpi_attrs;
|
||||
} e820_memory;
|
||||
|
||||
EXTERN e820_memory emem[EMEM_ENTRIES]; /* List of available memory. */
|
||||
EXTERN int emem_entries;
|
||||
#endif
|
|
@ -1,19 +0,0 @@
|
|||
# bootblock: secondary boot code, still 16-bit mode
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
# XXX: Can only be built with ACK currently
|
||||
.include "${MINIXSRCDIR}/boot/minix.ack16.mk"
|
||||
AFLAGS+= -Was-ncc
|
||||
STRIPFLAG= -s
|
||||
|
||||
PROG= bootblock
|
||||
|
||||
SRCS= bootblock.s
|
||||
|
||||
BINDIR= /usr/mdec
|
||||
MAN=
|
||||
|
||||
LIBC= # defined, to silence bsd.*.mk
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,256 +0,0 @@
|
|||
#
|
||||
! Bootblock 1.5 - Minix boot block. Author: Kees J. Bot
|
||||
! 21 Dec 1991
|
||||
!
|
||||
! When the PC is powered on, it will try to read the first sector of floppy
|
||||
! disk 0 at address 0x7C00. If this fails due to the absence of flexible
|
||||
! magnetic media, it will read the master boot record from the first sector
|
||||
! of the hard disk. This sector not only contains executable code, but also
|
||||
! the partition table of the hard disk. When executed, it will select the
|
||||
! active partition and load the first sector of that at address 0x7C00.
|
||||
! This file contains the code that is eventually read from either the floppy
|
||||
! disk, or the hard disk partition. It is just smart enough to load /boot
|
||||
! from the boot device into memory at address 0x10000 and execute that. The
|
||||
! disk addresses for /boot are patched into this code by installboot as 24-bit
|
||||
! sector numbers and 8-bit sector counts above enddata upwards. /boot is in
|
||||
! turn smart enough to load the different parts of the Minix kernel into
|
||||
! memory and execute them to finally get Minix started.
|
||||
!
|
||||
|
||||
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
|
||||
BOOTSEG = 0x1000 ! Secondary boot code segment.
|
||||
#ifdef CDBOOT
|
||||
BOOTOFF = 0x0050 ! Offset into /boot above header
|
||||
#else
|
||||
BOOTOFF = 0x0030 ! Offset into /boot above header
|
||||
#endif
|
||||
BUFFER = 0x0600 ! First free memory
|
||||
#ifndef CDBOOT /* just constants, but make no sense for CDs */
|
||||
LOWSEC = 8 ! Offset of logical first sector in partition
|
||||
! table
|
||||
|
||||
! Variables addressed using bp register
|
||||
lowsec = 2 ! Offset of boot partition within drive
|
||||
secpcyl = 6 ! Sectors per cylinder = heads * sectors
|
||||
#endif
|
||||
device = 0 ! The boot device
|
||||
|
||||
.text
|
||||
|
||||
! Start boot procedure.
|
||||
|
||||
boot:
|
||||
xor ax, ax ! ax = 0x0000, the vector segment
|
||||
mov ds, ax
|
||||
cli ! Ignore interrupts while setting stack
|
||||
mov ss, ax ! ss = ds = vector segment
|
||||
mov sp, #LOADOFF ! Usual place for a bootstrap stack
|
||||
sti
|
||||
|
||||
push ax
|
||||
push ax ! Push a zero lowsec(bp)
|
||||
|
||||
push dx ! Boot device in dl will be device(bp)
|
||||
mov bp, sp ! Using var(bp) is one byte cheaper then var.
|
||||
|
||||
push es
|
||||
push si ! es:si = partition table entry if hard disk
|
||||
|
||||
mov di, #LOADOFF+sectors ! char *di = sectors;
|
||||
|
||||
#ifndef CDBOOT
|
||||
testb dl, dl ! Winchester disks if dl >= 0x80
|
||||
jge floppy
|
||||
#endif
|
||||
|
||||
winchester:
|
||||
|
||||
#ifndef CDBOOT
|
||||
! Get the offset of the first sector of the boot partition from the partition
|
||||
! table. The table is found at es:si, the lowsec parameter at offset LOWSEC.
|
||||
|
||||
eseg
|
||||
les ax, LOWSEC(si) ! es:ax = LOWSEC+2(si):LOWSEC(si)
|
||||
mov lowsec+0(bp), ax ! Low 16 bits of partitions first sector
|
||||
mov lowsec+2(bp), es ! High 16 bits of partitions first sector
|
||||
|
||||
! Get the drive parameters, the number of sectors is bluntly written into the
|
||||
! floppy disk sectors/track array.
|
||||
|
||||
movb ah, #0x08 ! Code for drive parameters
|
||||
int 0x13 ! dl still contains drive
|
||||
andb cl, #0x3F ! cl = max sector number (1-origin)
|
||||
movb (di), cl ! Number of sectors per track
|
||||
incb dh ! dh = 1 + max head number (0-origin)
|
||||
#endif
|
||||
jmp loadboot
|
||||
|
||||
#ifndef CDBOOT
|
||||
! Floppy:
|
||||
! Execute three read tests to determine the drive type. Test for each floppy
|
||||
! type by reading the last sector on the first track. If it fails, try a type
|
||||
! that has less sectors. Therefore we start with 1.44M (18 sectors) then 1.2M
|
||||
! (15 sectors) ending with 720K/360K (both 9 sectors).
|
||||
|
||||
next: inc di ! Next number of sectors per track
|
||||
|
||||
floppy: xorb ah, ah ! Reset drive
|
||||
int 0x13
|
||||
|
||||
movb cl, (di) ! cl = number of last sector on track
|
||||
|
||||
cmpb cl, #9 ! No need to do the last 720K/360K test
|
||||
je success
|
||||
|
||||
! Try to read the last sector on track 0
|
||||
|
||||
mov es, lowsec(bp) ! es = vector segment (lowsec = 0)
|
||||
mov bx, #BUFFER ! es:bx buffer = 0x0000:0x0600
|
||||
mov ax, #0x0201 ! Read sector, #sectors = 1
|
||||
xorb ch, ch ! Track 0, last sector
|
||||
xorb dh, dh ! Drive dl, head 0
|
||||
int 0x13
|
||||
jc next ! Error, try the next floppy type
|
||||
|
||||
success:movb dh, #2 ! Load number of heads for multiply
|
||||
#endif
|
||||
|
||||
loadboot:
|
||||
! Load /boot from the boot device
|
||||
|
||||
#ifndef CDBOOT
|
||||
movb al, (di) ! al = (di) = sectors per track
|
||||
mulb dh ! dh = heads, ax = heads * sectors
|
||||
mov secpcyl(bp), ax ! Sectors per cylinder = heads * sectors
|
||||
#endif
|
||||
|
||||
mov ax, #BOOTSEG ! Segment to load /boot into
|
||||
mov es, ax
|
||||
xor bx, bx ! Load first sector at es:bx = BOOTSEG:0x0000
|
||||
mov si, #LOADOFF+addresses ! Start of the boot code addresses
|
||||
load:
|
||||
mov ax, 1(si) ! Get next sector number: low 16 bits
|
||||
movb dl, 3(si) ! Bits 16-23 for your up to 8GB partition
|
||||
xorb dh, dh ! dx:ax = sector within partition
|
||||
#ifndef CDBOOT
|
||||
add ax, lowsec+0(bp)
|
||||
adc dx, lowsec+2(bp)! dx:ax = sector within drive
|
||||
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
|
||||
jae bigdisk
|
||||
div secpcyl(bp) ! ax = cylinder, dx = sector within cylinder
|
||||
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
|
||||
movb ch, dl ! ch = low 8 bits of cylinder
|
||||
divb (di) ! al = head, ah = sector (0-origin)
|
||||
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
|
||||
shr dx, #1
|
||||
shr dx, #1 ! dl[6..7] = high cylinder
|
||||
orb dl, ah ! dl[0..5] = sector (0-origin)
|
||||
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
|
||||
incb cl ! cl[0..5] = sector (1-origin)
|
||||
movb dh, al ! dh = al = head
|
||||
movb dl, device(bp) ! dl = device to read
|
||||
movb al, (di) ! Sectors per track - Sector number (0-origin)
|
||||
subb al, ah ! = Sectors left on this track
|
||||
cmpb al, (si) ! Compare with # sectors to read
|
||||
jbe read ! Cant read past the end of a cylinder?
|
||||
movb al, (si) ! (si) < sectors left on this track
|
||||
read: push ax ! Save al = sectors to read
|
||||
movb ah, #0x02 ! Code for disk read (all registers in use now!)
|
||||
int 0x13 ! Call the BIOS for a read
|
||||
pop cx ! Restore al in cl
|
||||
jmp rdeval
|
||||
#endif
|
||||
bigdisk:
|
||||
movb cl, (si) ! Number of sectors to read
|
||||
push si ! Save si
|
||||
mov si, #LOADOFF+ext_rw ! si = extended read/write parameter packet
|
||||
movb 2(si), cl ! Fill in # blocks to transfer
|
||||
mov 4(si), bx ! Buffer address
|
||||
mov 8(si), ax ! Starting block number = dx:ax
|
||||
mov 10(si), dx
|
||||
movb dl, device(bp) ! dl = device to read
|
||||
movb ah, #0x42 ! Extended read
|
||||
int 0x13
|
||||
pop si ! Restore si to point to the addresses array
|
||||
!jmp rdeval
|
||||
rdeval:
|
||||
jc error ! Jump on disk read error
|
||||
movb al, cl ! Restore al = sectors read
|
||||
addb bh, al ! bx += 2 * al * 256 (add bytes read)
|
||||
addb bh, al ! es:bx = where next sector must be read
|
||||
#ifdef CDBOOT
|
||||
addb bh, al ! For CDs, a sector is 2048 bytes, so
|
||||
addb bh, al ! do this 6 more times to get byte count.
|
||||
addb bh, al
|
||||
addb bh, al
|
||||
addb bh, al
|
||||
addb bh, al
|
||||
#endif
|
||||
add 1(si), ax ! Update address by sectors read
|
||||
adcb 3(si), ah ! Don't forget bits 16-23 (add ah = 0)
|
||||
subb (si), al ! Decrement sector count by sectors read
|
||||
jnz load ! Not all sectors have been read
|
||||
add si, #4 ! Next (address, count) pair
|
||||
cmpb ah, (si) ! Done when no sectors to read
|
||||
jnz load ! Read next chunk of /boot
|
||||
|
||||
done:
|
||||
|
||||
! Call /boot, assuming a long a.out header (48 bytes). The a.out header is
|
||||
! usually short (32 bytes), but to be sure /boot has two entry points:
|
||||
! One at offset 0 for the long, and one at offset 16 for the short header.
|
||||
! Parameters passed in registers are:
|
||||
!
|
||||
! dl = Boot-device.
|
||||
! es:si = Partition table entry if hard disk.
|
||||
!
|
||||
pop si ! Restore es:si = partition table entry
|
||||
pop es ! dl is still loaded
|
||||
jmpf BOOTOFF, BOOTSEG ! jmp to sec. boot (skipping header).
|
||||
|
||||
! Read error: print message, hang forever
|
||||
error:
|
||||
mov si, #LOADOFF+errno+1
|
||||
prnum: movb al, ah ! Error number in ah
|
||||
andb al, #0x0F ! Low 4 bits
|
||||
cmpb al, #10 ! A-F?
|
||||
jb digit ! 0-9!
|
||||
addb al, #7 ! 'A' - ':'
|
||||
digit: addb (si), al ! Modify '0' in string
|
||||
dec si
|
||||
movb cl, #4 ! Next 4 bits
|
||||
shrb ah, cl
|
||||
jnz prnum ! Again if digit > 0
|
||||
|
||||
mov si, #LOADOFF+rderr ! String to print
|
||||
print: lodsb ! al = *si++ is char to be printed
|
||||
testb al, al ! Null byte marks end
|
||||
hang: jz hang ! Hang forever waiting for CTRL-ALT-DEL
|
||||
movb ah, #0x0E ! Print character in teletype mode
|
||||
mov bx, #0x0001 ! Page 0, foreground color
|
||||
int 0x10 ! Call BIOS VIDEO_IO
|
||||
jmp print
|
||||
|
||||
.data
|
||||
rderr: .ascii "Read error "
|
||||
errno: .ascii "00 \0"
|
||||
errend:
|
||||
|
||||
! Floppy disk sectors per track for the 1.44M, 1.2M and 360K/720K types:
|
||||
sectors:
|
||||
.data1 18, 15, 9
|
||||
|
||||
! Extended read/write commands require a parameter packet.
|
||||
ext_rw:
|
||||
.data1 0x10 ! Length of extended r/w packet
|
||||
.data1 0 ! Reserved
|
||||
.data2 0 ! Blocks to transfer (to be filled in)
|
||||
.data2 0 ! Buffer address offset (tbfi)
|
||||
.data2 BOOTSEG ! Buffer address segment
|
||||
.data4 0 ! Starting block number low 32 bits (tbfi)
|
||||
.data4 0 ! Starting block number high 32 bits
|
||||
|
||||
.align 2
|
||||
addresses:
|
||||
! The space below this is for disk addresses for a 38K /boot program (worst
|
||||
! case, i.e. file is completely fragmented). It should be enough.
|
|
@ -1,21 +0,0 @@
|
|||
# cdbootblock: secondary boot code, when booting from cd-rom
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
# XXX: Can only be built with ACK currently
|
||||
.include "${MINIXSRCDIR}/boot/minix.ack16.mk"
|
||||
AFLAGS+= -Was-ncc
|
||||
STRIPFLAG= -s
|
||||
|
||||
PROG= cdbootblock
|
||||
|
||||
SRCS= bootblock.s
|
||||
.PATH: ${.CURDIR}/../bootblock
|
||||
AFLAGS+= -DCDBOOT
|
||||
|
||||
BINDIR= /usr/mdec
|
||||
MAN=
|
||||
|
||||
LIBC= # defined, to silence bsd.*.mk
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,12 +0,0 @@
|
|||
# edparams: customize boot; runs on both installer's and user's machines
|
||||
|
||||
PROG= edparams
|
||||
BINDIR= /usr/bin
|
||||
|
||||
SRCS= boot.c rawfs.c
|
||||
.PATH: ${.CURDIR}/../boot ${.CURDIR}/..
|
||||
CPPFLAGS= -DUNIX -I${MINIXSRCDIR} -I${.CURDIR}/..
|
||||
|
||||
MAN= # monitor.8
|
||||
|
||||
.include <bsd.prog.mk>
|
13
boot/image.h
13
boot/image.h
|
@ -1,13 +0,0 @@
|
|||
/* image.h - Info between installboot and boot. Author: Kees J. Bot
|
||||
*/
|
||||
|
||||
#define IM_NAME_MAX 63
|
||||
|
||||
struct image_header {
|
||||
char name[IM_NAME_MAX + 1]; /* Null terminated. */
|
||||
struct exec process;
|
||||
};
|
||||
|
||||
/*
|
||||
* $PchId: image.h,v 1.4 1995/11/27 22:23:12 philip Exp $
|
||||
*/
|
|
@ -1,12 +0,0 @@
|
|||
# installboot: install the boot package; runs on the installer's machine
|
||||
|
||||
PROG= installboot_minix
|
||||
BINDIR= /usr/bin
|
||||
|
||||
SRCS= installboot.c rawfs.c
|
||||
.PATH: ${.CURDIR}/..
|
||||
CPPFLAGS= -I${MINIXSRCDIR} -I${.CURDIR}/..
|
||||
|
||||
MAN= # installboot.8
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,832 +0,0 @@
|
|||
/* installboot 3.0 - Make a device bootable Author: Kees J. Bot
|
||||
* 21 Dec 1991
|
||||
*
|
||||
* Either make a device bootable or make an image from kernel, mm, fs, etc.
|
||||
*/
|
||||
#define _POSIX_SOURCE 1
|
||||
#define _MINIX 1
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <a.out.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/partition.h>
|
||||
#include <minix/u64.h>
|
||||
#include "rawfs.h"
|
||||
#include "image.h"
|
||||
|
||||
#define BOOTBLOCK 0 /* Of course */
|
||||
#define SECTOR_SIZE 512 /* Disk sector size. */
|
||||
#define RATIO(b) ((b)/SECTOR_SIZE)
|
||||
#define SIGNATURE 0xAA55 /* Boot block signature. */
|
||||
#define BOOT_MAX 64 /* Absolute maximum size of secondary boot */
|
||||
#define SIGPOS 510 /* Where to put signature word. */
|
||||
#define PARTPOS 446 /* Offset to the partition table in a master
|
||||
* boot block.
|
||||
*/
|
||||
|
||||
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
|
||||
#define control(c) between('\0', (c), '\37')
|
||||
|
||||
#define BOOT_BLOCK_SIZE 1024
|
||||
|
||||
static void report(const char *label)
|
||||
/* installboot: label: No such file or directory */
|
||||
{
|
||||
fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
|
||||
}
|
||||
|
||||
static void fatal(const char *label)
|
||||
{
|
||||
report(label);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *basename(char *name)
|
||||
/* Return the last component of name, stripping trailing slashes from name.
|
||||
* Precondition: name != "/". If name is prefixed by a label, then the
|
||||
* label is copied to the basename too.
|
||||
*/
|
||||
{
|
||||
static char base[IM_NAME_MAX];
|
||||
char *p, *bp= base;
|
||||
|
||||
if ((p= strchr(name, ':')) != NULL) {
|
||||
while (name <= p && bp < base + IM_NAME_MAX - 1)
|
||||
*bp++ = *name++;
|
||||
}
|
||||
for (;;) {
|
||||
if ((p= strrchr(name, '/')) == NULL) { p= name; break; }
|
||||
if (*++p != 0) break;
|
||||
*--p= 0;
|
||||
}
|
||||
while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
|
||||
*bp= 0;
|
||||
return base;
|
||||
}
|
||||
|
||||
static void bread(FILE *f, char *name, void *buf, size_t len)
|
||||
/* Read len bytes. Don't dare return without them. */
|
||||
{
|
||||
if (len > 0 && fread(buf, len, 1, f) != 1) {
|
||||
if (ferror(f)) fatal(name);
|
||||
fprintf(stderr, "installboot: Unexpected EOF on %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void bwrite(FILE *f, const char *name, const void *buf, size_t len)
|
||||
{
|
||||
if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
|
||||
}
|
||||
|
||||
long total_text= 0, total_data= 0, total_bss= 0;
|
||||
int making_image= 0;
|
||||
|
||||
void read_header(int talk, char *proc, FILE *procf, struct image_header *ihdr)
|
||||
/* Read the a.out header of a program and check it. If procf happens to be
|
||||
* NULL then the header is already in *image_hdr and need only be checked.
|
||||
*/
|
||||
{
|
||||
int n, big= 0;
|
||||
static int banner= 0;
|
||||
struct exec *phdr= &ihdr->process;
|
||||
|
||||
if (procf == NULL) {
|
||||
/* Header already present. */
|
||||
n= phdr->a_hdrlen;
|
||||
} else {
|
||||
memset(ihdr, 0, sizeof(*ihdr));
|
||||
|
||||
/* Put the basename of proc in the header. */
|
||||
strncpy(ihdr->name, basename(proc), IM_NAME_MAX);
|
||||
|
||||
/* Read the header. */
|
||||
n= fread(phdr, sizeof(char), A_MINHDR, procf);
|
||||
if (ferror(procf)) fatal(proc);
|
||||
}
|
||||
|
||||
if (n < A_MINHDR || BADMAG(*phdr)) {
|
||||
fprintf(stderr, "installboot: %s is not an executable\n", proc);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the rest of the exec header. */
|
||||
if (procf != NULL) {
|
||||
bread(procf, proc, ((char *) phdr) + A_MINHDR,
|
||||
phdr->a_hdrlen - A_MINHDR);
|
||||
}
|
||||
|
||||
if (talk && !banner) {
|
||||
printf(" text data bss size\n");
|
||||
banner= 1;
|
||||
}
|
||||
|
||||
if (talk) {
|
||||
printf(" %8ld %8ld %8ld %9ld %s\n",
|
||||
phdr->a_text, phdr->a_data, phdr->a_bss,
|
||||
phdr->a_text + phdr->a_data + phdr->a_bss, proc);
|
||||
}
|
||||
total_text+= phdr->a_text;
|
||||
total_data+= phdr->a_data;
|
||||
total_bss+= phdr->a_bss;
|
||||
|
||||
if (phdr->a_cpu == A_I8086) {
|
||||
long data= phdr->a_data + phdr->a_bss;
|
||||
|
||||
if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;
|
||||
|
||||
if (phdr->a_text >= 65536) big|= 1;
|
||||
if (data >= 65536) big|= 2;
|
||||
}
|
||||
if (big) {
|
||||
fprintf(stderr,
|
||||
"%s will crash, %s%s%s segment%s larger then 64K\n",
|
||||
proc,
|
||||
big & 1 ? "text" : "",
|
||||
big == 3 ? " and " : "",
|
||||
big & 2 ? "data" : "",
|
||||
big == 3 ? "s are" : " is");
|
||||
}
|
||||
}
|
||||
|
||||
void padimage(const char *image, FILE *imagef, int n)
|
||||
/* Add n zeros to image to pad it to a sector boundary. */
|
||||
{
|
||||
while (n > 0) {
|
||||
if (putc(0, imagef) == EOF) fatal(image);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
#define align(n) (((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))
|
||||
|
||||
void copyexec(char *proc, FILE *procf, char *image, FILE *imagef, long n)
|
||||
/* Copy n bytes from proc to image padded to fill a sector. */
|
||||
{
|
||||
int pad, c;
|
||||
|
||||
/* Compute number of padding bytes. */
|
||||
pad= align(n) - n;
|
||||
|
||||
while (n > 0) {
|
||||
if ((c= getc(procf)) == EOF) {
|
||||
if (ferror(procf)) fatal(proc);
|
||||
fprintf(stderr, "installboot: premature EOF on %s\n",
|
||||
proc);
|
||||
exit(1);
|
||||
}
|
||||
if (putc(c, imagef) == EOF) fatal(image);
|
||||
n--;
|
||||
}
|
||||
padimage(image, imagef, pad);
|
||||
}
|
||||
|
||||
void make_image(char *image, char **procv)
|
||||
/* Collect a set of files in an image, each "segment" is nicely padded out
|
||||
* to SECTOR_SIZE, so it may be read from disk into memory without trickery.
|
||||
*/
|
||||
{
|
||||
FILE *imagef, *procf;
|
||||
char *proc, *file;
|
||||
int procn;
|
||||
struct image_header ihdr;
|
||||
struct exec phdr;
|
||||
struct stat st;
|
||||
|
||||
making_image= 1;
|
||||
|
||||
if ((imagef= fopen(image, "w")) == NULL) fatal(image);
|
||||
|
||||
for (procn= 0; (proc= *procv++) != NULL; procn++) {
|
||||
/* Remove the label from the file name. */
|
||||
if ((file= strchr(proc, ':')) != NULL) file++; else file= proc;
|
||||
|
||||
/* Real files please, may need to seek. */
|
||||
if (stat(file, &st) < 0
|
||||
|| (errno= EISDIR, !S_ISREG(st.st_mode))
|
||||
|| (procf= fopen(file, "r")) == NULL
|
||||
) fatal(proc);
|
||||
|
||||
/* Read a.out header. */
|
||||
read_header(1, proc, procf, &ihdr);
|
||||
|
||||
/* Scratch. */
|
||||
phdr= ihdr.process;
|
||||
|
||||
/* The symbol table is always stripped off. */
|
||||
ihdr.process.a_syms= 0;
|
||||
ihdr.process.a_flags &= ~A_NSYM;
|
||||
|
||||
/* Write header padded to fill a sector */
|
||||
bwrite(imagef, image, &ihdr, sizeof(ihdr));
|
||||
|
||||
padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));
|
||||
|
||||
/* A page aligned executable needs the header in text. */
|
||||
if (phdr.a_flags & A_PAL) {
|
||||
rewind(procf);
|
||||
phdr.a_text+= phdr.a_hdrlen;
|
||||
}
|
||||
|
||||
/* Copy text and data of proc to image. */
|
||||
if (phdr.a_flags & A_SEP) {
|
||||
/* Separate I&D: pad text & data separately. */
|
||||
|
||||
copyexec(proc, procf, image, imagef, phdr.a_text);
|
||||
copyexec(proc, procf, image, imagef, phdr.a_data);
|
||||
} else {
|
||||
/* Common I&D: keep text and data together. */
|
||||
|
||||
copyexec(proc, procf, image, imagef,
|
||||
phdr.a_text + phdr.a_data);
|
||||
}
|
||||
|
||||
/* Done with proc. */
|
||||
(void) fclose(procf);
|
||||
}
|
||||
/* Done with image. */
|
||||
|
||||
if (fclose(imagef) == EOF) fatal(image);
|
||||
|
||||
printf(" ------ ------ ------ -------\n");
|
||||
printf(" %8ld %8ld %8ld %9ld total\n",
|
||||
total_text, total_data, total_bss,
|
||||
total_text + total_data + total_bss);
|
||||
}
|
||||
|
||||
void extractexec(FILE *imagef, char *image, FILE *procf, char *proc,
|
||||
long count, off_t *alen)
|
||||
/* Copy a segment of an executable. It is padded to a sector in image. */
|
||||
{
|
||||
char buf[SECTOR_SIZE];
|
||||
|
||||
while (count > 0) {
|
||||
bread(imagef, image, buf, sizeof(buf));
|
||||
*alen-= sizeof(buf);
|
||||
|
||||
bwrite(procf, proc, buf,
|
||||
count < sizeof(buf) ? (size_t) count : sizeof(buf));
|
||||
count-= sizeof(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void extract_image(char *image)
|
||||
/* Extract the executables from an image. */
|
||||
{
|
||||
FILE *imagef, *procf;
|
||||
off_t len;
|
||||
struct stat st;
|
||||
struct image_header ihdr;
|
||||
struct exec phdr;
|
||||
char buf[SECTOR_SIZE];
|
||||
|
||||
if (stat(image, &st) < 0) fatal(image);
|
||||
|
||||
/* Size of the image. */
|
||||
len= S_ISREG(st.st_mode) ? st.st_size : -1;
|
||||
|
||||
if ((imagef= fopen(image, "r")) == NULL) fatal(image);
|
||||
|
||||
while (len != 0) {
|
||||
/* Extract a program, first sector is an extended header. */
|
||||
bread(imagef, image, buf, sizeof(buf));
|
||||
len-= sizeof(buf);
|
||||
|
||||
memcpy(&ihdr, buf, sizeof(ihdr));
|
||||
phdr= ihdr.process;
|
||||
|
||||
/* Check header. */
|
||||
read_header(1, ihdr.name, NULL, &ihdr);
|
||||
|
||||
if ((procf= fopen(ihdr.name, "w")) == NULL) fatal(ihdr.name);
|
||||
|
||||
if (phdr.a_flags & A_PAL) {
|
||||
/* A page aligned process contains a header in text. */
|
||||
phdr.a_text+= phdr.a_hdrlen;
|
||||
} else {
|
||||
bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
|
||||
}
|
||||
|
||||
/* Extract text and data segments. */
|
||||
if (phdr.a_flags & A_SEP) {
|
||||
extractexec(imagef, image, procf, ihdr.name,
|
||||
phdr.a_text, &len);
|
||||
extractexec(imagef, image, procf, ihdr.name,
|
||||
phdr.a_data, &len);
|
||||
} else {
|
||||
extractexec(imagef, image, procf, ihdr.name,
|
||||
phdr.a_text + phdr.a_data, &len);
|
||||
}
|
||||
|
||||
if (fclose(procf) == EOF) fatal(ihdr.name);
|
||||
}
|
||||
}
|
||||
|
||||
static int rawfd; /* File descriptor to open device. */
|
||||
static const char *rawdev; /* Name of device. */
|
||||
|
||||
void readblock(off_t blk, char *buf, int block_size)
|
||||
/* For rawfs, so that it can read blocks. */
|
||||
{
|
||||
int n;
|
||||
|
||||
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|
||||
|| (n= read(rawfd, buf, block_size)) < 0
|
||||
) fatal(rawdev);
|
||||
|
||||
if (n < block_size) {
|
||||
fprintf(stderr, "installboot: Unexpected EOF on %s\n", rawdev);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void writeblock(off_t blk, const char *buf, int block_size)
|
||||
/* Add a function to write blocks for local use. */
|
||||
{
|
||||
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|
||||
|| write(rawfd, buf, block_size) < 0
|
||||
) fatal(rawdev);
|
||||
}
|
||||
|
||||
int raw_install(char *file, off_t *start, off_t *len, int block_size)
|
||||
/* Copy bootcode or an image to the boot device at the given absolute disk
|
||||
* block number. This "raw" installation is used to place bootcode and
|
||||
* image on a disk without a filesystem to make a simple boot disk. Useful
|
||||
* in automated scripts for J. Random User.
|
||||
* Note: *len == 0 when an image is read. It is set right afterwards.
|
||||
*/
|
||||
{
|
||||
static char buf[_MAX_BLOCK_SIZE]; /* Nonvolatile block buffer. */
|
||||
FILE *f;
|
||||
off_t sec;
|
||||
unsigned long devsize;
|
||||
static int banner= 0;
|
||||
struct partition entry;
|
||||
|
||||
/* See if the device has a maximum size. */
|
||||
devsize= -1;
|
||||
if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);
|
||||
|
||||
if ((f= fopen(file, "r")) == NULL) fatal(file);
|
||||
|
||||
/* Copy sectors from file onto the boot device. */
|
||||
sec= *start;
|
||||
do {
|
||||
int off= sec % RATIO(BOOT_BLOCK_SIZE);
|
||||
|
||||
if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
|
||||
break;
|
||||
|
||||
if (sec >= devsize) {
|
||||
fprintf(stderr,
|
||||
"installboot: %s can't be attached to %s\n",
|
||||
file, rawdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (off == RATIO(BOOT_BLOCK_SIZE) - 1) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
|
||||
} while (++sec != *start + *len);
|
||||
|
||||
if (ferror(f)) fatal(file);
|
||||
(void) fclose(f);
|
||||
|
||||
/* Write a partial block, this may be the last image. */
|
||||
if (sec % RATIO(BOOT_BLOCK_SIZE) != 0) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
|
||||
|
||||
if (!banner) {
|
||||
printf(" sector length\n");
|
||||
banner= 1;
|
||||
}
|
||||
*len= sec - *start;
|
||||
printf("%8ld%8ld %s\n", *start, *len, file);
|
||||
*start= sec;
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum howto { FS, BOOT };
|
||||
|
||||
void make_bootable(enum howto how, char *device, char *bootblock,
|
||||
char *bootcode, char **imagev)
|
||||
/* Install bootblock on the bootsector of device with the disk addresses to
|
||||
* bootcode patched into the data segment of bootblock. "How" tells if there
|
||||
* should or shoudn't be a file system on the disk. The images in the imagev
|
||||
* vector are added to the end of the device.
|
||||
*/
|
||||
{
|
||||
char buf[_MAX_BLOCK_SIZE + 256], *adrp, *parmp;
|
||||
struct fileaddr {
|
||||
off_t address;
|
||||
int count;
|
||||
} bootaddr[BOOT_MAX + 1], *bap= bootaddr;
|
||||
struct exec boothdr;
|
||||
struct image_header dummy;
|
||||
struct stat st;
|
||||
ino_t ino;
|
||||
off_t sector, max_sector;
|
||||
FILE *bootf;
|
||||
off_t addr, fssize, pos, len;
|
||||
char *labels, *label, *image;
|
||||
int nolabel;
|
||||
int block_size = 0;
|
||||
|
||||
/* Open device and set variables for readblock. */
|
||||
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
|
||||
|
||||
/* Read and check the superblock. */
|
||||
fssize= r_super(&block_size);
|
||||
|
||||
switch (how) {
|
||||
case FS:
|
||||
if (fssize == 0) {
|
||||
fprintf(stderr,
|
||||
"installboot: %s is not a Minix file system\n",
|
||||
device);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case BOOT:
|
||||
if (fssize != 0) {
|
||||
int s;
|
||||
printf("%s contains a file system!\n", device);
|
||||
printf("Scribbling in 10 seconds");
|
||||
for (s= 0; s < 10; s++) {
|
||||
fputc('.', stdout);
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
fssize= 1; /* Just a boot block. */
|
||||
}
|
||||
|
||||
if (how == FS) {
|
||||
/* See if the boot code can be found on the file system. */
|
||||
if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
|
||||
if (errno != ENOENT) fatal(bootcode);
|
||||
}
|
||||
} else {
|
||||
/* Boot code must be attached at the end. */
|
||||
ino= 0;
|
||||
}
|
||||
|
||||
if (ino == 0) {
|
||||
/* For a raw installation, we need to copy the boot code onto
|
||||
* the device, so we need to look at the file to be copied.
|
||||
*/
|
||||
if (stat(bootcode, &st) < 0) fatal(bootcode);
|
||||
|
||||
if ((bootf= fopen(bootcode, "r")) == NULL) fatal(bootcode);
|
||||
} else {
|
||||
/* Boot code is present in the file system. */
|
||||
r_stat(ino, &st);
|
||||
|
||||
/* Get the header from the first block. */
|
||||
if ((addr= r_vir2abs((off_t) 0)) == 0) {
|
||||
boothdr.a_magic[0]= !A_MAGIC0;
|
||||
} else {
|
||||
readblock(addr, buf, block_size);
|
||||
memcpy(&boothdr, buf, sizeof(struct exec));
|
||||
}
|
||||
bootf= NULL;
|
||||
dummy.process= boothdr;
|
||||
}
|
||||
/* See if it is an executable (read_header does the check). */
|
||||
read_header(0, bootcode, bootf, &dummy);
|
||||
boothdr= dummy.process;
|
||||
|
||||
if (bootf != NULL) fclose(bootf);
|
||||
|
||||
/* Get all the sector addresses of the secondary boot code. */
|
||||
max_sector= (boothdr.a_hdrlen + boothdr.a_text
|
||||
+ boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
||||
|
||||
if (max_sector > BOOT_MAX * RATIO(block_size)) {
|
||||
fprintf(stderr, "installboot: %s is way too big\n", bootcode);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Determine the addresses to the boot code to be patched into the
|
||||
* boot block.
|
||||
*/
|
||||
bap->count= 0; /* Trick to get the address recording going. */
|
||||
|
||||
for (sector= 0; sector < max_sector; sector++) {
|
||||
if (ino == 0) {
|
||||
addr= fssize + (sector / RATIO(block_size));
|
||||
} else
|
||||
if ((addr= r_vir2abs(sector / RATIO(block_size))) == 0) {
|
||||
fprintf(stderr, "installboot: %s has holes!\n",
|
||||
bootcode);
|
||||
exit(1);
|
||||
}
|
||||
addr= (addr * RATIO(block_size)) + (sector % RATIO(block_size));
|
||||
|
||||
/* First address of the addresses array? */
|
||||
if (bap->count == 0) bap->address= addr;
|
||||
|
||||
/* Paste sectors together in a multisector read. */
|
||||
if (bap->address + bap->count == addr)
|
||||
bap->count++;
|
||||
else {
|
||||
/* New address. */
|
||||
bap++;
|
||||
bap->address= addr;
|
||||
bap->count= 1;
|
||||
}
|
||||
}
|
||||
(++bap)->count= 0; /* No more. */
|
||||
|
||||
/* Get the boot block and patch the pieces in. */
|
||||
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
|
||||
|
||||
if ((bootf= fopen(bootblock, "r")) == NULL) fatal(bootblock);
|
||||
|
||||
read_header(0, bootblock, bootf, &dummy);
|
||||
boothdr= dummy.process;
|
||||
|
||||
if (boothdr.a_text + boothdr.a_data +
|
||||
4 * (bap - bootaddr) + 1 > PARTPOS) {
|
||||
fprintf(stderr,
|
||||
"installboot: %s + addresses to %s don't fit in the boot sector\n",
|
||||
bootblock, bootcode);
|
||||
fprintf(stderr,
|
||||
"You can try copying/reinstalling %s to defragment it\n",
|
||||
bootcode);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* All checks out right. Read bootblock into the boot block! */
|
||||
bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
|
||||
(void) fclose(bootf);
|
||||
|
||||
/* Patch the addresses in. */
|
||||
adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
|
||||
for (bap= bootaddr; bap->count != 0; bap++) {
|
||||
*adrp++= bap->count;
|
||||
*adrp++= (bap->address >> 0) & 0xFF;
|
||||
*adrp++= (bap->address >> 8) & 0xFF;
|
||||
*adrp++= (bap->address >> 16) & 0xFF;
|
||||
}
|
||||
/* Zero count stops bootblock's reading loop. */
|
||||
*adrp++= 0;
|
||||
|
||||
if (bap > bootaddr+1) {
|
||||
printf("%s and %d addresses to %s patched into %s\n",
|
||||
bootblock, (int)(bap - bootaddr), bootcode, device);
|
||||
}
|
||||
|
||||
/* Boot block signature. */
|
||||
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
|
||||
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
|
||||
|
||||
/* Sector 2 of the boot block is used for boot parameters, initially
|
||||
* filled with null commands (newlines). Initialize it only if
|
||||
* necessary.
|
||||
*/
|
||||
for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++) {
|
||||
if (*imagev != NULL || (control(*parmp) && *parmp != '\n')) {
|
||||
/* Param sector must be initialized. */
|
||||
memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Offset to the end of the file system to add boot code and images. */
|
||||
pos= fssize * RATIO(block_size);
|
||||
|
||||
if (ino == 0) {
|
||||
/* Place the boot code onto the boot device. */
|
||||
len= max_sector;
|
||||
if (!raw_install(bootcode, &pos, &len, block_size)) {
|
||||
if (how == FS) {
|
||||
fprintf(stderr,
|
||||
"\t(Isn't there a copy of %s on %s that can be used?)\n",
|
||||
bootcode, device);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
parmp= buf + SECTOR_SIZE;
|
||||
nolabel= 0;
|
||||
|
||||
if (how == BOOT) {
|
||||
/* A boot only disk needs to have floppies swapped. */
|
||||
strcpy(parmp,
|
||||
"trailer()echo \\nInsert the root diskette then hit RETURN\\n\\w\\c\n");
|
||||
parmp+= strlen(parmp);
|
||||
}
|
||||
|
||||
while ((labels= *imagev++) != NULL) {
|
||||
/* Place each kernel image on the boot device. */
|
||||
|
||||
if ((image= strchr(labels, ':')) != NULL)
|
||||
*image++= 0;
|
||||
else {
|
||||
if (nolabel) {
|
||||
fprintf(stderr,
|
||||
"installboot: Only one image can be the default\n");
|
||||
exit(1);
|
||||
}
|
||||
nolabel= 1;
|
||||
image= labels;
|
||||
labels= NULL;
|
||||
}
|
||||
len= 0;
|
||||
if (!raw_install(image, &pos, &len, block_size)) exit(1);
|
||||
|
||||
if (labels == NULL) {
|
||||
/* Let this image be the default. */
|
||||
sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
|
||||
parmp+= strlen(parmp);
|
||||
}
|
||||
|
||||
while (labels != NULL) {
|
||||
/* Image is prefixed by a comma separated list of
|
||||
* labels. Define functions to select label and image.
|
||||
*/
|
||||
label= labels;
|
||||
if ((labels= strchr(labels, ',')) != NULL) *labels++ = 0;
|
||||
|
||||
sprintf(parmp,
|
||||
"%s(%c){label=%s;image=%ld:%ld;echo %s kernel selected;menu}\n",
|
||||
label,
|
||||
between('A', label[0], 'Z')
|
||||
? label[0]-'A'+'a' : label[0],
|
||||
label, pos-len, len, label);
|
||||
parmp+= strlen(parmp);
|
||||
}
|
||||
|
||||
if (parmp > buf + block_size) {
|
||||
fprintf(stderr,
|
||||
"installboot: Out of parameter space, too many images\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
/* Install boot block. */
|
||||
writeblock((off_t) BOOTBLOCK, buf, 1024);
|
||||
|
||||
if (pos > fssize * RATIO(block_size)) {
|
||||
/* Tell the total size of the data on the device. */
|
||||
printf("%16ld (%ld kb) total\n", pos,
|
||||
(pos + RATIO(block_size) - 1) / RATIO(block_size));
|
||||
}
|
||||
}
|
||||
|
||||
static void install_master(const char *device, char *masterboot, char **guide)
|
||||
/* Booting a hard disk is a two stage process: The master bootstrap in sector
|
||||
* 0 loads the bootstrap from sector 0 of the active partition which in turn
|
||||
* starts the operating system. This code installs such a master bootstrap
|
||||
* on a hard disk. If guide[0] is non-null then the master bootstrap is
|
||||
* guided into booting a certain device.
|
||||
*/
|
||||
{
|
||||
FILE *masf;
|
||||
unsigned long size;
|
||||
struct stat st;
|
||||
static char buf[_MAX_BLOCK_SIZE];
|
||||
|
||||
/* Open device. */
|
||||
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
|
||||
|
||||
/* Open the master boot code. */
|
||||
if ((masf= fopen(masterboot, "r")) == NULL) fatal(masterboot);
|
||||
|
||||
/* See if the user is cloning a device. */
|
||||
if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
|
||||
size= PARTPOS;
|
||||
else {
|
||||
/* Read and check header otherwise. */
|
||||
struct image_header ihdr;
|
||||
|
||||
read_header(1, masterboot, masf, &ihdr);
|
||||
size= ihdr.process.a_text + ihdr.process.a_data;
|
||||
}
|
||||
if (size > PARTPOS) {
|
||||
fprintf(stderr, "installboot: %s is too big\n", masterboot);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read the master boot block, patch it, write. */
|
||||
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
|
||||
|
||||
memset(buf, 0, PARTPOS);
|
||||
(void) bread(masf, masterboot, buf, size);
|
||||
|
||||
if (guide[0] != NULL) {
|
||||
/* Fixate partition to boot. */
|
||||
const char *keys= guide[0];
|
||||
const char *logical= guide[1];
|
||||
size_t i;
|
||||
int logfd;
|
||||
u32_t offset;
|
||||
struct partition geometry;
|
||||
|
||||
/* A string of digits to be seen as keystrokes. */
|
||||
i= 0;
|
||||
do {
|
||||
if (!between('0', keys[i], '9')) {
|
||||
fprintf(stderr,
|
||||
"installboot: bad guide keys '%s'\n",
|
||||
keys);
|
||||
exit(1);
|
||||
}
|
||||
} while (keys[++i] != 0);
|
||||
|
||||
if (size + i + 1 > PARTPOS) {
|
||||
fprintf(stderr,
|
||||
"installboot: not enough space after '%s' for '%s'\n",
|
||||
masterboot, keys);
|
||||
exit(1);
|
||||
}
|
||||
memcpy(buf + size, keys, i);
|
||||
size += i;
|
||||
buf[size]= '\r';
|
||||
|
||||
if (logical != NULL) {
|
||||
if ((logfd= open(logical, O_RDONLY)) < 0
|
||||
|| ioctl(logfd, DIOCGETP, &geometry) < 0
|
||||
) {
|
||||
fatal(logical);
|
||||
}
|
||||
offset= div64u(geometry.base, SECTOR_SIZE);
|
||||
if (size + 5 > PARTPOS) {
|
||||
fprintf(stderr,
|
||||
"installboot: not enough space "
|
||||
"after '%s' for '%s' and an offset "
|
||||
"to '%s'\n",
|
||||
masterboot, keys, logical);
|
||||
exit(1);
|
||||
}
|
||||
buf[size]= '#';
|
||||
memcpy(buf+size+1, &offset, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/* Install signature. */
|
||||
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
|
||||
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
|
||||
|
||||
writeblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: installboot -i(mage) image kernel mm fs ... init\n"
|
||||
" installboot -(e)x(tract) image\n"
|
||||
" installboot -d(evice) device bootblock boot [image ...]\n"
|
||||
" installboot -b(oot) device bootblock boot image ...\n"
|
||||
" installboot -m(aster) device masterboot [keys [logical]]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int isoption(const char *option, const char *test)
|
||||
/* Check if the option argument is equals "test". Also accept -i as short
|
||||
* for -image, and the special case -x for -extract.
|
||||
*/
|
||||
{
|
||||
if (strcmp(option, test) == 0) return 1;
|
||||
if (option[0] != '-' && strlen(option) != 2) return 0;
|
||||
if (option[1] == test[1]) return 1;
|
||||
if (option[1] == 'x' && test[1] == 'e') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) usage();
|
||||
|
||||
if (argc >= 4 && isoption(argv[1], "-image")) {
|
||||
make_image(argv[2], argv + 3);
|
||||
} else
|
||||
if (argc == 3 && isoption(argv[1], "-extract")) {
|
||||
extract_image(argv[2]);
|
||||
} else
|
||||
if (argc >= 5 && isoption(argv[1], "-device")) {
|
||||
make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
|
||||
} else
|
||||
if (argc >= 6 && isoption(argv[1], "-boot")) {
|
||||
make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
|
||||
} else
|
||||
if ((4 <= argc && argc <= 6) && isoption(argv[1], "-master")) {
|
||||
install_master(argv[2], argv[3], argv + 4);
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: installboot.c,v 1.10 2000/08/13 22:07:50 philip Exp $
|
||||
*/
|
|
@ -1,19 +0,0 @@
|
|||
# jumpboot: supplementary MBR code (alternate to masterboot)
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
# XXX: Can only be built with ACK currently
|
||||
.include "${MINIXSRCDIR}/boot/minix.ack16.mk"
|
||||
AFLAGS+= -Was-ncc
|
||||
STRIPFLAG= -s
|
||||
|
||||
PROG= jumpboot
|
||||
|
||||
SRCS= jumpboot.s
|
||||
|
||||
BINDIR= /usr/mdec
|
||||
MAN=
|
||||
|
||||
LIBC= # defined, to silence bsd.*.mk
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,261 +0,0 @@
|
|||
! jumpboot 1.0 - Jump to another bootstrap Author: Kees J. Bot
|
||||
! 14 Apr 1999
|
||||
!
|
||||
! This code may be placed into any free boot sector, like the first sector
|
||||
! of an extended partition, a file system partition other than the root,
|
||||
! or even the master bootstrap. It will load and run another bootstrap whose
|
||||
! disk, partition, and slice number (not necessarily all three) are patched
|
||||
! into this code by installboot. If the ALT key is held down when this code
|
||||
! is booted then you can type the disk, partition, and slice numbers manually.
|
||||
! The manual interface is default if no numbers are patched in by installboot.
|
||||
!
|
||||
|
||||
o32 = 0x66 ! This assembler doesn't know 386 extensions
|
||||
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
|
||||
BUFFER = 0x0600 ! First free memory
|
||||
PART_TABLE = 446 ! Location of partition table within master
|
||||
PENTRYSIZE = 16 ! Size of one partition table entry
|
||||
MAGIC = 510 ! Location of the AA55 magic number
|
||||
|
||||
! <ibm/partition.h>:
|
||||
MINIX_PART = 0x81
|
||||
sysind = 4
|
||||
lowsec = 8
|
||||
|
||||
|
||||
.text
|
||||
|
||||
! Find and load another bootstrap and jump to it.
|
||||
jumpboot:
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
cli
|
||||
mov ss, ax ! ds = es = ss = Vector segment
|
||||
mov sp, #LOADOFF
|
||||
sti
|
||||
|
||||
! Move this code to safety, then jump to it.
|
||||
mov si, sp ! si = start of this code
|
||||
mov di, #BUFFER ! di = Buffer area
|
||||
mov cx, #512/2 ! One sector
|
||||
cld
|
||||
rep movs
|
||||
jmpf BUFFER+migrate, 0 ! To safety
|
||||
migrate:
|
||||
|
||||
mov bp, #BUFFER+guide ! Patched guiding characters
|
||||
altkey:
|
||||
movb ah, #0x02 ! Keyboard shift status
|
||||
int 0x16
|
||||
testb al, #0x08 ! Bit 3 = ALT key
|
||||
jz noalt ! ALT key pressed?
|
||||
again:
|
||||
mov bp, #zero ! Ignore patched stuff
|
||||
noalt:
|
||||
|
||||
! Follow guide characters to find the boot partition.
|
||||
call print
|
||||
.ascii "d?\b\0" ! Initial greeting
|
||||
|
||||
! Disk number?
|
||||
disk:
|
||||
movb dl, #0x80 - 0x30 ! Prepare to add an ASCII digit
|
||||
call getch ! Get number to tell which disk
|
||||
addb dl, al ! dl = 0x80 + (al - '0')
|
||||
jns n0nboot ! Result should be >= 0x80
|
||||
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
|
||||
cmpb (bp), #0x23 ! Next guide character is '#'?
|
||||
jne notlogical
|
||||
lea si, 1-lowsec(bp) ! Logical sector offset follows '#'
|
||||
notlogical:
|
||||
call load ! Load chosen sector of chosen disk
|
||||
cmpb (bp), #0x23
|
||||
je boot ! Run bootstrap if a logical is chosen
|
||||
|
||||
call print ! Intro to partition number
|
||||
.ascii "p?\b\0"
|
||||
|
||||
part:
|
||||
call getch ! Get character to tell partition
|
||||
call gettable ! Get partition table
|
||||
call sort ! Sort partition table
|
||||
call choose_load ! Compute chosen entry and load
|
||||
|
||||
cmpb sysind(si), #MINIX_PART ! Minix subpartition table possible?
|
||||
jne waitboot
|
||||
|
||||
call print ! Intro to slice number
|
||||
.ascii "s?\b\0"
|
||||
|
||||
slice:
|
||||
call getch ! Get character to tell slice
|
||||
call gettable ! Get partition table
|
||||
call choose_load ! Compute chosen entry and load
|
||||
|
||||
waitboot:
|
||||
call print ! Intro to nothing
|
||||
.ascii " ?\b\0"
|
||||
call getch ! Supposed to type RETURN now
|
||||
n0nboot:jmp nonboot ! Sorry, can't go further
|
||||
|
||||
! Get a character, either the patched-in, or one from the keyboard.
|
||||
getch:
|
||||
movb al, (bp) ! Get patched-in character
|
||||
testb al, al
|
||||
jz getkey
|
||||
inc bp
|
||||
jmp gotkey
|
||||
getkey: xorb ah, ah ! Wait for keypress
|
||||
int 0x16
|
||||
gotkey: testb dl, dl ! Ignore CR if disk number not yet set
|
||||
jns putch
|
||||
cmpb al, #0x0D ! Carriage return?
|
||||
je boot
|
||||
!jmp putch
|
||||
|
||||
! Print a character
|
||||
putch: movb ah, #0x0E ! Print character in teletype mode
|
||||
mov bx, #0x0001 ! Page 0, foreground color
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
! Print a message.
|
||||
print: mov cx, si ! Save si
|
||||
pop si ! si = String following 'call print'
|
||||
prnext: lodsb ! al = *si++ is char to be printed
|
||||
testb al, al ! Null marks end
|
||||
jz prdone
|
||||
call putch
|
||||
jmp prnext
|
||||
prdone: xchg si, cx ! Restore si
|
||||
jmp (cx) ! Continue after the string
|
||||
|
||||
! Return typed (or in patched data) means to run the bootstrap now in core!
|
||||
boot:
|
||||
call print ! Make line on screen look proper
|
||||
.ascii "\b \r\n\0"
|
||||
jmp LOADOFF-BUFFER ! Jump to LOADOFF
|
||||
|
||||
! Compute address of chosen partition entry from choice al into si, then
|
||||
! continue to load the boot sector of that partition.
|
||||
choose_load:
|
||||
subb al, #0x30 ! al -= '0'
|
||||
cmpb al, #4 ! Only four partitions
|
||||
ja n0nboot
|
||||
movb ah, #PENTRYSIZE
|
||||
mulb ah ! al *= PENTRYSIZE
|
||||
add ax, #BUFFER+PART_TABLE
|
||||
mov si, ax ! si = &part_table[al - '0']
|
||||
movb al, sysind(si) ! System indicator
|
||||
testb al, al ! Unused partition?
|
||||
jz n0nboot
|
||||
!jmp load ! Continue to load boot sector
|
||||
|
||||
! Load boot sector of the current partition.
|
||||
load:
|
||||
push dx ! Save drive code
|
||||
push es ! Next call sets es
|
||||
movb ah, #0x08 ! Code for drive parameters
|
||||
int 0x13
|
||||
pop es
|
||||
andb cl, #0x3F ! cl = max sector number (1-origin)
|
||||
incb dh ! dh = 1 + max head number (0-origin)
|
||||
movb al, cl ! al = cl = sectors per track
|
||||
mulb dh ! dh = heads, ax = heads * sectors
|
||||
mov bx, ax ! bx = sectors per cylinder = heads * sectors
|
||||
mov ax, lowsec+0(si)
|
||||
mov dx, lowsec+2(si) ! dx:ax = sector within drive
|
||||
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
|
||||
jae bigdisk
|
||||
div bx ! ax = cylinder, dx = sector within cylinder
|
||||
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
|
||||
movb ch, dl ! ch = low 8 bits of cylinder
|
||||
divb cl ! al = head, ah = sector (0-origin)
|
||||
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
|
||||
shr dx, #1
|
||||
shr dx, #1 ! dl[6..7] = high cylinder
|
||||
orb dl, ah ! dl[0..5] = sector (0-origin)
|
||||
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
|
||||
incb cl ! cl[0..5] = sector (1-origin)
|
||||
pop dx ! Restore drive code in dl
|
||||
movb dh, al ! dh = al = head
|
||||
mov bx, #LOADOFF ! es:bx = where sector is loaded
|
||||
mov ax, #0x0201 ! ah = Code for read / al = one sector
|
||||
int 0x13
|
||||
jmp rdeval ! Evaluate read result
|
||||
bigdisk:
|
||||
mov bx, dx ! bx:ax = dx:ax = sector to read
|
||||
pop dx ! Restore drive code in dl
|
||||
push si ! Save si
|
||||
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
|
||||
mov 8(si), ax ! Starting block number = bx:ax
|
||||
mov 10(si), bx
|
||||
movb ah, #0x42 ! Extended read
|
||||
int 0x13
|
||||
pop si ! Restore si to point to partition entry
|
||||
!jmp rdeval
|
||||
rdeval:
|
||||
jnc rdok
|
||||
rderr:
|
||||
call print
|
||||
.ascii "\r\nRead error\r\n\0"
|
||||
jmp again
|
||||
rdok:
|
||||
cmp LOADOFF+MAGIC, #0xAA55
|
||||
je sigok ! Signature ok?
|
||||
nonboot:
|
||||
call print
|
||||
.ascii "\r\nNot bootable\r\n\0"
|
||||
jmp again
|
||||
sigok:
|
||||
ret
|
||||
|
||||
! Get the partition table into my space.
|
||||
gettable:
|
||||
mov si, #LOADOFF+PART_TABLE
|
||||
mov di, #BUFFER+PART_TABLE
|
||||
mov cx, #4*PENTRYSIZE/2
|
||||
rep movs
|
||||
ret
|
||||
|
||||
! Sort the partition table.
|
||||
sort:
|
||||
mov cx, #4 ! Four times is enough to sort
|
||||
bubble: mov si, #BUFFER+PART_TABLE ! First table entry
|
||||
bubble1:lea di, PENTRYSIZE(si) ! Next entry
|
||||
cmpb sysind(si), ch ! Partition type, nonzero when in use
|
||||
jz exchg ! Unused entries sort to the end
|
||||
inuse: mov bx, lowsec+0(di)
|
||||
sub bx, lowsec+0(si) ! Compute di->lowsec - si->lowsec
|
||||
mov bx, lowsec+2(di)
|
||||
sbb bx, lowsec+2(si)
|
||||
jae order ! In order if si->lowsec <= di->lowsec
|
||||
exchg: movb bl, (si)
|
||||
xchgb bl, PENTRYSIZE(si) ! Exchange entries byte by byte
|
||||
movb (si), bl
|
||||
inc si
|
||||
cmp si, di
|
||||
jb exchg
|
||||
order: mov si, di
|
||||
cmp si, #BUFFER+PART_TABLE+3*PENTRYSIZE
|
||||
jb bubble1
|
||||
loop bubble
|
||||
ret
|
||||
|
||||
.data
|
||||
|
||||
! Extended read/write commands require a parameter packet.
|
||||
ext_rw:
|
||||
.data1 0x10 ! Length of extended r/w packet
|
||||
.data1 0 ! Reserved
|
||||
.data2 1 ! Blocks to transfer (just one)
|
||||
.data2 LOADOFF ! Buffer address offset
|
||||
.data2 0 ! Buffer address segment
|
||||
.data4 0 ! Starting block number low 32 bits (tbfi)
|
||||
zero: .data4 0 ! Starting block number high 32 bits
|
||||
|
||||
.align 2
|
||||
guide:
|
||||
! Guide characters and possibly a logical partition number patched here by
|
||||
! installboot, up to 6 bytes maximum.
|
|
@ -1,20 +0,0 @@
|
|||
# masterboot: MBR code, first to run, 16-bit mode
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
# XXX: Can only be built with ACK currently
|
||||
.include "${MINIXSRCDIR}/boot/minix.ack16.mk"
|
||||
AFLAGS+= -Was-ncc
|
||||
STRIPFLAG= -s
|
||||
|
||||
|
||||
PROG= masterboot
|
||||
|
||||
SRCS= masterboot.s
|
||||
|
||||
BINDIR= /usr/mdec
|
||||
MAN=
|
||||
|
||||
LIBC= # defined, to silence bsd.*.mk
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,218 +0,0 @@
|
|||
! masterboot 2.0 - Master boot block code Author: Kees J. Bot
|
||||
!
|
||||
! This code may be placed in the first sector (the boot sector) of a floppy,
|
||||
! hard disk or hard disk primary partition. There it will perform the
|
||||
! following actions at boot time:
|
||||
!
|
||||
! - If the booted device is a hard disk and one of the partitions is active
|
||||
! then the active partition is booted.
|
||||
!
|
||||
! - Otherwise the next floppy or hard disk device is booted, trying them one
|
||||
! by one.
|
||||
!
|
||||
! To make things a little clearer, the boot path might be:
|
||||
! /dev/fd0 - Floppy disk containing data, tries fd1 then d0
|
||||
! [/dev/fd1] - Drive empty
|
||||
! /dev/c0d0 - Master boot block, selects active partition 2
|
||||
! /dev/c0d0p2 - Submaster, selects active subpartition 0
|
||||
! /dev/c0d0p2s0 - Minix bootblock, reads Boot Monitor /boot
|
||||
! Minix - Started by /boot from a kernel image in /minix
|
||||
|
||||
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
|
||||
BUFFER = 0x0600 ! First free memory
|
||||
PART_TABLE = 446 ! Location of partition table within this code
|
||||
PENTRYSIZE = 16 ! Size of one partition table entry
|
||||
MAGIC = 510 ! Location of the AA55 magic number
|
||||
|
||||
! <ibm/partition>.h:
|
||||
bootind = 0
|
||||
sysind = 4
|
||||
lowsec = 8
|
||||
|
||||
|
||||
.text
|
||||
|
||||
! Find active (sub)partition, load its first sector, run it.
|
||||
|
||||
master:
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
cli
|
||||
mov ss, ax ! ds = es = ss = Vector segment
|
||||
mov sp, #LOADOFF
|
||||
sti
|
||||
|
||||
! Copy this code to safety, then jump to it.
|
||||
mov si, sp ! si = start of this code
|
||||
push si ! Also where we'll return to eventually
|
||||
mov di, #BUFFER ! Buffer area
|
||||
mov cx, #512/2 ! One sector
|
||||
cld
|
||||
rep movs
|
||||
jmpf BUFFER+migrate, 0 ! To safety
|
||||
migrate:
|
||||
|
||||
! Find the active partition
|
||||
findactive:
|
||||
testb dl, dl
|
||||
jns nextdisk ! No bootable partitions on floppies
|
||||
mov si, #BUFFER+PART_TABLE
|
||||
find: cmpb sysind(si), #0 ! Partition type, nonzero when in use
|
||||
jz nextpart
|
||||
testb bootind(si), #0x80 ! Active partition flag in bit 7
|
||||
jz nextpart ! It's not active
|
||||
loadpart:
|
||||
call load ! Load partition bootstrap
|
||||
jc error1 ! Not supposed to fail
|
||||
bootstrap:
|
||||
ret ! Jump to the master bootstrap
|
||||
nextpart:
|
||||
add si, #PENTRYSIZE
|
||||
cmp si, #BUFFER+PART_TABLE+4*PENTRYSIZE
|
||||
jb find
|
||||
! No active partition, tell 'em
|
||||
call print
|
||||
.ascii "No active partition\0"
|
||||
jmp reboot
|
||||
|
||||
! There are no active partitions on this drive, try the next drive.
|
||||
nextdisk:
|
||||
incb dl ! Increment dl for the next drive
|
||||
testb dl, dl
|
||||
js nexthd ! Hard disk if negative
|
||||
int 0x11 ! Get equipment configuration
|
||||
shl ax, #1 ! Highest floppy drive # in bits 6-7
|
||||
shl ax, #1 ! Now in bits 0-1 of ah
|
||||
andb ah, #0x03 ! Extract bits
|
||||
cmpb dl, ah ! Must be dl <= ah for drive to exist
|
||||
ja nextdisk ! Otherwise try disk 0 eventually
|
||||
call load0 ! Read the next floppy bootstrap
|
||||
jc nextdisk ! It failed, next disk please
|
||||
ret ! Jump to the next master bootstrap
|
||||
nexthd: call load0 ! Read the hard disk bootstrap
|
||||
error1: jc error ! No disk?
|
||||
ret
|
||||
|
||||
|
||||
! Load sector 0 from the current device. It's either a floppy bootstrap or
|
||||
! a hard disk master bootstrap.
|
||||
load0:
|
||||
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
|
||||
!jmp load
|
||||
|
||||
! Load sector lowsec(si) from the current device. The obvious head, sector,
|
||||
! and cylinder numbers are ignored in favour of the more trustworthy absolute
|
||||
! start of partition.
|
||||
load:
|
||||
mov di, #3 ! Three retries for floppy spinup
|
||||
retry: push dx ! Save drive code
|
||||
push es
|
||||
push di ! Next call destroys es and di
|
||||
movb ah, #0x08 ! Code for drive parameters
|
||||
int 0x13
|
||||
pop di
|
||||
pop es
|
||||
andb cl, #0x3F ! cl = max sector number (1-origin)
|
||||
incb dh ! dh = 1 + max head number (0-origin)
|
||||
movb al, cl ! al = cl = sectors per track
|
||||
mulb dh ! dh = heads, ax = heads * sectors
|
||||
mov bx, ax ! bx = sectors per cylinder = heads * sectors
|
||||
mov ax, lowsec+0(si)
|
||||
mov dx, lowsec+2(si)! dx:ax = sector within drive
|
||||
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
|
||||
jae bigdisk
|
||||
div bx ! ax = cylinder, dx = sector within cylinder
|
||||
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
|
||||
movb ch, dl ! ch = low 8 bits of cylinder
|
||||
divb cl ! al = head, ah = sector (0-origin)
|
||||
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
|
||||
shr dx, #1
|
||||
shr dx, #1 ! dl[6..7] = high cylinder
|
||||
orb dl, ah ! dl[0..5] = sector (0-origin)
|
||||
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
|
||||
incb cl ! cl[0..5] = sector (1-origin)
|
||||
pop dx ! Restore drive code in dl
|
||||
movb dh, al ! dh = al = head
|
||||
mov bx, #LOADOFF ! es:bx = where sector is loaded
|
||||
mov ax, #0x0201 ! Code for read, just one sector
|
||||
int 0x13 ! Call the BIOS for a read
|
||||
jmp rdeval ! Evaluate read result
|
||||
bigdisk:
|
||||
mov bx, dx ! bx:ax = dx:ax = sector to read
|
||||
pop dx ! Restore drive code in dl
|
||||
push si ! Save si
|
||||
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
|
||||
mov 8(si), ax ! Starting block number = bx:ax
|
||||
mov 10(si), bx
|
||||
movb ah, #0x42 ! Extended read
|
||||
int 0x13
|
||||
pop si ! Restore si to point to partition entry
|
||||
!jmp rdeval
|
||||
rdeval:
|
||||
jnc rdok ! Read succeeded
|
||||
cmpb ah, #0x80 ! Disk timed out? (Floppy drive empty)
|
||||
je rdbad
|
||||
dec di
|
||||
jl rdbad ! Retry count expired
|
||||
xorb ah, ah
|
||||
int 0x13 ! Reset
|
||||
jnc retry ! Try again
|
||||
rdbad: stc ! Set carry flag
|
||||
ret
|
||||
rdok: cmp LOADOFF+MAGIC, #0xAA55
|
||||
jne nosig ! Error if signature wrong
|
||||
ret ! Return with carry still clear
|
||||
nosig: call print
|
||||
.ascii "Not bootable\0"
|
||||
jmp reboot
|
||||
|
||||
! A read error occurred, complain and hang
|
||||
error:
|
||||
mov si, #LOADOFF+errno+1
|
||||
prnum: movb al, ah ! Error number in ah
|
||||
andb al, #0x0F ! Low 4 bits
|
||||
cmpb al, #10 ! A-F?
|
||||
jb digit ! 0-9!
|
||||
addb al, #7 ! 'A' - ':'
|
||||
digit: addb (si), al ! Modify '0' in string
|
||||
dec si
|
||||
movb cl, #4 ! Next 4 bits
|
||||
shrb ah, cl
|
||||
jnz prnum ! Again if digit > 0
|
||||
call print
|
||||
.ascii "Read error "
|
||||
errno: .ascii "00\0"
|
||||
!jmp reboot
|
||||
|
||||
reboot:
|
||||
call print
|
||||
.ascii ". Hit any key to reboot.\0"
|
||||
xorb ah, ah ! Wait for keypress
|
||||
int 0x16
|
||||
call print
|
||||
.ascii "\r\n\0"
|
||||
int 0x19
|
||||
|
||||
! Print a message.
|
||||
print: pop si ! si = String following 'call print'
|
||||
prnext: lodsb ! al = *si++ is char to be printed
|
||||
testb al, al ! Null marks end
|
||||
jz prdone
|
||||
movb ah, #0x0E ! Print character in teletype mode
|
||||
mov bx, #0x0001 ! Page 0, foreground color
|
||||
int 0x10
|
||||
jmp prnext
|
||||
prdone: jmp (si) ! Continue after the string
|
||||
|
||||
.data
|
||||
|
||||
! Extended read/write commands require a parameter packet.
|
||||
ext_rw:
|
||||
.data1 0x10 ! Length of extended r/w packet
|
||||
.data1 0 ! Reserved
|
||||
.data2 1 ! Blocks to transfer (just one)
|
||||
.data2 LOADOFF ! Buffer address offset
|
||||
.data2 0 ! Buffer address segment
|
||||
.data4 0 ! Starting block number low 32 bits (tbfi)
|
||||
zero: .data4 0 ! Starting block number high 32 bits
|
|
@ -1,12 +0,0 @@
|
|||
# Makefile fragment to use Ack compiler (16-bit i86 target)
|
||||
ARCH= i86
|
||||
LIBDIR= /usr/lib/i86 # force
|
||||
|
||||
CC:=${CC:C/.*[gp]cc/cc/:C/clang/cc/}
|
||||
AR=aal
|
||||
COMPILER_TYPE=ack
|
||||
OBJECT_FMT=a.out
|
||||
CPPFLAGS+= -mi86
|
||||
AFLAGS+= -mi86
|
||||
LDFLAGS+= -mi86 -.o $(MINIXID) # no crtso
|
||||
MINIXID?= -com # common I+D default
|
313
boot/rawfs.c
313
boot/rawfs.c
|
@ -1,313 +0,0 @@
|
|||
/* rawfs.c - Raw Minix file system support. Author: Kees J. Bot
|
||||
* 23 Dec 1991
|
||||
* Based on readfs by Paul Polderman
|
||||
*/
|
||||
#define _POSIX_SOURCE 1
|
||||
#define _MINIX 1
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/type.h>
|
||||
#include <servers/mfs/const.h>
|
||||
#include <servers/mfs/type.h>
|
||||
#include <servers/mfs/super.h>
|
||||
#include <servers/mfs/inode.h>
|
||||
#include "rawfs.h"
|
||||
#include <servers/mfs/buf.h>
|
||||
|
||||
void readblock(off_t blockno, char *buf, int);
|
||||
|
||||
/* The following code handles two file system types: Version 1 with small
|
||||
* inodes and 16-bit disk addresses and Version 2 with big inodes and 32-bit
|
||||
* disk addresses.
|
||||
#ifdef FLEX
|
||||
* To make matters worse, Minix-vmd knows about the normal Unix Version 7
|
||||
* directories and directories with flexible entries.
|
||||
#endif
|
||||
*/
|
||||
|
||||
/* File system parameters. */
|
||||
static unsigned nr_dzones; /* Fill these in after reading superblock. */
|
||||
static unsigned nr_indirects;
|
||||
static unsigned inodes_per_block;
|
||||
static int block_size;
|
||||
|
||||
#if __minix_vmd
|
||||
static struct v12_super_block super; /* Superblock of file system */
|
||||
#define s_log_zone_size s_dummy /* Zones are obsolete. */
|
||||
#else
|
||||
static struct super_block super; /* Superblock of file system */
|
||||
#define SUPER_V1 SUPER_MAGIC /* V1 magic has a weird name. */
|
||||
#endif
|
||||
|
||||
static struct inode curfil; /* Inode of file under examination */
|
||||
static char indir[_MAX_BLOCK_SIZE]; /* Single indirect block. */
|
||||
static char dindir[_MAX_BLOCK_SIZE]; /* Double indirect block. */
|
||||
static char dirbuf[_MAX_BLOCK_SIZE]; /* Scratch/Directory block. */
|
||||
#define scratch dirbuf
|
||||
|
||||
static block_t a_indir, a_dindir; /* Addresses of the indirects. */
|
||||
static off_t dirpos; /* Reading pos in a dir. */
|
||||
|
||||
#define fsbuf(b) (* (union fsdata_u *) (b))
|
||||
|
||||
#define zone_shift (super.s_log_zone_size) /* zone to block ratio */
|
||||
|
||||
off_t r_super(int *bs)
|
||||
/* Initialize variables, return size of file system in blocks,
|
||||
* (zero on error).
|
||||
*/
|
||||
{
|
||||
/* Read superblock. (The superblock is always at 1kB offset,
|
||||
* that's why we lie to readblock and say the block size is 1024
|
||||
* and we want block number 1 (the 'second block', at offset 1kB).)
|
||||
*/
|
||||
readblock(1, scratch, 1024);
|
||||
|
||||
memcpy(&super, scratch, sizeof(super));
|
||||
|
||||
/* Is it really a MINIX file system ? */
|
||||
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
|
||||
if(super.s_magic == SUPER_V2)
|
||||
super.s_block_size = 1024;
|
||||
*bs = block_size = super.s_block_size;
|
||||
if(block_size < _MIN_BLOCK_SIZE ||
|
||||
block_size > _MAX_BLOCK_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
nr_dzones= V2_NR_DZONES;
|
||||
nr_indirects= V2_INDIRECTS(block_size);
|
||||
inodes_per_block= V2_INODES_PER_BLOCK(block_size);
|
||||
return (off_t) super.s_zones << zone_shift;
|
||||
} else
|
||||
if (super.s_magic == SUPER_V1) {
|
||||
*bs = block_size = 1024;
|
||||
nr_dzones= V1_NR_DZONES;
|
||||
nr_indirects= V1_INDIRECTS;
|
||||
inodes_per_block= V1_INODES_PER_BLOCK;
|
||||
return (off_t) super.s_nzones << zone_shift;
|
||||
} else {
|
||||
/* Filesystem not recognized as Minix. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void r_stat(Ino_t inum, struct stat *stp)
|
||||
/* Return information about a file like stat(2) and remember it. */
|
||||
{
|
||||
block_t block;
|
||||
block_t ino_block;
|
||||
ino_t ino_offset;
|
||||
union fsdata_u *blockbuf;
|
||||
|
||||
/* Calculate start of i-list */
|
||||
block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks;
|
||||
|
||||
/* Calculate block with inode inum */
|
||||
ino_block = ((inum - 1) / inodes_per_block);
|
||||
ino_offset = ((inum - 1) % inodes_per_block);
|
||||
block += ino_block;
|
||||
|
||||
/* Fetch the block */
|
||||
blockbuf = (union fsdata_u *) scratch;
|
||||
readblock(block, (char *) blockbuf, block_size);
|
||||
|
||||
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
|
||||
d2_inode *dip;
|
||||
int i;
|
||||
|
||||
dip= &blockbuf->b__v2_ino[(unsigned int) ino_offset];
|
||||
|
||||
curfil.i_mode= dip->d2_mode;
|
||||
curfil.i_nlinks= dip->d2_nlinks;
|
||||
curfil.i_uid= dip->d2_uid;
|
||||
curfil.i_gid= dip->d2_gid;
|
||||
curfil.i_size= dip->d2_size;
|
||||
curfil.i_atime= dip->d2_atime;
|
||||
curfil.i_mtime= dip->d2_mtime;
|
||||
curfil.i_ctime= dip->d2_ctime;
|
||||
for (i= 0; i < V2_NR_TZONES; i++)
|
||||
curfil.i_zone[i]= dip->d2_zone[i];
|
||||
} else {
|
||||
d1_inode *dip;
|
||||
int i;
|
||||
|
||||
dip= &blockbuf->b__v1_ino[(unsigned int) ino_offset];
|
||||
|
||||
curfil.i_mode= dip->d1_mode;
|
||||
curfil.i_nlinks= dip->d1_nlinks;
|
||||
curfil.i_uid= dip->d1_uid;
|
||||
curfil.i_gid= dip->d1_gid;
|
||||
curfil.i_size= dip->d1_size;
|
||||
curfil.i_atime= dip->d1_mtime;
|
||||
curfil.i_mtime= dip->d1_mtime;
|
||||
curfil.i_ctime= dip->d1_mtime;
|
||||
for (i= 0; i < V1_NR_TZONES; i++)
|
||||
curfil.i_zone[i]= dip->d1_zone[i];
|
||||
}
|
||||
curfil.i_dev= -1; /* Can't fill this in alas. */
|
||||
curfil.i_num= inum;
|
||||
|
||||
stp->st_dev= curfil.i_dev;
|
||||
stp->st_ino= curfil.i_num;
|
||||
stp->st_mode= curfil.i_mode;
|
||||
stp->st_nlink= curfil.i_nlinks;
|
||||
stp->st_uid= curfil.i_uid;
|
||||
stp->st_gid= curfil.i_gid;
|
||||
stp->st_rdev= (dev_t) curfil.i_zone[0];
|
||||
stp->st_size= curfil.i_size;
|
||||
stp->st_atime= curfil.i_atime;
|
||||
stp->st_mtime= curfil.i_mtime;
|
||||
stp->st_ctime= curfil.i_ctime;
|
||||
|
||||
a_indir= a_dindir= 0;
|
||||
dirpos= 0;
|
||||
}
|
||||
|
||||
ino_t r_readdir(char *name)
|
||||
/* Read next directory entry at "dirpos" from file "curfil". */
|
||||
{
|
||||
ino_t inum= 0;
|
||||
int blkpos;
|
||||
struct direct *dp;
|
||||
|
||||
if (!S_ISDIR(curfil.i_mode)) { errno= ENOTDIR; return -1; }
|
||||
|
||||
if(!block_size) { errno = 0; return -1; }
|
||||
|
||||
while (inum == 0 && dirpos < curfil.i_size) {
|
||||
if ((blkpos= (int) (dirpos % block_size)) == 0) {
|
||||
/* Need to fetch a new directory block. */
|
||||
|
||||
readblock(r_vir2abs(dirpos / block_size), dirbuf, block_size);
|
||||
}
|
||||
/* Let dp point to the next entry. */
|
||||
dp= (struct direct *) (dirbuf + blkpos);
|
||||
|
||||
if ((inum= dp->mfs_d_ino) != 0) {
|
||||
/* This entry is occupied, return name. */
|
||||
strncpy(name, dp->mfs_d_name, sizeof(dp->mfs_d_name));
|
||||
name[sizeof(dp->mfs_d_name)]= 0;
|
||||
}
|
||||
dirpos+= DIR_ENTRY_SIZE;
|
||||
}
|
||||
return inum;
|
||||
}
|
||||
|
||||
off_t r_vir2abs(off_t virblk)
|
||||
/* Translate a block number in a file to an absolute disk block number.
|
||||
* Returns 0 for a hole and -1 if block is past end of file.
|
||||
*/
|
||||
{
|
||||
block_t b= virblk;
|
||||
zone_t zone, ind_zone;
|
||||
block_t z, zone_index;
|
||||
int i;
|
||||
|
||||
if(!block_size) return -1;
|
||||
|
||||
/* Check if virblk within file. */
|
||||
if (virblk * block_size >= curfil.i_size) return -1;
|
||||
|
||||
/* Calculate zone in which the datablock number is contained */
|
||||
zone = (zone_t) (b >> zone_shift);
|
||||
|
||||
/* Calculate index of the block number in the zone */
|
||||
zone_index = b - ((block_t) zone << zone_shift);
|
||||
|
||||
/* Go get the zone */
|
||||
if (zone < (zone_t) nr_dzones) { /* direct block */
|
||||
zone = curfil.i_zone[(int) zone];
|
||||
z = ((block_t) zone << zone_shift) + zone_index;
|
||||
return z;
|
||||
}
|
||||
|
||||
/* The zone is not a direct one */
|
||||
zone -= (zone_t) nr_dzones;
|
||||
|
||||
/* Is it single indirect ? */
|
||||
if (zone < (zone_t) nr_indirects) { /* single indirect block */
|
||||
ind_zone = curfil.i_zone[nr_dzones];
|
||||
} else { /* double indirect block */
|
||||
/* Fetch the double indirect block */
|
||||
if ((ind_zone = curfil.i_zone[nr_dzones + 1]) == 0) return 0;
|
||||
|
||||
z = (block_t) ind_zone << zone_shift;
|
||||
if (a_dindir != z) {
|
||||
readblock(z, dindir, block_size);
|
||||
a_dindir= z;
|
||||
}
|
||||
/* Extract the indirect zone number from it */
|
||||
zone -= (zone_t) nr_indirects;
|
||||
|
||||
i = zone / (zone_t) nr_indirects;
|
||||
ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
|
||||
? fsbuf(dindir).b__v2_ind[i]
|
||||
: fsbuf(dindir).b__v1_ind[i];
|
||||
zone %= (zone_t) nr_indirects;
|
||||
}
|
||||
if (ind_zone == 0) return 0;
|
||||
|
||||
/* Extract the datablock number from the indirect zone */
|
||||
z = (block_t) ind_zone << zone_shift;
|
||||
if (a_indir != z) {
|
||||
readblock(z, indir, block_size);
|
||||
a_indir= z;
|
||||
}
|
||||
zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
|
||||
? fsbuf(indir).b__v2_ind[(int) zone]
|
||||
: fsbuf(indir).b__v1_ind[(int) zone];
|
||||
|
||||
/* Calculate absolute datablock number */
|
||||
z = ((block_t) zone << zone_shift) + zone_index;
|
||||
return z;
|
||||
}
|
||||
|
||||
ino_t r_lookup(Ino_t cwd, const char *path)
|
||||
/* Translates a pathname to an inode number. This is just a nice utility
|
||||
* function, it only needs r_stat and r_readdir.
|
||||
*/
|
||||
{
|
||||
char name[MFS_DIRSIZ+1], r_name[MFS_DIRSIZ+1];
|
||||
char *n;
|
||||
struct stat st;
|
||||
ino_t ino;
|
||||
|
||||
ino= path[0] == '/' ? ROOT_INO : cwd;
|
||||
|
||||
for (;;) {
|
||||
if (ino == 0) {
|
||||
errno= ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*path == '/') path++;
|
||||
|
||||
if (*path == 0) return ino;
|
||||
|
||||
r_stat(ino, &st);
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
errno= ENOTDIR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
n= name;
|
||||
while (*path != 0 && *path != '/')
|
||||
if (n < name + MFS_DIRSIZ) *n++ = *path++;
|
||||
*n= 0;
|
||||
|
||||
while ((ino= r_readdir(r_name)) != 0
|
||||
&& strcmp(name, r_name) != 0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: rawfs.c,v 1.8 1999/11/05 23:14:15 philip Exp $
|
||||
*/
|
51
boot/rawfs.h
51
boot/rawfs.h
|
@ -1,51 +0,0 @@
|
|||
/* rawfs.h - Raw Minix file system support. Author: Kees J. Bot
|
||||
*
|
||||
* off_t r_super(int *block_size);
|
||||
* Initialize variables, returns the size of a valid Minix
|
||||
* file system blocks, but zero on error.
|
||||
*
|
||||
* void r_stat(ino_t file, struct stat *stp);
|
||||
* Return information about a file like stat(2) and
|
||||
* remembers file for the next two calls.
|
||||
*
|
||||
* off_t r_vir2abs(off_t virblockno);
|
||||
* Translate virtual block number in file to absolute
|
||||
* disk block number. Returns 0 if the file contains
|
||||
* a hole, or -1 if the block lies past the end of file.
|
||||
*
|
||||
* ino_t r_readdir(char *name);
|
||||
* Return next directory entry or 0 if there are no more.
|
||||
* Returns -1 and sets errno on error.
|
||||
*
|
||||
* ino_t r_lookup(ino_t cwd, const char *path);
|
||||
* A utility function that translates a pathname to an
|
||||
* inode number. It starts from directory "cwd" unless
|
||||
* path starts with a '/', then from ROOT_INO.
|
||||
* Returns 0 and sets errno on error.
|
||||
*
|
||||
* One function needs to be provided by the outside world:
|
||||
*
|
||||
* void readblock(off_t blockno, char *buf, int block_size);
|
||||
* Read a block into the buffer. Outside world handles
|
||||
* errors.
|
||||
*/
|
||||
|
||||
#ifndef INC_RAWFS_H
|
||||
#define INC_RAWFS_H
|
||||
|
||||
#include <minix/dirent.h>
|
||||
#include <servers/mfs/mfsdir.h>
|
||||
|
||||
#define ROOT_INO ((ino_t) 1) /* Inode nr of root dir. */
|
||||
|
||||
extern off_t r_super(int *);
|
||||
extern void r_stat(Ino_t file, struct stat *stp);
|
||||
extern off_t r_vir2abs(off_t virblockno);
|
||||
extern ino_t r_readdir(char *name);
|
||||
extern ino_t r_lookup(Ino_t cwd, const char *path);
|
||||
|
||||
/*
|
||||
* $PchId: rawfs.h,v 1.4 1996/04/19 08:16:36 philip Exp $
|
||||
*/
|
||||
|
||||
#endif
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
MDEC=/usr/mdec
|
||||
BOOT=/boot/boot
|
||||
ROOT=`printroot -r`
|
||||
|
||||
if [ ! -b "$ROOT" ]
|
||||
then echo root device $ROOT not found
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -n "Install boot as $BOOT on current root and patch into $ROOT? (y/N) "
|
||||
read ans
|
||||
|
||||
if [ ! "$ans" = y ]
|
||||
then echo Aborting.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
make install || true
|
||||
|
||||
echo Installing boot monitor into $BOOT.
|
||||
cp $MDEC/boot $BOOT
|
||||
|
||||
echo Patching position of $BOOT into $ROOT.
|
||||
installboot_minix -d "$ROOT" $MDEC/bootblock $BOOT
|
||||
sync
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# M, U - mount or unmount standard devices.
|
||||
|
||||
case $#:$2 in
|
||||
1:|2:-r) ;;
|
||||
*) echo "Usage: $0 <abbreviation> [-r]" >&2; exit 1
|
||||
esac
|
||||
|
||||
. /etc/fstab
|
||||
|
||||
dev=$1 dir=$1
|
||||
|
||||
case $1 in
|
||||
0) dev=/dev/fd0 dir=fd0 ;;
|
||||
1) dev=/dev/fd1 dir=fd1 ;;
|
||||
PS0|at0|fd0|pat0|pc0|ps0) dev=/dev/$dev dir=fd0 ;;
|
||||
PS1|at1|fd1|pat1|pc1|ps1) dev=/dev/$dev dir=fd1 ;;
|
||||
root) dev=$root ;;
|
||||
tmp) dev=$tmp ;;
|
||||
usr) dev=$usr ;;
|
||||
*) dev=/dev/$dev dir=mnt
|
||||
esac
|
||||
|
||||
case $0 in
|
||||
*M) mount $dev /$dir $2 ;;
|
||||
*U) umount $dev
|
||||
esac
|
|
@ -1,7 +0,0 @@
|
|||
SCRIPTS= M.sh
|
||||
BINDIR= /bin
|
||||
MAN=
|
||||
|
||||
LINKS+= ${BINDIR}/M ${BINDIR}/U
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -2,22 +2,22 @@
|
|||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= aal add_route arp ash at autil awk \
|
||||
backup badblocks banner basename binpackage \
|
||||
binpackages btrace cal calendar \
|
||||
cat cawf cd cdprobe checkhier chmem \
|
||||
SUBDIR= add_route arp ash at autil awk \
|
||||
backup badblocks banner basename \
|
||||
btrace cal calendar \
|
||||
cat cawf cd cdprobe checkhier \
|
||||
chmod chown chroot ci cksum cleantmp clear cmp co \
|
||||
comm compress cp crc cron crontab cut date \
|
||||
comm compress cp crc cron crontab cut \
|
||||
dd decomp16 DESCRIBE dev2name devsize df dhcpd \
|
||||
dhrystone diff dirname dis386 dis88 diskctl du dumpcore \
|
||||
dhrystone diff dirname diskctl du dumpcore \
|
||||
ed eject elle elvis env expand factor fbdctl file \
|
||||
find finger fingerd fix fold format fortune fsck.mfs \
|
||||
ftp101 gcore gcov-pull getty grep head hexdump host \
|
||||
hostaddr id ifconfig ifdef install \
|
||||
intr ipcrm ipcs irdpd isoread join kill last leave \
|
||||
less lex loadkeys loadramdisk logger login look lp \
|
||||
lpd ls lspci M mail make MAKEDEV \
|
||||
mdb mesg mined ackmkdep mkfifo mkfs.mfs mknod \
|
||||
lpd ls lspci mail make MAKEDEV \
|
||||
mdb mesg mined mkfifo mkfs.mfs mknod \
|
||||
mkproto modem mount mt netconf newroot nice acknm nohup \
|
||||
nonamed od paste patch pax \
|
||||
ping postinstall poweroff pr prep printf printroot \
|
||||
|
@ -25,7 +25,7 @@ SUBDIR= aal add_route arp ash at autil awk \
|
|||
ramdisk rarpd rawspeed rcp rdate readall readclock \
|
||||
reboot remsync rev rget rlogin rlogind \
|
||||
rotate rsh rshd sed service setup shar acksize \
|
||||
sleep slip sort spell split srccrc ackstrip \
|
||||
sleep slip sort spell split srccrc \
|
||||
stty su sum svclog swifi sync synctree sysenv \
|
||||
syslogd tail tar tcpd tcpdp tcpstat tee telnet \
|
||||
telnetd term termcap tget time touch tr \
|
||||
|
@ -35,15 +35,10 @@ SUBDIR= aal add_route arp ash at autil awk \
|
|||
xargs yacc yes zdump zmodem pkgin_cd \
|
||||
mktemp worldstone
|
||||
|
||||
.if ${COMPILER_TYPE} == "gnu"
|
||||
SUBDIR += elf2aout
|
||||
.endif
|
||||
|
||||
.if ${ARCH} == "i386"
|
||||
SUBDIR+= atnormalize dosread fdisk loadfont \
|
||||
autopart part partition playwave postmort \
|
||||
recwave repartition screendump padtext
|
||||
SUBDIR+= acd asmconv gas2ack
|
||||
autopart part partition playwave \
|
||||
recwave repartition screendump
|
||||
.endif
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
# Any of the commands can force the new libc being used by
|
||||
# setting NEED_NBSDLIBC
|
||||
.if defined(NEED_NBSDLIBC)
|
||||
.include <minix.newlibc.mk>
|
||||
.endif
|
||||
|
||||
.if (${NBSD_LIBC} != "no")
|
||||
CPPFLAGS+= -D_MINIX -D_NETBSD_SOURCE -D_MINIX_COMPAT
|
||||
LDADD+= -lminlib -lcompat_minix -lasyn -lterminfo
|
||||
.else
|
||||
CPPFLAGS+= -D_MINIX -D_POSIX_SOURCE
|
||||
.endif
|
||||
|
||||
BINDIR?=/usr/bin
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# Makefile for aal
|
||||
|
||||
PROG= aal
|
||||
SRCS= archiver.c print.c rd.c rd_arhdr.c rd_unsig2.c sprint.c \
|
||||
wr_arhdr.c wr_bytes.c wr_int2.c wr_long.c wr_ranlib.c \
|
||||
format.c rd_bytes.c system.c write.c long2str.c
|
||||
CPPFLAGS+= -I${.CURDIR} -DAAL -DSTB -DNDEBUG -DDISTRIBUTION
|
||||
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,28 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_H_INCLUDED
|
||||
#define __ARCH_H_INCLUDED
|
||||
|
||||
#define ARMAG 0177545
|
||||
#define AALMAG 0177454
|
||||
|
||||
struct ar_hdr {
|
||||
char ar_name[14];
|
||||
long ar_date;
|
||||
char ar_uid;
|
||||
char ar_gid;
|
||||
short ar_mode;
|
||||
long ar_size;
|
||||
};
|
||||
|
||||
#define AR_TOTAL 26
|
||||
#define AR_SIZE 22
|
||||
|
||||
extern int rd_arhdr(int fd, register struct ar_hdr arhdr[]);
|
||||
extern void wr_arhdr(int fd, struct ar_hdr arhdr[]);
|
||||
|
||||
#endif /* __ARCH_H_INCLUDED */
|
|
@ -1,816 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* ar - archiver Author: Michiel Huisjes */
|
||||
/* Made into arch/aal by Ceriel Jacobs
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "rd.h"
|
||||
#include "wr_bytes.h"
|
||||
#include "wr_long.h"
|
||||
#include "wr_int2.h"
|
||||
#include "arch.h"
|
||||
#include "archiver.h"
|
||||
#include "print.h"
|
||||
|
||||
static char RcsId[] = "$Header$";
|
||||
|
||||
/*
|
||||
* Usage: [arch|aal] [adprtvx] archive [file] ...
|
||||
* v: verbose
|
||||
* x: extract
|
||||
* a: append
|
||||
* r: replace (append when not in archive)
|
||||
* d: delete
|
||||
* t: print contents of archive
|
||||
* p: print named files
|
||||
* l: temporaries in current directory instead of /usr/tmp
|
||||
* c: don't give "create" message
|
||||
* u: replace only if dated later than member in archive
|
||||
#ifdef DISTRIBUTION
|
||||
* D: make distribution: use distr_time, uid=2, gid=2, mode=0644
|
||||
#endif
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __NBSD_LIBC
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifndef S_IREAD
|
||||
#define S_IREAD S_IRUSR
|
||||
#endif
|
||||
#ifndef S_IWRITE
|
||||
#define S_IWRITE S_IWUSR
|
||||
#endif
|
||||
#ifndef S_IEXEC
|
||||
#define S_IEXEC S_IXUSR
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <arch.h>
|
||||
#ifdef AAL
|
||||
#include <ranlib.h>
|
||||
#include <out.h>
|
||||
#define MAGIC_NUMBER AALMAG
|
||||
long offset;
|
||||
struct ranlib *tab;
|
||||
unsigned int tnum = 0;
|
||||
char *tstrtab;
|
||||
unsigned int tssiz = 0;
|
||||
long time();
|
||||
unsigned int tabsz, strtabsz;
|
||||
#else
|
||||
#define MAGIC_NUMBER ARMAG
|
||||
#endif
|
||||
long lseek();
|
||||
|
||||
#define odd(nr) (nr & 01)
|
||||
#define even(nr) (odd(nr) ? nr + 1 : nr)
|
||||
|
||||
typedef char BOOL;
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#define READ 0
|
||||
#define APPEND 2
|
||||
#define CREATE 1
|
||||
|
||||
#define MEMBER struct ar_hdr
|
||||
|
||||
#define IO_SIZE (10 * 1024)
|
||||
|
||||
#define equal(str1, str2) (!strncmp((str1), (str2), 14))
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(m) (m & S_IFDIR) /* is a directory */
|
||||
#endif
|
||||
|
||||
BOOL verbose;
|
||||
BOOL app_fl;
|
||||
BOOL ex_fl;
|
||||
BOOL show_fl;
|
||||
BOOL pr_fl;
|
||||
BOOL rep_fl;
|
||||
BOOL del_fl;
|
||||
BOOL nocr_fl;
|
||||
BOOL local_fl;
|
||||
BOOL update_fl;
|
||||
#ifdef DISTRIBUTION
|
||||
BOOL distr_fl;
|
||||
long distr_time;
|
||||
#endif
|
||||
|
||||
int ar_fd;
|
||||
|
||||
char io_buffer[IO_SIZE];
|
||||
|
||||
char *progname;
|
||||
|
||||
char temp_buf[32];
|
||||
char *temp_arch = &temp_buf[0];
|
||||
extern char *mktemp();
|
||||
extern char *ctime();
|
||||
|
||||
/* Forward declarations. */
|
||||
static void enter_name(struct outname *namep);
|
||||
static void do_names(struct outhead *headp);
|
||||
static void do_object(int f, long size);
|
||||
static void show(char *s, char *name);
|
||||
static void write_symdef(void);
|
||||
static void mwrite(int fd, char *address, int bytes);
|
||||
static void extract(register MEMBER *member);
|
||||
static void copy_member(MEMBER *member, int from, int to, int extracting);
|
||||
static void add(char *name, int fd, char *mess);
|
||||
static void get(int argc, char *argv[]);
|
||||
|
||||
/*VARARGS2*/
|
||||
void error1(BOOL quit, char *str1)
|
||||
{
|
||||
fputs(str1,stderr);
|
||||
if (quit) {
|
||||
unlink(temp_arch);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void error2(BOOL quit, char *str1, char *str2)
|
||||
{
|
||||
fprintf(stderr,str1,str2);
|
||||
if (quit) {
|
||||
unlink(temp_arch);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void error3(BOOL quit, char *str1, char *str2, char *str3)
|
||||
{
|
||||
fprintf(stderr,str1,str2,str3);
|
||||
if (quit) {
|
||||
unlink(temp_arch);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
error3(TRUE, "usage: %s %s archive [file] ...\n",
|
||||
progname,
|
||||
#ifdef AAL
|
||||
"[acdrtxvlu]"
|
||||
#else
|
||||
"[acdprtxvlu]"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
char *basename(char *path)
|
||||
{
|
||||
register char *ptr = path;
|
||||
register char *last = NULL;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (*ptr == '/')
|
||||
last = ptr;
|
||||
ptr++;
|
||||
}
|
||||
if (last == NULL)
|
||||
return path;
|
||||
if (*(last + 1) == '\0') {
|
||||
*last = '\0';
|
||||
return basename(path);
|
||||
}
|
||||
return last + 1;
|
||||
}
|
||||
|
||||
extern unsigned int rd_unsigned2();
|
||||
|
||||
int open_archive(char *name, int mode)
|
||||
{
|
||||
unsigned short magic = 0;
|
||||
int fd;
|
||||
|
||||
if (mode == CREATE) {
|
||||
if ((fd = creat(name, 0666)) < 0)
|
||||
error2(TRUE, "cannot creat %s\n", name);
|
||||
magic = MAGIC_NUMBER;
|
||||
wr_int2(fd, magic);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if ((fd = open(name, mode)) < 0) {
|
||||
if (mode == APPEND) {
|
||||
close(open_archive(name, CREATE));
|
||||
if (!nocr_fl) error3(FALSE, "%s: creating %s\n", progname, name);
|
||||
return open_archive(name, APPEND);
|
||||
}
|
||||
error2(TRUE, "cannot open %s\n", name);
|
||||
}
|
||||
lseek(fd, 0L, 0);
|
||||
magic = rd_unsigned2(fd);
|
||||
if (magic != AALMAG && magic != ARMAG)
|
||||
error2(TRUE, "%s is not in ar format\n", name);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#if __STDC__
|
||||
void catch(int sig)
|
||||
#else
|
||||
catch()
|
||||
#endif
|
||||
{
|
||||
unlink(temp_arch);
|
||||
_exit (2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
register char *ptr;
|
||||
int needs_arg = 0;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
if (argc < 3)
|
||||
usage();
|
||||
|
||||
for (ptr = argv[1]; *ptr; ptr++) {
|
||||
switch (*ptr) {
|
||||
case 't' :
|
||||
show_fl = TRUE;
|
||||
break;
|
||||
case 'v' :
|
||||
verbose = TRUE;
|
||||
break;
|
||||
case 'x' :
|
||||
ex_fl = TRUE;
|
||||
break;
|
||||
case 'a' :
|
||||
needs_arg = 1;
|
||||
app_fl = TRUE;
|
||||
break;
|
||||
case 'c' :
|
||||
nocr_fl = TRUE;
|
||||
break;
|
||||
#ifndef AAL
|
||||
case 'p' :
|
||||
needs_arg = 1;
|
||||
pr_fl = TRUE;
|
||||
break;
|
||||
#endif
|
||||
case 'd' :
|
||||
needs_arg = 1;
|
||||
del_fl = TRUE;
|
||||
break;
|
||||
case 'r' :
|
||||
needs_arg = 1;
|
||||
rep_fl = TRUE;
|
||||
break;
|
||||
case 'l' :
|
||||
local_fl = TRUE;
|
||||
break;
|
||||
case 'u' :
|
||||
update_fl = TRUE;
|
||||
break;
|
||||
#ifdef DISTRIBUTION
|
||||
case 'D' :
|
||||
distr_fl = TRUE;
|
||||
break;
|
||||
#endif
|
||||
default :
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_arg && argc <= 3)
|
||||
usage();
|
||||
#ifdef DISTRIBUTION
|
||||
if (distr_fl) {
|
||||
struct stat statbuf;
|
||||
|
||||
stat(progname, &statbuf);
|
||||
distr_time = statbuf.st_mtime;
|
||||
}
|
||||
#endif
|
||||
if (local_fl) strcpy(temp_arch, "ar.XXXXXX");
|
||||
else strcpy(temp_arch, "/usr/tmp/ar.XXXXXX");
|
||||
|
||||
if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1)
|
||||
usage();
|
||||
|
||||
if (update_fl && !rep_fl)
|
||||
usage();
|
||||
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
) {
|
||||
mktemp(temp_arch);
|
||||
}
|
||||
#ifdef AAL
|
||||
tab = (struct ranlib *) malloc(512 * sizeof(struct ranlib));
|
||||
tstrtab = malloc(4096);
|
||||
if (!tab || !tstrtab) error1(TRUE,"Out of core\n");
|
||||
tabsz = 512;
|
||||
strtabsz = 4096;
|
||||
#endif
|
||||
|
||||
signal(SIGINT, catch);
|
||||
get(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MEMBER *
|
||||
get_member()
|
||||
{
|
||||
static MEMBER member;
|
||||
|
||||
again:
|
||||
if (rd_arhdr(ar_fd, &member) == 0)
|
||||
return NULL;
|
||||
if (member.ar_size < 0) {
|
||||
error1(TRUE, "archive has member with negative size\n");
|
||||
}
|
||||
#ifdef AAL
|
||||
if (equal(SYMDEF, member.ar_name)) {
|
||||
lseek(ar_fd, member.ar_size, 1);
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
return &member;
|
||||
}
|
||||
|
||||
char *get_mode();
|
||||
|
||||
static void get(int argc, char *argv[])
|
||||
{
|
||||
register MEMBER *member;
|
||||
int i = 0;
|
||||
int temp_fd, read_chars;
|
||||
|
||||
ar_fd = open_archive(argv[2], (show_fl || pr_fl || ex_fl) ? READ : APPEND);
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
)
|
||||
temp_fd = open_archive(temp_arch, CREATE);
|
||||
while ((member = get_member()) != NULL) {
|
||||
if (argc > 3) {
|
||||
for (i = 3; i < argc; i++) {
|
||||
if (equal(basename(argv[i]), member->ar_name))
|
||||
break;
|
||||
}
|
||||
if (i == argc || app_fl) {
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
) {
|
||||
#ifdef AAL
|
||||
if (i != argc) {
|
||||
print("%s: already in archive\n", argv[i]);
|
||||
argv[i] = "";
|
||||
}
|
||||
#endif
|
||||
wr_arhdr(temp_fd, member);
|
||||
copy_member(member, ar_fd, temp_fd, 0);
|
||||
}
|
||||
else {
|
||||
#ifndef AAL
|
||||
if (app_fl && i != argc) {
|
||||
print("%s: already in archive\n", argv[i]);
|
||||
argv[i] = "";
|
||||
}
|
||||
#endif
|
||||
lseek(ar_fd, even(member->ar_size),1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ex_fl || pr_fl)
|
||||
extract(member);
|
||||
else {
|
||||
if (rep_fl) {
|
||||
int isold = 0;
|
||||
if(update_fl) {
|
||||
struct stat status;
|
||||
if (stat(argv[i], &status) >= 0) {
|
||||
if(status.st_mtime <= member->ar_date)
|
||||
isold = 1;
|
||||
}
|
||||
}
|
||||
if(!isold)
|
||||
add(argv[i], temp_fd, "r - %s\n");
|
||||
else {
|
||||
wr_arhdr(temp_fd, member);
|
||||
copy_member(member, ar_fd, temp_fd, 0);
|
||||
if(verbose)
|
||||
show("r - %s (old)\n", member->ar_name);
|
||||
}
|
||||
}
|
||||
else if (show_fl) {
|
||||
char buf[sizeof(member->ar_name) + 2];
|
||||
register char *p = buf, *q = member->ar_name;
|
||||
|
||||
while (q <= &member->ar_name[sizeof(member->ar_name)-1] && *q) {
|
||||
*p++ = *q++;
|
||||
}
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
if (verbose) {
|
||||
char *mode = get_mode(member->ar_mode);
|
||||
char *date = ctime(&(member->ar_date));
|
||||
|
||||
*(date + 16) = '\0';
|
||||
*(date + 24) = '\0';
|
||||
|
||||
print("%s%3u/%u%7ld %s %s %s",
|
||||
mode,
|
||||
(unsigned) (member->ar_uid & 0377),
|
||||
(unsigned) (member->ar_gid & 0377),
|
||||
member->ar_size,
|
||||
date+4,
|
||||
date+20,
|
||||
buf);
|
||||
}
|
||||
else print(buf);
|
||||
}
|
||||
else if (del_fl)
|
||||
show("d - %s\n", member->ar_name);
|
||||
lseek(ar_fd, even(member->ar_size), 1);
|
||||
}
|
||||
argv[i] = "";
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
for (i = 3; i < argc; i++)
|
||||
if (argv[i][0] != '\0') {
|
||||
#ifndef AAL
|
||||
if (app_fl)
|
||||
add(argv[i], ar_fd, "a - %s\n");
|
||||
else
|
||||
#endif
|
||||
if (rep_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
)
|
||||
add(argv[i], temp_fd, "a - %s\n");
|
||||
else {
|
||||
print("%s: not found\n", argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
) {
|
||||
signal(SIGINT, SIG_IGN);
|
||||
close(ar_fd);
|
||||
close(temp_fd);
|
||||
ar_fd = open_archive(argv[2], CREATE);
|
||||
temp_fd = open_archive(temp_arch, APPEND);
|
||||
#ifdef AAL
|
||||
write_symdef();
|
||||
#endif
|
||||
while ((read_chars = read(temp_fd, io_buffer, IO_SIZE)) > 0)
|
||||
mwrite(ar_fd, io_buffer, read_chars);
|
||||
close(temp_fd);
|
||||
unlink(temp_arch);
|
||||
}
|
||||
close(ar_fd);
|
||||
}
|
||||
|
||||
static void add(char *name, int fd, char *mess)
|
||||
{
|
||||
static MEMBER member;
|
||||
register int read_chars;
|
||||
struct stat status;
|
||||
int src_fd;
|
||||
|
||||
if (stat(name, &status) < 0) {
|
||||
error2(FALSE, "cannot find %s\n", name);
|
||||
return;
|
||||
}
|
||||
else if (S_ISDIR(status.st_mode)) {
|
||||
error2(FALSE, "%s is a directory (ignored)\n", name);
|
||||
return;
|
||||
}
|
||||
else if ((src_fd = open(name, 0)) < 0) {
|
||||
error2(FALSE, "cannot open %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy (member.ar_name, basename (name), sizeof(member.ar_name));
|
||||
member.ar_uid = status.st_uid;
|
||||
member.ar_gid = status.st_gid;
|
||||
member.ar_mode = status.st_mode;
|
||||
member.ar_date = status.st_mtime;
|
||||
member.ar_size = status.st_size;
|
||||
#ifdef DISTRIBUTION
|
||||
if (distr_fl) {
|
||||
member.ar_uid = 2;
|
||||
member.ar_gid = 2;
|
||||
member.ar_mode = 0644;
|
||||
member.ar_date = distr_time;
|
||||
}
|
||||
#endif
|
||||
wr_arhdr(fd, &member);
|
||||
#ifdef AAL
|
||||
do_object(src_fd, member.ar_size);
|
||||
lseek(src_fd, 0L, 0);
|
||||
offset += AR_TOTAL + even(member.ar_size);
|
||||
#endif
|
||||
while (status.st_size > 0) {
|
||||
int x = IO_SIZE;
|
||||
|
||||
read_chars = x;
|
||||
if (status.st_size < x) {
|
||||
x = status.st_size;
|
||||
read_chars = x;
|
||||
status.st_size = 0;
|
||||
x = even(x);
|
||||
}
|
||||
else status.st_size -= x;
|
||||
if (read(src_fd, io_buffer, read_chars) != read_chars) {
|
||||
error2(FALSE,"%s seems to shrink\n", name);
|
||||
break;
|
||||
}
|
||||
mwrite(fd, io_buffer, x);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
show(mess, member.ar_name);
|
||||
close(src_fd);
|
||||
}
|
||||
|
||||
static void extract(register MEMBER *member)
|
||||
{
|
||||
int fd = 1;
|
||||
char buf[sizeof(member->ar_name) + 1];
|
||||
|
||||
strncpy(buf, member->ar_name, sizeof(member->ar_name));
|
||||
buf[sizeof(member->ar_name)] = 0;
|
||||
if (pr_fl == FALSE && (fd = creat(buf, 0666)) < 0) {
|
||||
error2(FALSE, "cannot create %s\n", buf);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (pr_fl == FALSE) show("x - %s\n", buf);
|
||||
else show("\n<%s>\n\n", buf);
|
||||
}
|
||||
|
||||
copy_member(member, ar_fd, fd, 1);
|
||||
|
||||
if (fd >= 0 && fd != 1)
|
||||
close(fd);
|
||||
if (pr_fl == FALSE) chmod(buf, member->ar_mode);
|
||||
}
|
||||
|
||||
static void copy_member(MEMBER *member, int from, int to, int extracting)
|
||||
{
|
||||
register int rest;
|
||||
long mem_size = member->ar_size;
|
||||
BOOL is_odd = odd(mem_size) ? TRUE : FALSE;
|
||||
|
||||
#ifdef AAL
|
||||
if (! extracting) {
|
||||
long pos = lseek(from, 0L, 1);
|
||||
|
||||
do_object(from, mem_size);
|
||||
offset += AR_TOTAL + even(mem_size);
|
||||
lseek(from, pos, 0);
|
||||
}
|
||||
#endif
|
||||
do {
|
||||
rest = mem_size > (long) IO_SIZE ? IO_SIZE : (int) mem_size;
|
||||
if (read(from, io_buffer, rest) != rest) {
|
||||
char buf[sizeof(member->ar_name) + 1];
|
||||
|
||||
strncpy(buf, member->ar_name, sizeof(member->ar_name));
|
||||
buf[sizeof(member->ar_name)] = 0;
|
||||
error2(TRUE, "read error on %s\n", buf);
|
||||
}
|
||||
if (to >= 0) mwrite(to, io_buffer, rest);
|
||||
mem_size -= (long) rest;
|
||||
} while (mem_size > 0L);
|
||||
|
||||
if (is_odd) {
|
||||
lseek(from, 1L, 1);
|
||||
if (to >= 0 && ! extracting)
|
||||
lseek(to, 1L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
get_mode(mode)
|
||||
register int mode;
|
||||
{
|
||||
static char mode_buf[11];
|
||||
register int tmp = mode;
|
||||
int i;
|
||||
|
||||
mode_buf[9] = ' ';
|
||||
for (i = 0; i < 3; i++) {
|
||||
mode_buf[i * 3] = (tmp & S_IREAD) ? 'r' : '-';
|
||||
mode_buf[i * 3 + 1] = (tmp & S_IWRITE) ? 'w' : '-';
|
||||
mode_buf[i * 3 + 2] = (tmp & S_IEXEC) ? 'x' : '-';
|
||||
tmp <<= 3;
|
||||
}
|
||||
if (mode & S_ISUID)
|
||||
mode_buf[2] = 's';
|
||||
if (mode & S_ISGID)
|
||||
mode_buf[5] = 's';
|
||||
return mode_buf;
|
||||
}
|
||||
|
||||
void wr_fatal()
|
||||
{
|
||||
error1(TRUE, "write error\n");
|
||||
}
|
||||
|
||||
void rd_fatal()
|
||||
{
|
||||
error1(TRUE, "read error\n");
|
||||
}
|
||||
|
||||
static void mwrite(int fd, char *address, int bytes)
|
||||
{
|
||||
if (write(fd, address, bytes) != bytes)
|
||||
error1(TRUE, "write error\n");
|
||||
}
|
||||
|
||||
static void show(char *s, char *name)
|
||||
{
|
||||
MEMBER x;
|
||||
char buf[sizeof(x.ar_name)+1];
|
||||
register char *p = buf, *q = name;
|
||||
|
||||
while (q <= &name[sizeof(x.ar_name)-1] && *q) *p++ = *q++;
|
||||
*p++ = '\0';
|
||||
print(s, buf);
|
||||
}
|
||||
|
||||
#ifdef AAL
|
||||
/*
|
||||
* Write out the ranlib table: first 4 bytes telling how many ranlib structs
|
||||
* there are, followed by the ranlib structs,
|
||||
* then 4 bytes giving the size of the string table, followed by the string
|
||||
* table itself.
|
||||
*/
|
||||
static void write_symdef(void)
|
||||
{
|
||||
register struct ranlib *ran;
|
||||
register int i;
|
||||
register long delta;
|
||||
MEMBER arbuf;
|
||||
|
||||
if (odd(tssiz))
|
||||
tstrtab[tssiz++] = '\0';
|
||||
for (i = 0; i < sizeof(arbuf.ar_name); i++)
|
||||
arbuf.ar_name[i] = '\0';
|
||||
strcpy(arbuf.ar_name, SYMDEF);
|
||||
arbuf.ar_size = 4 + 2 * 4 * (long)tnum + 4 + (long)tssiz;
|
||||
time(&arbuf.ar_date);
|
||||
arbuf.ar_uid = getuid();
|
||||
arbuf.ar_gid = getgid();
|
||||
arbuf.ar_mode = 0444;
|
||||
#ifdef DISTRIBUTION
|
||||
if (distr_fl) {
|
||||
arbuf.ar_uid = 2;
|
||||
arbuf.ar_gid = 2;
|
||||
arbuf.ar_date = distr_time;
|
||||
}
|
||||
#endif
|
||||
wr_arhdr(ar_fd,&arbuf);
|
||||
wr_long(ar_fd, (long) tnum);
|
||||
/*
|
||||
* Account for the space occupied by the magic number
|
||||
* and the ranlib table.
|
||||
*/
|
||||
delta = 2 + AR_TOTAL + arbuf.ar_size;
|
||||
for (ran = tab; ran < &tab[tnum]; ran++) {
|
||||
ran->ran_pos += delta;
|
||||
}
|
||||
|
||||
wr_ranlib(ar_fd, tab, (long) tnum);
|
||||
wr_long(ar_fd, (long) tssiz);
|
||||
wr_bytes(ar_fd, tstrtab, (long) tssiz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return whether the bytes in `buf' form a good object header.
|
||||
* The header is put in `headp'.
|
||||
*/
|
||||
int
|
||||
is_outhead(register struct outhead *headp)
|
||||
{
|
||||
return !BADMAGIC(*headp) && headp->oh_nname != 0;
|
||||
}
|
||||
|
||||
static void do_object(int f, long size)
|
||||
{
|
||||
struct outhead headbuf;
|
||||
|
||||
if (size < SZ_HEAD) {
|
||||
/* It can't be an object file. */
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Read a header to see if it is an object file.
|
||||
*/
|
||||
if (! rd_fdopen(f)) {
|
||||
rd_fatal();
|
||||
}
|
||||
rd_ohead(&headbuf);
|
||||
if (!is_outhead(&headbuf)) {
|
||||
return;
|
||||
}
|
||||
do_names(&headbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* First skip the names and read in the string table, then seek back to the
|
||||
* name table and read and write the names one by one. Update the ranlib table
|
||||
* accordingly.
|
||||
*/
|
||||
static void do_names(struct outhead *headp)
|
||||
{
|
||||
register char *strings;
|
||||
register int nnames = headp->oh_nname;
|
||||
#define NNAMES 100
|
||||
struct outname namebuf[NNAMES];
|
||||
long xxx = OFF_CHAR(*headp);
|
||||
|
||||
if ( headp->oh_nchar != (unsigned int)headp->oh_nchar ||
|
||||
(strings = malloc((unsigned int)headp->oh_nchar)) == (char *)0
|
||||
) {
|
||||
error1(TRUE, "string table too big\n");
|
||||
}
|
||||
rd_string(strings, headp->oh_nchar);
|
||||
while (nnames) {
|
||||
int i = nnames >= NNAMES ? NNAMES : nnames;
|
||||
register struct outname *p = namebuf;
|
||||
|
||||
nnames -= i;
|
||||
rd_name(namebuf, i);
|
||||
while (i--) {
|
||||
long off = p->on_foff - xxx;
|
||||
if (p->on_foff == (long)0) {
|
||||
p++;
|
||||
continue; /* An unrecognizable name. */
|
||||
}
|
||||
p->on_mptr = strings + off;
|
||||
/*
|
||||
* Only enter names that are exported and are really
|
||||
* defined. Also enter common names. Note, that
|
||||
* this might cause problems when the name is really
|
||||
* defined in a later file, with a value != 0.
|
||||
* However, this problem also exists on the Unix
|
||||
* ranlib archives.
|
||||
*/
|
||||
if ( (p->on_type & S_EXT) &&
|
||||
(p->on_type & S_TYP) != S_UND
|
||||
)
|
||||
enter_name(p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
free(strings);
|
||||
}
|
||||
|
||||
static void enter_name(struct outname *namep)
|
||||
{
|
||||
register char *cp;
|
||||
|
||||
if (tnum >= tabsz) {
|
||||
tab = (struct ranlib *)
|
||||
realloc((char *) tab, (tabsz += 512) * sizeof(struct ranlib));
|
||||
if (! tab) error1(TRUE, "Out of core\n");
|
||||
}
|
||||
tab[tnum].ran_off = tssiz;
|
||||
tab[tnum].ran_pos = offset;
|
||||
|
||||
for (cp = namep->on_mptr;; cp++) {
|
||||
if (tssiz >= strtabsz) {
|
||||
tstrtab = realloc(tstrtab, (strtabsz += 4096));
|
||||
if (! tstrtab) error1(TRUE, "string table overflow\n");
|
||||
}
|
||||
tstrtab[tssiz++] = *cp;
|
||||
if (!*cp) break;
|
||||
}
|
||||
tnum++;
|
||||
}
|
||||
#endif /* AAL */
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
extern void rd_fatal();
|
||||
extern void wr_fatal();
|
|
@ -1,9 +0,0 @@
|
|||
#if defined(mc68020) || defined(mc68000) || defined(sparc)
|
||||
#define BYTES_REVERSED 1
|
||||
#define WORDS_REVERSED 1
|
||||
#define CHAR_UNSIGNED 0
|
||||
#else
|
||||
#define BYTES_REVERSED 0
|
||||
#define WORDS_REVERSED 0
|
||||
#define CHAR_UNSIGNED 0
|
||||
#endif
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
extern char *long2str();
|
||||
|
||||
static int
|
||||
integral(int c)
|
||||
{
|
||||
switch (c) {
|
||||
case 'b':
|
||||
return -2;
|
||||
case 'd':
|
||||
return 10;
|
||||
case 'o':
|
||||
return -8;
|
||||
case 'u':
|
||||
return -10;
|
||||
case 'x':
|
||||
return -16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*VARARGS2*/
|
||||
/*FORMAT1 $
|
||||
%s = char *
|
||||
%l = long
|
||||
%c = int
|
||||
%[uxbo] = unsigned int
|
||||
%d = int
|
||||
$ */
|
||||
int
|
||||
_format(char *buf, char *fmt, va_list argp)
|
||||
{
|
||||
register char *pf = fmt;
|
||||
register char *pb = buf;
|
||||
|
||||
while (*pf) {
|
||||
if (*pf == '%') {
|
||||
register int width, base, pad, npad;
|
||||
char *arg;
|
||||
char cbuf[2];
|
||||
char *badformat = "<bad format>";
|
||||
|
||||
/* get padder */
|
||||
if (*++pf == '0') {
|
||||
pad = '0';
|
||||
++pf;
|
||||
}
|
||||
else
|
||||
pad = ' ';
|
||||
|
||||
/* get width */
|
||||
width = 0;
|
||||
while (*pf >= '0' && *pf <= '9')
|
||||
width = 10 * width + *pf++ - '0';
|
||||
|
||||
if (*pf == 's') {
|
||||
arg = va_arg(argp, char *);
|
||||
}
|
||||
else
|
||||
if (*pf == 'c') {
|
||||
cbuf[0] = va_arg(argp, int);
|
||||
cbuf[1] = '\0';
|
||||
arg = &cbuf[0];
|
||||
}
|
||||
else
|
||||
if (*pf == 'l') {
|
||||
/* alignment ??? */
|
||||
base = integral(*++pf);
|
||||
if (base) {
|
||||
arg = long2str(va_arg(argp,long), base);
|
||||
}
|
||||
else {
|
||||
pf--;
|
||||
arg = badformat;
|
||||
}
|
||||
}
|
||||
else
|
||||
if ((base = integral(*pf))) {
|
||||
arg = long2str((long)va_arg(argp,int), base);
|
||||
}
|
||||
else
|
||||
if (*pf == '%')
|
||||
arg = "%";
|
||||
else
|
||||
arg = badformat;
|
||||
|
||||
npad = width - strlen(arg);
|
||||
|
||||
while (npad-- > 0)
|
||||
*pb++ = pad;
|
||||
|
||||
while (*pb++ = *arg++);
|
||||
pb--;
|
||||
pf++;
|
||||
}
|
||||
else
|
||||
*pb++ = *pf++;
|
||||
}
|
||||
return pb - buf;
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
extern int _format(char *buf, char *fmt, va_list argp);
|
|
@ -1,19 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* collection of options, selected by including or excluding 'defines' */
|
||||
|
||||
/* Version number of the EM object code */
|
||||
# define VERSION 3 /* 16 bits number */
|
||||
|
||||
/* The default machine used by ack, acc, apc */
|
||||
# define ACKM "minix"
|
||||
|
||||
/* size of local machine, either 0 (for 16 bit address space), or 1 */
|
||||
# undef BIGMACHINE
|
||||
|
||||
/* operating system, SYS_5, V7, BSD4_1 or BSD4_2; Do NOT delete the comment
|
||||
in the next line! */
|
||||
# define V7 1 /* SYSTEM */
|
|
@ -1,67 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* Integer to String translator
|
||||
-> base is a value from [-16,-2] V [2,16]
|
||||
-> base < 0: see 'val' as unsigned value
|
||||
-> no checks for buffer overflow and illegal parameters
|
||||
(1985, EHB)
|
||||
*/
|
||||
|
||||
#define MAXWIDTH 32
|
||||
|
||||
char *
|
||||
long2str(val, base)
|
||||
register long val;
|
||||
register int base;
|
||||
{
|
||||
static char numbuf[MAXWIDTH];
|
||||
static char vec[] = "0123456789ABCDEF";
|
||||
register char *p = &numbuf[MAXWIDTH];
|
||||
int sign = (base > 0);
|
||||
|
||||
*--p = '\0'; /* null-terminate string */
|
||||
if (val) {
|
||||
if (base > 0) {
|
||||
if (val < 0L) {
|
||||
long v1 = -val;
|
||||
if (v1 == val)
|
||||
goto overflow;
|
||||
val = v1;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
}
|
||||
else
|
||||
if (base < 0) { /* unsigned */
|
||||
base = -base;
|
||||
if (val < 0L) { /* taken from Amoeba src */
|
||||
register int mod, i;
|
||||
overflow:
|
||||
mod = 0;
|
||||
for (i = 0; i < 8 * sizeof val; i++) {
|
||||
mod <<= 1;
|
||||
if (val < 0)
|
||||
mod++;
|
||||
val <<= 1;
|
||||
if (mod >= base) {
|
||||
mod -= base;
|
||||
val++;
|
||||
}
|
||||
}
|
||||
*--p = vec[mod];
|
||||
}
|
||||
}
|
||||
do {
|
||||
*--p = vec[(int) (val % base)];
|
||||
val /= base;
|
||||
} while (val != 0L);
|
||||
if (sign)
|
||||
*--p = '-'; /* don't forget it !! */
|
||||
}
|
||||
else
|
||||
*--p = '0'; /* just a simple 0 */
|
||||
return p;
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "byte_order.h"
|
||||
#include <local.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if CHAR_UNSIGNED
|
||||
#define Xchar(ch) (ch)
|
||||
#else
|
||||
#define Xchar(ch) ((ch) & 0377)
|
||||
#endif
|
||||
|
||||
#if ! defined(BYTES_REVERSED)
|
||||
#define BYTES_REVERSED 1
|
||||
#endif
|
||||
|
||||
#if ! defined(WORDS_REVERSED)
|
||||
#define WORDS_REVERSED 1
|
||||
#endif
|
||||
|
||||
#if BYTES_REVERSED
|
||||
#define uget2(c) (Xchar((c)[0]) | ((unsigned) Xchar((c)[1]) << 8))
|
||||
#define Xput2(i, c) (((c)[0] = (i)), ((c)[1] = (i) >> 8))
|
||||
#define put2(i, c) { register int j = (i); Xput2(j, c); }
|
||||
#else
|
||||
#define uget2(c) (* ((unsigned short *) (c)))
|
||||
#define Xput2(i, c) (* ((short *) (c)) = (i))
|
||||
#define put2(i, c) Xput2(i, c)
|
||||
#endif
|
||||
|
||||
#define get2(c) ((short) uget2(c))
|
||||
|
||||
#if WORDS_REVERSED || BYTES_REVERSED
|
||||
#define get4(c) (uget2(c) | ((long) uget2((c)+2) << 16))
|
||||
#define put4(l, c) { register long x=(l); \
|
||||
Xput2((int)x,c); \
|
||||
Xput2((int)(x>>16),(c)+2); \
|
||||
}
|
||||
#else
|
||||
#define get4(c) (* ((long *) (c)))
|
||||
#define put4(l, c) (* ((long *) (c)) = (l))
|
||||
#endif
|
||||
|
||||
#define SECTCNT 3 /* number of sections with own output buffer */
|
||||
#if BIGMACHINE
|
||||
#define WBUFSIZ (8*BUFSIZ)
|
||||
#else
|
||||
#define WBUFSIZ BUFSIZ
|
||||
#endif
|
||||
|
||||
struct fil {
|
||||
int cnt;
|
||||
char *pnow;
|
||||
char *pbegin;
|
||||
long currpos;
|
||||
int fd;
|
||||
char pbuf[WBUFSIZ];
|
||||
};
|
||||
|
||||
extern struct fil __parts[];
|
||||
|
||||
#define PARTEMIT 0
|
||||
#define PARTRELO (PARTEMIT+SECTCNT)
|
||||
#define PARTNAME (PARTRELO+1)
|
||||
#define PARTCHAR (PARTNAME+1)
|
||||
#ifdef SYMDBUG
|
||||
#define PARTDBUG (PARTCHAR+1)
|
||||
#else
|
||||
#define PARTDBUG (PARTCHAR+0)
|
||||
#endif
|
||||
#define NPARTS (PARTDBUG + 1)
|
||||
|
||||
#define getsect(s) (PARTEMIT+((s)>=(SECTCNT-1)?(SECTCNT-1):(s)))
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#ifndef __OUT_H_INCLUDED
|
||||
#define __OUT_H_INCLUDED
|
||||
/*
|
||||
* output format for ACK assemblers
|
||||
*/
|
||||
#ifndef ushort
|
||||
#define ushort unsigned short
|
||||
#endif /* ushort */
|
||||
|
||||
struct outhead {
|
||||
ushort oh_magic; /* magic number */
|
||||
ushort oh_stamp; /* version stamp */
|
||||
ushort oh_flags; /* several format flags */
|
||||
ushort oh_nsect; /* number of outsect structures */
|
||||
ushort oh_nrelo; /* number of outrelo structures */
|
||||
ushort oh_nname; /* number of outname structures */
|
||||
long oh_nemit; /* sum of all os_flen */
|
||||
long oh_nchar; /* size of string area */
|
||||
};
|
||||
|
||||
#define O_MAGIC 0x0201 /* magic number of output file */
|
||||
#define O_STAMP 0 /* version stamp */
|
||||
#define MAXSECT 64 /* Maximum number of sections */
|
||||
|
||||
#define HF_LINK 0x0004 /* unresolved references left */
|
||||
#define HF_8086 0x0008 /* os_base specially encoded */
|
||||
|
||||
struct outsect {
|
||||
long os_base; /* startaddress in machine */
|
||||
long os_size; /* section size in machine */
|
||||
long os_foff; /* startaddress in file */
|
||||
long os_flen; /* section size in file */
|
||||
long os_lign; /* section alignment */
|
||||
};
|
||||
|
||||
struct outrelo {
|
||||
char or_type; /* type of reference */
|
||||
char or_sect; /* referencing section */
|
||||
ushort or_nami; /* referenced symbol index */
|
||||
long or_addr; /* referencing address */
|
||||
};
|
||||
|
||||
struct outname {
|
||||
union {
|
||||
char *on_ptr; /* symbol name (in core) */
|
||||
long on_off; /* symbol name (in file) */
|
||||
} on_u;
|
||||
#define on_mptr on_u.on_ptr
|
||||
#define on_foff on_u.on_off
|
||||
ushort on_type; /* symbol type */
|
||||
ushort on_desc; /* debug info */
|
||||
long on_valu; /* symbol value */
|
||||
};
|
||||
|
||||
/*
|
||||
* relocation type bits
|
||||
*/
|
||||
#define RELSZ 0x07 /* relocation length */
|
||||
#define RELO1 1 /* 1 byte */
|
||||
#define RELO2 2 /* 2 bytes */
|
||||
#define RELO4 4 /* 4 bytes */
|
||||
#define RELPC 0x08 /* pc relative */
|
||||
#define RELBR 0x10 /* High order byte lowest address. */
|
||||
#define RELWR 0x20 /* High order word lowest address. */
|
||||
|
||||
/*
|
||||
* section type bits and fields
|
||||
*/
|
||||
#define S_TYP 0x007F /* undefined, absolute or relative */
|
||||
#define S_EXT 0x0080 /* external flag */
|
||||
#define S_ETC 0x7F00 /* for symbolic debug, bypassing 'as' */
|
||||
|
||||
/*
|
||||
* S_TYP field values
|
||||
*/
|
||||
#define S_UND 0x0000 /* undefined item */
|
||||
#define S_ABS 0x0001 /* absolute item */
|
||||
#define S_MIN 0x0002 /* first user section */
|
||||
#define S_MAX (S_TYP-1) /* last user section */
|
||||
#define S_CRS S_TYP /* on_valu is symbol index which contains value */
|
||||
|
||||
/*
|
||||
* S_ETC field values
|
||||
*/
|
||||
#define S_SCT 0x0100 /* section names */
|
||||
#define S_LIN 0x0200 /* hll source line item */
|
||||
#define S_FIL 0x0300 /* hll source file item */
|
||||
#define S_MOD 0x0400 /* ass source file item */
|
||||
#define S_COM 0x1000 /* Common name. */
|
||||
#define S_STB 0xe000 /* entries with any of these bits set are
|
||||
reserved for debuggers
|
||||
*/
|
||||
|
||||
/*
|
||||
* structure format strings
|
||||
*/
|
||||
#define SF_HEAD "22222244"
|
||||
#define SF_SECT "44444"
|
||||
#define SF_RELO "1124"
|
||||
#define SF_NAME "4224"
|
||||
|
||||
/*
|
||||
* structure sizes (bytes in file; add digits in SF_*)
|
||||
*/
|
||||
#define SZ_HEAD 20
|
||||
#define SZ_SECT 20
|
||||
#define SZ_RELO 8
|
||||
#define SZ_NAME 12
|
||||
|
||||
/*
|
||||
* file access macros
|
||||
*/
|
||||
#define BADMAGIC(x) ((x).oh_magic!=O_MAGIC)
|
||||
#define OFF_SECT(x) SZ_HEAD
|
||||
#define OFF_EMIT(x) (OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT))
|
||||
#define OFF_RELO(x) (OFF_EMIT(x) + (x).oh_nemit)
|
||||
#define OFF_NAME(x) (OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO))
|
||||
#define OFF_CHAR(x) (OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME))
|
||||
|
||||
#endif /* __OUT_H_INCLUDED */
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#define SSIZE 1024
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include <system.h>
|
||||
#include "param.h"
|
||||
#include "format.h"
|
||||
#include "write.h"
|
||||
|
||||
/*VARARGS*/
|
||||
/*FORMAT0v $
|
||||
%s = char *
|
||||
%l = long
|
||||
%c = int
|
||||
%[uxbo] = unsigned int
|
||||
%d = int
|
||||
$ */
|
||||
void
|
||||
#if __STDC__
|
||||
print(char *fmt, ...)
|
||||
#else
|
||||
print(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
char buf[SSIZE];
|
||||
|
||||
#if __STDC__
|
||||
va_start(args, fmt);
|
||||
#else
|
||||
va_start(args);
|
||||
#endif
|
||||
sys_write(STDOUT, buf, _format(buf, fmt, args));
|
||||
va_end(args);
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
extern void print(char *fmt, ...);
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#ifndef __RANLIB_H_INCLUDED
|
||||
#define __RANLIB_H_INCLUDED
|
||||
|
||||
#ifndef SYMDEF
|
||||
# define SYMDEF "__.SYMDEF"
|
||||
#endif /* SYMDEF */
|
||||
|
||||
/*
|
||||
* Structure of the SYMDEF table of contents for an archive.
|
||||
* SYMDEF begins with a long giving the number of ranlib
|
||||
* structures that immediately follow, and then continues with a string
|
||||
* table consisting of a long giving the number of bytes of
|
||||
* strings that follow and then the strings themselves.
|
||||
*/
|
||||
struct ranlib {
|
||||
union {
|
||||
char *ran__ptr; /* symbol name (in core) */
|
||||
long ran__off; /* symbol name (in file) */
|
||||
} ran_u;
|
||||
#define ran_ptr ran_u.ran__ptr
|
||||
#define ran_off ran_u.ran__off
|
||||
long ran_pos; /* library member is at this position */
|
||||
};
|
||||
|
||||
#define SZ_RAN 8
|
||||
#define SF_RAN "44"
|
||||
|
||||
extern void wr_ranlib(int fd, struct ranlib ran[], long cnt);
|
||||
#endif /* __RANLIB_H_INCLUDED */
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "out.h"
|
||||
#include "object.h"
|
||||
#include "rd.h"
|
||||
#include "rd_bytes.h"
|
||||
|
||||
extern long lseek();
|
||||
|
||||
/*
|
||||
* Parts of the output file.
|
||||
*/
|
||||
#undef PARTEMIT
|
||||
#undef PARTRELO
|
||||
#undef PARTNAME
|
||||
#undef PARTCHAR
|
||||
#undef PARTDBUG
|
||||
#undef NPARTS
|
||||
|
||||
#define PARTEMIT 0
|
||||
#define PARTRELO 1
|
||||
#define PARTNAME 2
|
||||
#define PARTCHAR 3
|
||||
#ifdef SYMDBUG
|
||||
#define PARTDBUG 4
|
||||
#else
|
||||
#define PARTDBUG 3
|
||||
#endif
|
||||
#define NPARTS (PARTDBUG + 1)
|
||||
|
||||
static long offset[MAXSECT];
|
||||
|
||||
static int outfile;
|
||||
static long outseek[NPARTS];
|
||||
static long currpos;
|
||||
static long rd_base;
|
||||
#define OUTSECT(i) \
|
||||
(outseek[PARTEMIT] = offset[i])
|
||||
#define BEGINSEEK(p, o) \
|
||||
(outseek[(p)] = (o))
|
||||
|
||||
static int sectionnr;
|
||||
|
||||
static
|
||||
void OUTREAD(int p, char *b, long n)
|
||||
{
|
||||
register long l = outseek[p];
|
||||
|
||||
if (currpos != l) {
|
||||
lseek(outfile, l, 0);
|
||||
}
|
||||
rd_bytes(outfile, b, n);
|
||||
l += n;
|
||||
currpos = l;
|
||||
outseek[p] = l;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the output file according to the chosen strategy.
|
||||
*/
|
||||
int
|
||||
rd_open(char *f)
|
||||
{
|
||||
int outfile = open(f, 0);
|
||||
if (outfile < 0)
|
||||
return 0;
|
||||
return rd_fdopen(outfile);
|
||||
}
|
||||
|
||||
static int offcnt;
|
||||
|
||||
int rd_fdopen(int fd)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < NPARTS; i++) outseek[i] = 0;
|
||||
offcnt = 0;
|
||||
rd_base = lseek(fd, 0L, 1);
|
||||
if (rd_base < 0) {
|
||||
return 0;
|
||||
}
|
||||
currpos = rd_base;
|
||||
outseek[PARTEMIT] = currpos;
|
||||
outfile = fd;
|
||||
sectionnr = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rd_close()
|
||||
{
|
||||
|
||||
close(outfile);
|
||||
outfile = -1;
|
||||
}
|
||||
|
||||
int rd_fd()
|
||||
{
|
||||
return outfile;
|
||||
}
|
||||
|
||||
void rd_ohead(register struct outhead *head)
|
||||
{
|
||||
register long off;
|
||||
|
||||
OUTREAD(PARTEMIT, (char *) head, (long) SZ_HEAD);
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outhead) != SZ_HEAD)
|
||||
#endif
|
||||
{
|
||||
register char *c = (char *) head + (SZ_HEAD-4);
|
||||
|
||||
head->oh_nchar = get4(c);
|
||||
c -= 4; head->oh_nemit = get4(c);
|
||||
c -= 2; head->oh_nname = uget2(c);
|
||||
c -= 2; head->oh_nrelo = uget2(c);
|
||||
c -= 2; head->oh_nsect = uget2(c);
|
||||
c -= 2; head->oh_flags = uget2(c);
|
||||
c -= 2; head->oh_stamp = uget2(c);
|
||||
c -= 2; head->oh_magic = uget2(c);
|
||||
}
|
||||
off = OFF_RELO(*head) + rd_base;
|
||||
BEGINSEEK(PARTRELO, off);
|
||||
off += (long) head->oh_nrelo * SZ_RELO;
|
||||
BEGINSEEK(PARTNAME, off);
|
||||
off += (long) head->oh_nname * SZ_NAME;
|
||||
BEGINSEEK(PARTCHAR, off);
|
||||
#ifdef SYMDBUG
|
||||
off += head->oh_nchar;
|
||||
BEGINSEEK(PARTDBUG, off);
|
||||
#endif
|
||||
}
|
||||
|
||||
void rd_rew_relos(head)
|
||||
register struct outhead *head;
|
||||
{
|
||||
register long off = OFF_RELO(*head) + rd_base;
|
||||
|
||||
BEGINSEEK(PARTRELO, off);
|
||||
}
|
||||
|
||||
void rd_sect(sect, cnt)
|
||||
register struct outsect *sect;
|
||||
register unsigned int cnt;
|
||||
{
|
||||
register char *c = (char *) sect + cnt * SZ_SECT;
|
||||
|
||||
OUTREAD(PARTEMIT, (char *) sect, (long)cnt * SZ_SECT);
|
||||
sect += cnt;
|
||||
offcnt += cnt;
|
||||
while (cnt--) {
|
||||
sect--;
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outsect) != SZ_SECT)
|
||||
#endif
|
||||
{
|
||||
c -= 4; sect->os_lign = get4(c);
|
||||
c -= 4; sect->os_flen = get4(c);
|
||||
c -= 4; sect->os_foff = get4(c);
|
||||
}
|
||||
offset[--offcnt] = sect->os_foff + rd_base;
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outsect) != SZ_SECT)
|
||||
#endif
|
||||
{
|
||||
c -= 4; sect->os_size = get4(c);
|
||||
c -= 4; sect->os_base = get4(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rd_outsect(int s)
|
||||
{
|
||||
OUTSECT(s);
|
||||
sectionnr = s;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't have to worry about byte order here.
|
||||
*/
|
||||
void rd_emit(emit, cnt)
|
||||
char *emit;
|
||||
long cnt;
|
||||
{
|
||||
OUTREAD(PARTEMIT, emit, cnt);
|
||||
offset[sectionnr] += cnt;
|
||||
}
|
||||
|
||||
void rd_relo(relo, cnt)
|
||||
register struct outrelo *relo;
|
||||
register unsigned int cnt;
|
||||
{
|
||||
OUTREAD(PARTRELO, (char *) relo, (long) cnt * SZ_RELO);
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outrelo) != SZ_RELO)
|
||||
#endif
|
||||
{
|
||||
register char *c = (char *) relo + (long) cnt * SZ_RELO;
|
||||
|
||||
relo += cnt;
|
||||
while (cnt--) {
|
||||
relo--;
|
||||
c -= 4; relo->or_addr = get4(c);
|
||||
c -= 2; relo->or_nami = uget2(c);
|
||||
relo->or_sect = *--c;
|
||||
relo->or_type = *--c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rd_name(struct outname *name, unsigned int cnt)
|
||||
{
|
||||
|
||||
OUTREAD(PARTNAME, (char *) name, (long) cnt * SZ_NAME);
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outname) != SZ_NAME)
|
||||
#endif
|
||||
{
|
||||
register char *c = (char *) name + (long) cnt * SZ_NAME;
|
||||
|
||||
name += cnt;
|
||||
while (cnt--) {
|
||||
name--;
|
||||
c -= 4; name->on_valu = get4(c);
|
||||
c -= 2; name->on_desc = uget2(c);
|
||||
c -= 2; name->on_type = uget2(c);
|
||||
c -= 4; name->on_foff = get4(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rd_string(char *addr, long len)
|
||||
{
|
||||
OUTREAD(PARTCHAR, addr, len);
|
||||
}
|
||||
|
||||
#ifdef SYMDBUG
|
||||
void rd_dbug(char *buf, long size)
|
||||
{
|
||||
OUTREAD(PARTDBUG, buf, size);
|
||||
}
|
||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Headers for rd.c
|
||||
*/
|
||||
|
||||
#include "out.h"
|
||||
|
||||
extern void rd_string(char *addr, long len);
|
||||
extern void rd_name(struct outname name[], unsigned int cnt);
|
||||
extern int rd_fdopen(int fd);
|
||||
extern void rd_ohead(register struct outhead head[]);
|
|
@ -1,39 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <arch.h>
|
||||
#include "object.h"
|
||||
|
||||
#include "arch.h"
|
||||
#include "archiver.h"
|
||||
|
||||
int
|
||||
rd_arhdr(int fd, register struct ar_hdr *arhdr)
|
||||
{
|
||||
char buf[AR_TOTAL];
|
||||
register char *c = buf;
|
||||
register char *p = arhdr->ar_name;
|
||||
register int i;
|
||||
|
||||
i = read(fd, c, AR_TOTAL);
|
||||
if (i == 0) return 0;
|
||||
if (i != AR_TOTAL) {
|
||||
rd_fatal();
|
||||
}
|
||||
i = 14;
|
||||
while (i--) {
|
||||
*p++ = *c++;
|
||||
}
|
||||
arhdr->ar_date = ((long) get2(c)) << 16; c += 2;
|
||||
arhdr->ar_date |= ((long) get2(c)) & 0xffff; c += 2;
|
||||
arhdr->ar_uid = *c++;
|
||||
arhdr->ar_gid = *c++;
|
||||
arhdr->ar_mode = get2(c); c += 2;
|
||||
arhdr->ar_size = (long) get2(c) << 16; c += 2;
|
||||
arhdr->ar_size |= (long) get2(c) & 0xffff;
|
||||
return 1;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#define MININT (1 << (sizeof(int) * 8 - 1))
|
||||
#define MAXCHUNK (~MININT) /* Highest count we read(2). */
|
||||
/* Unfortunately, MAXCHUNK is too large with some compilers. Put it in
|
||||
an int!
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "archiver.h"
|
||||
#include "rd_bytes.h"
|
||||
|
||||
static int maxchunk = MAXCHUNK;
|
||||
|
||||
/*
|
||||
* We don't have to worry about byte order here.
|
||||
* Just read "cnt" bytes from file-descriptor "fd".
|
||||
*/
|
||||
void rd_bytes(int fd, char *string, long cnt)
|
||||
{
|
||||
|
||||
while (cnt) {
|
||||
register int n = cnt >= maxchunk ? maxchunk : cnt;
|
||||
|
||||
if (read(fd, string, n) != n)
|
||||
rd_fatal();
|
||||
string += n;
|
||||
cnt -= n;
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
extern void rd_bytes(int fd, char *string, long cnt);
|
|
@ -1,16 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "object.h"
|
||||
#include "rd_bytes.h"
|
||||
|
||||
unsigned int
|
||||
rd_unsigned2(int fd)
|
||||
{
|
||||
char buf[2];
|
||||
|
||||
rd_bytes(fd, buf, 2L);
|
||||
return uget2(buf);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include <system.h>
|
||||
#include "param.h"
|
||||
#include "format.h"
|
||||
|
||||
/*VARARGS*/
|
||||
/*FORMAT1v $
|
||||
%s = char *
|
||||
%l = long
|
||||
%c = int
|
||||
%[uxbo] = unsigned int
|
||||
%d = int
|
||||
$ */
|
||||
char *
|
||||
#if __STDC__
|
||||
sprint(char *buf, char *fmt, ...)
|
||||
#else
|
||||
sprint(buf, fmt, va_alist)
|
||||
char *buf, *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
#if __STDC__
|
||||
va_start(args, fmt);
|
||||
#else
|
||||
va_start(args);
|
||||
#endif
|
||||
buf[_format(buf, fmt, args)] = '\0';
|
||||
va_end(args);
|
||||
return buf;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* RCS: $Header$ */
|
||||
|
||||
#include <system.h>
|
||||
|
||||
File _sys_ftab[SYS_NOPEN] = {
|
||||
{ 0, OP_READ},
|
||||
{ 1, OP_APPEND},
|
||||
{ 2, OP_APPEND}
|
||||
};
|
||||
|
||||
File *
|
||||
_get_entry()
|
||||
{
|
||||
register File *fp;
|
||||
|
||||
for (fp = &_sys_ftab[0]; fp < &_sys_ftab[SYS_NOPEN]; fp++)
|
||||
if (fp->o_flags == 0)
|
||||
return fp;
|
||||
return (File *)0;
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* RCS: $Header$ */
|
||||
#ifndef __SYSTEM_INCLUDED__
|
||||
#define __SYSTEM_INCLUDED__
|
||||
|
||||
struct _sys_fildes {
|
||||
int o_fd; /* UNIX filedescriptor */
|
||||
int o_flags; /* flags for open; 0 if not used */
|
||||
};
|
||||
|
||||
typedef struct _sys_fildes File;
|
||||
|
||||
extern File _sys_ftab[];
|
||||
|
||||
/* flags for sys_open() */
|
||||
#define OP_READ 01
|
||||
#define OP_WRITE 02
|
||||
#define OP_APPEND 04
|
||||
|
||||
/* flags for sys_access() */
|
||||
#define AC_EXIST 00
|
||||
#define AC_READ 04
|
||||
#define AC_WRITE 02
|
||||
#define AC_EXEC 01
|
||||
|
||||
/* flags for sys_stop() */
|
||||
#define S_END 0
|
||||
#define S_EXIT 1
|
||||
#define S_ABORT 2
|
||||
|
||||
/* standard file decsriptors */
|
||||
#define STDIN &_sys_ftab[0]
|
||||
#define STDOUT &_sys_ftab[1]
|
||||
#define STDERR &_sys_ftab[2]
|
||||
|
||||
/* maximum number of open files */
|
||||
#define SYS_NOPEN 20
|
||||
|
||||
/* return value for sys_break */
|
||||
#define ILL_BREAK ((char *)0)
|
||||
|
||||
/* system's idea of block */
|
||||
#ifndef BUFSIZ
|
||||
#define BUFSIZ 1024
|
||||
#endif
|
||||
#endif /* __SYSTEM_INCLUDED__ */
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#ifndef _VARARGS_H
|
||||
#define _VARARGS_H
|
||||
|
||||
typedef char *va_list;
|
||||
# define __va_sz(mode) (((sizeof(mode) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
|
||||
# define va_dcl int va_alist;
|
||||
# define va_start(list) (list = (char *) &va_alist)
|
||||
# define va_end(list)
|
||||
# define va_arg(list,mode) (*((mode *)((list += __va_sz(mode)) - __va_sz(mode))))
|
||||
#endif /* _VARARGS_H */
|
|
@ -1,30 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include <arch.h>
|
||||
#include "object.h"
|
||||
#include "arch.h"
|
||||
#include "write.h"
|
||||
#include "wr_bytes.h"
|
||||
|
||||
void wr_arhdr(int fd, struct ar_hdr *arhdr)
|
||||
{
|
||||
char buf[AR_TOTAL];
|
||||
register char *c = buf;
|
||||
register char *p = arhdr->ar_name;
|
||||
register int i = 14;
|
||||
|
||||
while (i--) {
|
||||
*c++ = *p++;
|
||||
}
|
||||
put2((int)(arhdr->ar_date>>16),c); c += 2;
|
||||
put2((int)(arhdr->ar_date),c); c += 2;
|
||||
*c++ = arhdr->ar_uid;
|
||||
*c++ = arhdr->ar_gid;
|
||||
put2(arhdr->ar_mode,c); c += 2;
|
||||
put2((int)(arhdr->ar_size>>16),c); c += 2;
|
||||
put2((int)(arhdr->ar_size),c);
|
||||
wr_bytes(fd, buf, (long) AR_TOTAL);
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#define MININT (1 << (sizeof(int) * 8 - 1))
|
||||
#define MAXCHUNK (~MININT) /* Highest count we write(2). */
|
||||
/* Notice that MAXCHUNK itself might be too large with some compilers.
|
||||
You have to put it in an int!
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "wr_bytes.h"
|
||||
#include "archiver.h"
|
||||
|
||||
static int maxchunk = MAXCHUNK;
|
||||
|
||||
/*
|
||||
* Just write "cnt" bytes to file-descriptor "fd".
|
||||
*/
|
||||
void wr_bytes(int fd, register char *string, long cnt)
|
||||
{
|
||||
|
||||
while (cnt) {
|
||||
register int n = cnt >= maxchunk ? maxchunk : cnt;
|
||||
|
||||
if (write(fd, string, n) != n)
|
||||
wr_fatal();
|
||||
string += n;
|
||||
cnt -= n;
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
/*
|
||||
* Exported symbols of wr_bytes.c
|
||||
*/
|
||||
extern void wr_bytes(int fd, register char *string, long cnt);
|
|
@ -1,16 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "object.h"
|
||||
#include "wr_int2.h"
|
||||
#include "wr_bytes.h"
|
||||
|
||||
void wr_int2(int fd, int i)
|
||||
{
|
||||
char buf[2];
|
||||
|
||||
put2(i, buf);
|
||||
wr_bytes(fd, buf, 2L);
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
extern void wr_int2(int fd, int i);
|
|
@ -1,16 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "object.h"
|
||||
#include "wr_bytes.h"
|
||||
#include "wr_long.h"
|
||||
|
||||
void wr_long(int fd, long l)
|
||||
{
|
||||
char buf[4];
|
||||
|
||||
put4(l, buf);
|
||||
wr_bytes(fd, buf, 4L);
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
extern void wr_long(int fd, long l);
|
|
@ -1,36 +0,0 @@
|
|||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include <ranlib.h>
|
||||
#include "object.h"
|
||||
#include "wr_bytes.h"
|
||||
#include "ranlib.h"
|
||||
|
||||
void wr_ranlib(int fd, struct ranlib *ran, long cnt)
|
||||
{
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof (struct ranlib) != SZ_RAN)
|
||||
#endif
|
||||
{
|
||||
char buf[100 * SZ_RAN];
|
||||
|
||||
while (cnt) {
|
||||
register int i = (cnt > 100) ? 100 : cnt;
|
||||
register char *c = buf;
|
||||
long j = i * SZ_RAN;
|
||||
|
||||
cnt -= i;
|
||||
while (i--) {
|
||||
put4(ran->ran_off,c); c += 4;
|
||||
put4(ran->ran_pos,c); c += 4;
|
||||
ran++;
|
||||
}
|
||||
wr_bytes(fd, buf, j);
|
||||
}
|
||||
}
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
else wr_bytes(fd, (char *) ran, cnt * SZ_RAN);
|
||||
#endif
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <system.h>
|
||||
#include "write.h"
|
||||
|
||||
int
|
||||
sys_write(File *fp, char *bufptr, int nbytes)
|
||||
{
|
||||
if (! fp) return 0;
|
||||
return write(fp->o_fd, bufptr, nbytes) == nbytes;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
#include "system.h"
|
||||
extern int sys_write(File *fp, char *bufptr, int nbytes);
|
|
@ -1,10 +0,0 @@
|
|||
# Makefile for acd
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= acd
|
||||
CPPFLAGS+= -DARCH=\"`arch`\" -DDESCR=\"/usr/lib/descr\"
|
||||
LINKS+= ${BINDIR}/acd ${BINDIR}/cc
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
2701
commands/acd/acd.c
2701
commands/acd/acd.c
File diff suppressed because it is too large
Load diff
|
@ -1,4 +0,0 @@
|
|||
SCRIPTS= ackmkdep.sh
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,60 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# ackmkdep 1.1 - Generate Makefile dependencies. Author: Kees J. Bot
|
||||
#
|
||||
# Does what 'cc -M' should do, but no compiler gets it right, they all
|
||||
# strip the leading path of the '.o' file.)
|
||||
#
|
||||
# Added option to generate .depend files in subdirectories of given dir.
|
||||
# Jorrit N. Herder
|
||||
|
||||
set -e
|
||||
|
||||
case $# in
|
||||
|
||||
# Display help ...
|
||||
0)
|
||||
echo "Usage: ackmkdep 'cpp command' file ..." >&2
|
||||
echo " ackmkdep directory" >&2
|
||||
;;
|
||||
|
||||
# Create .depend files ...
|
||||
1)
|
||||
echo "Creating .depend files in $1"
|
||||
for dir in `find $1 -type d ! -name CVS ! -name .svn`
|
||||
do
|
||||
touch $dir/.depend
|
||||
done
|
||||
|
||||
;;
|
||||
|
||||
|
||||
# Get dependencies ...
|
||||
*)
|
||||
cpp="$1"; shift
|
||||
|
||||
for f
|
||||
do
|
||||
: < "$f" || exit
|
||||
|
||||
o=`expr "$f" : '\(.*\)\..*'`.o
|
||||
o=`basename $o`
|
||||
|
||||
echo
|
||||
|
||||
$cpp "$f" | \
|
||||
/usr/bin/sed -e '/^#/!d
|
||||
s/.*"\(.*\)".*/\1/
|
||||
s:^\./::' \
|
||||
-e '/^<built-in>$/d' \
|
||||
-e '/^<command.line>$/d' \
|
||||
-e "s:^:$o\: :" | \
|
||||
sort -u
|
||||
done
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
#
|
||||
# $PchId: mkdep.sh,v 1.3 1998/07/23 21:24:38 philip Exp $
|
||||
#
|
|
@ -1,4 +0,0 @@
|
|||
PROG= ackstrip
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,169 +0,0 @@
|
|||
/* strip - remove symbols. Author: Dick van Veen */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <a.out.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Strip [file] ...
|
||||
*
|
||||
* - when no file is present, a.out is assumed.
|
||||
*
|
||||
*/
|
||||
|
||||
#define A_OUT "a.out"
|
||||
#define NAME_LENGTH 128 /* max file path name */
|
||||
|
||||
char buffer[BUFSIZ]; /* used to copy executable */
|
||||
char new_file[NAME_LENGTH]; /* contains name of temporary */
|
||||
struct exec header;
|
||||
|
||||
_PROTOTYPE(int main, (int argc, char **argv));
|
||||
_PROTOTYPE(void strip, (char *file));
|
||||
_PROTOTYPE(int read_header, (int fd));
|
||||
_PROTOTYPE(int write_header, (int fd));
|
||||
_PROTOTYPE(int make_tmp, (char *new_name, char *name));
|
||||
_PROTOTYPE(int copy_file, (int fd1, int fd2, long size));
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
argv++;
|
||||
if (*argv == NULL)
|
||||
strip(A_OUT);
|
||||
else
|
||||
while (*argv != NULL) {
|
||||
strip(*argv);
|
||||
argv++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void strip(file)
|
||||
char *file;
|
||||
{
|
||||
int fd, new_fd;
|
||||
struct stat buf;
|
||||
long symb_size, relo_size;
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "can't open %s\n", file);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (read_header(fd)) {
|
||||
fprintf(stderr, "%s: not an executable file\n", file);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (header.a_syms == 0L) {
|
||||
close(fd); /* no symbol table present */
|
||||
return;
|
||||
}
|
||||
symb_size = header.a_syms;
|
||||
header.a_syms = 0L; /* remove table size */
|
||||
fstat(fd, &buf);
|
||||
relo_size = buf.st_size - (A_MINHDR + header.a_text + header.a_data + symb_size);
|
||||
new_fd = make_tmp(new_file, file);
|
||||
if (new_fd == -1) {
|
||||
fprintf(stderr, "can't create temporary file\n");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (write_header(new_fd)) {
|
||||
fprintf(stderr, "can't write temporary file\n");
|
||||
unlink(new_file);
|
||||
close(fd);
|
||||
close(new_fd);
|
||||
return;
|
||||
}
|
||||
if (copy_file(fd, new_fd, header.a_text + header.a_data)) {
|
||||
fprintf(stderr, "can't copy %s\n", file);
|
||||
unlink(new_file);
|
||||
close(fd);
|
||||
close(new_fd);
|
||||
return;
|
||||
}
|
||||
if (relo_size != 0) {
|
||||
lseek(fd, symb_size, 1);
|
||||
if (copy_file(fd, new_fd, relo_size)) {
|
||||
fprintf(stderr, "can't copy %s\n", file);
|
||||
unlink(new_file);
|
||||
close(fd);
|
||||
close(new_fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
close(new_fd);
|
||||
if (unlink(file) == -1) {
|
||||
fprintf(stderr, "can't unlink %s\n", file);
|
||||
unlink(new_file);
|
||||
return;
|
||||
}
|
||||
link(new_file, file);
|
||||
unlink(new_file);
|
||||
chmod(file, buf.st_mode);
|
||||
}
|
||||
|
||||
int read_header(fd)
|
||||
int fd;
|
||||
{
|
||||
if (read(fd, (char *) &header, A_MINHDR) != A_MINHDR) return(1);
|
||||
if (BADMAG(header)) return (1);
|
||||
if (header.a_hdrlen > sizeof(struct exec)) return (1);
|
||||
lseek(fd, 0L, SEEK_SET); /* variable size header */
|
||||
if (read(fd, (char *)&header, (int)header.a_hdrlen) != (int) header.a_hdrlen)
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int write_header(fd)
|
||||
int fd;
|
||||
{
|
||||
lseek(fd, 0L, SEEK_SET);
|
||||
if (write(fd, (char *)&header, (int)header.a_hdrlen) != (int)header.a_hdrlen)
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int make_tmp(new_name, name)
|
||||
char *new_name, *name;
|
||||
{
|
||||
int len;
|
||||
char *nameptr;
|
||||
|
||||
len = strlen(name);
|
||||
if (len + 1 > NAME_LENGTH) return(-1);
|
||||
strcpy(new_name, name);
|
||||
nameptr = strrchr(new_name, '/');
|
||||
if (nameptr == NULL) nameptr = new_name - 1;
|
||||
if (nameptr - new_name + 6 + 1 > NAME_LENGTH) return (-1);
|
||||
strcpy(nameptr + 1, "XXXXXX");
|
||||
mktemp(new_name);
|
||||
return(creat(new_name, 0777));
|
||||
}
|
||||
|
||||
int copy_file(fd1, fd2, size)
|
||||
int fd1, fd2;
|
||||
long size;
|
||||
{
|
||||
int length;
|
||||
|
||||
while (size > 0) {
|
||||
if (size < sizeof(buffer))
|
||||
length = size;
|
||||
else
|
||||
length = sizeof(buffer);
|
||||
if (read(fd1, buffer, length) != length) return(1);
|
||||
if (write(fd2, buffer, length) != length) return (1);
|
||||
size -= length;
|
||||
}
|
||||
return(0);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
# Makefile for asmconv.
|
||||
|
||||
PROG= asmconv
|
||||
SRCS= asm86.c asmconv.c parse_ack.c parse_gnu.c parse_bas.c \
|
||||
tokenize.c emit_ack.c emit_gnu.c
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,85 +0,0 @@
|
|||
/* asm86.c - 80X86 assembly intermediate Author: Kees J. Bot
|
||||
* 24 Dec 1993
|
||||
*/
|
||||
#define nil 0
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "asm86.h"
|
||||
#include "asmconv.h"
|
||||
#include "token.h"
|
||||
|
||||
expression_t *new_expr(void)
|
||||
/* Make a new cell to build an expression. */
|
||||
{
|
||||
expression_t *e;
|
||||
|
||||
e= allocate(nil, sizeof(*e));
|
||||
e->operator= -1;
|
||||
e->left= e->middle= e->right= nil;
|
||||
e->name= nil;
|
||||
e->magic= 31624;
|
||||
return e;
|
||||
}
|
||||
|
||||
void del_expr(expression_t *e)
|
||||
/* Delete an expression tree. */
|
||||
{
|
||||
if (e != nil) {
|
||||
assert(e->magic == 31624);
|
||||
e->magic= 0;
|
||||
deallocate(e->name);
|
||||
del_expr(e->left);
|
||||
del_expr(e->middle);
|
||||
del_expr(e->right);
|
||||
deallocate(e);
|
||||
}
|
||||
}
|
||||
|
||||
asm86_t *new_asm86(void)
|
||||
/* Make a new cell to hold an 80X86 instruction. */
|
||||
{
|
||||
asm86_t *a;
|
||||
|
||||
a= allocate(nil, sizeof(*a));
|
||||
a->opcode= -1;
|
||||
get_file(&a->file, &a->line);
|
||||
a->optype= -1;
|
||||
a->oaz= 0;
|
||||
a->rep= ONCE;
|
||||
a->seg= DEFSEG;
|
||||
a->args= nil;
|
||||
a->magic= 37937;
|
||||
return a;
|
||||
}
|
||||
|
||||
void del_asm86(asm86_t *a)
|
||||
/* Delete an 80X86 instruction. */
|
||||
{
|
||||
assert(a != nil);
|
||||
assert(a->magic == 37937);
|
||||
a->magic= 0;
|
||||
del_expr(a->args);
|
||||
deallocate(a);
|
||||
}
|
||||
|
||||
int isregister(const char *name)
|
||||
/* True if the string is a register name. Return its size. */
|
||||
{
|
||||
static char *regs[] = {
|
||||
"al", "bl", "cl", "dl", "ah", "bh", "ch", "dh",
|
||||
"ax", "bx", "cx", "dx", "si", "di", "bp", "sp",
|
||||
"cs", "ds", "es", "fs", "gs", "ss",
|
||||
"eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
|
||||
"cr0", "cr1", "cr2", "cr3",
|
||||
"st",
|
||||
};
|
||||
int reg;
|
||||
|
||||
for (reg= 0; reg < arraysize(regs); reg++) {
|
||||
if (strcmp(name, regs[reg]) == 0) {
|
||||
return reg < 8 ? 1 : reg < 22 ? 2 : 4;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
/* asm86.h - 80X86 assembly intermediate Author: Kees J. Bot
|
||||
* 27 Jun 1993
|
||||
*/
|
||||
|
||||
typedef enum opcode { /* 80486 opcodes, from the i486 reference manual.
|
||||
* Synonyms left out, some new words invented.
|
||||
*/
|
||||
DOT_ALIGN,
|
||||
DOT_ASCII, DOT_ASCIZ,
|
||||
DOT_ASSERT, /* Pseudo's invented */
|
||||
DOT_BASE,
|
||||
DOT_COMM, DOT_LCOMM,
|
||||
DOT_DATA1,
|
||||
DOT_DATA2,
|
||||
DOT_DATA4,
|
||||
DOT_DEFINE, DOT_EXTERN,
|
||||
DOT_EQU,
|
||||
DOT_FILE, DOT_LINE,
|
||||
DOT_LABEL,
|
||||
DOT_LIST, DOT_NOLIST,
|
||||
DOT_SPACE,
|
||||
DOT_SYMB,
|
||||
DOT_TEXT, DOT_ROM, DOT_DATA, DOT_BSS, DOT_END,
|
||||
DOT_USE16, DOT_USE32,
|
||||
AAA,
|
||||
AAD,
|
||||
AAM,
|
||||
AAS,
|
||||
ADC,
|
||||
ADD,
|
||||
AND,
|
||||
ARPL,
|
||||
BOUND,
|
||||
BSF,
|
||||
BSR,
|
||||
BSWAP,
|
||||
BT,
|
||||
BTC,
|
||||
BTR,
|
||||
BTS,
|
||||
CALL, CALLF, /* CALLF added */
|
||||
CBW,
|
||||
CLC,
|
||||
CLD,
|
||||
CLI,
|
||||
CLTS,
|
||||
CMC,
|
||||
CMP,
|
||||
CMPS,
|
||||
CMPXCHG,
|
||||
CWD,
|
||||
DAA,
|
||||
DAS,
|
||||
DEC,
|
||||
DIV,
|
||||
ENTER,
|
||||
F2XM1,
|
||||
FABS,
|
||||
FADD, FADDD, FADDS, FADDP, FIADDL, FIADDS,
|
||||
FBLD,
|
||||
FBSTP,
|
||||
FCHS,
|
||||
FCLEX,
|
||||
FCOMD, FCOMS, FCOMPD, FCOMPS, FCOMPP,
|
||||
FCOS,
|
||||
FDECSTP,
|
||||
FDIVD, FDIVS, FDIVP, FIDIVL, FIDIVS,
|
||||
FDIVRD, FDIVRS, FDIVRP, FIDIVRL, FIDIVRS,
|
||||
FFREE,
|
||||
FICOM, FICOMP,
|
||||
FILDQ, FILDL, FILDS,
|
||||
FINCSTP,
|
||||
FINIT,
|
||||
FISTL, FISTS, FISTP,
|
||||
FLDX, FLDD, FLDS,
|
||||
FLD1, FLDL2T, FLDL2E, FLDPI, FLDLG2, FLDLN2, FLDZ,
|
||||
FLDCW,
|
||||
FLDENV,
|
||||
FMULD, FMULS, FMULP, FIMULL, FIMULS,
|
||||
FNOP,
|
||||
FPATAN,
|
||||
FPREM,
|
||||
FPREM1,
|
||||
FPTAN,
|
||||
FRNDINT,
|
||||
FRSTOR,
|
||||
FSAVE,
|
||||
FSCALE,
|
||||
FSIN,
|
||||
FSINCOS,
|
||||
FSQRT,
|
||||
FSTD, FSTS, FSTP, FSTPX, FSTPD, FSTPS,
|
||||
FSTCW,
|
||||
FSTENV,
|
||||
FSTSW,
|
||||
FSUBD, FSUBS, FSUBP, FISUBL, FISUBS,
|
||||
FSUBRD, FSUBRS, FSUBPR, FISUBRL, FISUBRS,
|
||||
FTST,
|
||||
FUCOM, FUCOMP, FUCOMPP,
|
||||
FXAM,
|
||||
FXCH,
|
||||
FXTRACT,
|
||||
FYL2X,
|
||||
FYL2XP1,
|
||||
HLT,
|
||||
IDIV,
|
||||
IMUL,
|
||||
IN,
|
||||
INC,
|
||||
INS,
|
||||
INT, INTO,
|
||||
INVD,
|
||||
INVLPG,
|
||||
IRET, IRETD,
|
||||
JA, JAE, JB, JBE, JCXZ, JE, JG, JGE, JL,
|
||||
JLE, JNE, JNO, JNP, JNS, JO, JP, JS,
|
||||
JMP, JMPF, /* JMPF added */
|
||||
LAHF,
|
||||
LAR,
|
||||
LEA,
|
||||
LEAVE,
|
||||
LGDT, LIDT,
|
||||
LGS, LSS, LDS, LES, LFS,
|
||||
LLDT,
|
||||
LMSW,
|
||||
LOCK,
|
||||
LODS,
|
||||
LOOP, LOOPE, LOOPNE,
|
||||
LSL,
|
||||
LTR,
|
||||
MOV,
|
||||
MOVS,
|
||||
MOVSX,
|
||||
MOVSXB,
|
||||
MOVZX,
|
||||
MOVZXB,
|
||||
MUL,
|
||||
NEG,
|
||||
NOP,
|
||||
NOT,
|
||||
OR,
|
||||
OUT,
|
||||
OUTS,
|
||||
POP,
|
||||
POPA,
|
||||
POPF,
|
||||
PUSH,
|
||||
PUSHA,
|
||||
PUSHF,
|
||||
RCL, RCR, ROL, ROR,
|
||||
RET, RETF, /* RETF added */
|
||||
SAHF,
|
||||
SAL, SAR, SHL, SHR,
|
||||
SBB,
|
||||
SCAS,
|
||||
SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL,
|
||||
SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS,
|
||||
SGDT, SIDT,
|
||||
SHLD,
|
||||
SHRD,
|
||||
SLDT,
|
||||
SMSW,
|
||||
STC,
|
||||
STD,
|
||||
STI,
|
||||
STOS,
|
||||
STR,
|
||||
SUB,
|
||||
TEST,
|
||||
VERR, VERW,
|
||||
WAIT,
|
||||
WBINVD,
|
||||
XADD,
|
||||
XCHG,
|
||||
XLAT,
|
||||
XOR
|
||||
} opcode_t;
|
||||
|
||||
#define is_pseudo(o) ((o) <= DOT_USE32)
|
||||
#define N_OPCODES ((int) XOR + 1)
|
||||
|
||||
#define OPZ 0x01 /* Operand size prefix. */
|
||||
#define ADZ 0x02 /* Address size prefix. */
|
||||
|
||||
typedef enum optype {
|
||||
PSEUDO, JUMP, BYTE, WORD, OWORD /* Ordered list! */
|
||||
} optype_t;
|
||||
|
||||
typedef enum repeat {
|
||||
ONCE, REP, REPE, REPNE
|
||||
} repeat_t;
|
||||
|
||||
typedef enum segment {
|
||||
DEFSEG, CSEG, DSEG, ESEG, FSEG, GSEG, SSEG
|
||||
} segment_t;
|
||||
|
||||
typedef struct expression {
|
||||
int operator;
|
||||
struct expression *left, *middle, *right;
|
||||
char *name;
|
||||
size_t len;
|
||||
unsigned magic;
|
||||
} expression_t;
|
||||
|
||||
typedef struct asm86 {
|
||||
opcode_t opcode; /* DOT_TEXT, MOV, ... */
|
||||
char *file; /* Name of the file it is found in. */
|
||||
long line; /* Line number. */
|
||||
optype_t optype; /* Type of operands: byte, word... */
|
||||
int oaz; /* Operand/address size prefix? */
|
||||
repeat_t rep; /* Repeat prefix used on this instr. */
|
||||
segment_t seg; /* Segment override. */
|
||||
expression_t *args; /* Arguments in ACK order. */
|
||||
unsigned magic;
|
||||
} asm86_t;
|
||||
|
||||
expression_t *new_expr(void);
|
||||
void del_expr(expression_t *a);
|
||||
asm86_t *new_asm86(void);
|
||||
void del_asm86(asm86_t *a);
|
||||
int isregister(const char *name);
|
||||
|
||||
/*
|
||||
* Format of the arguments of the asm86_t structure:
|
||||
*
|
||||
*
|
||||
* ACK assembly operands expression_t cell:
|
||||
* or part of operand: {operator, left, middle, right, name, len}
|
||||
*
|
||||
* [expr] {'[', nil, expr, nil}
|
||||
* word {'W', nil, nil, nil, word}
|
||||
* "string" {'S', nil, nil, nil, "string", strlen("string")}
|
||||
* label = expr {'=', nil, expr, nil, label}
|
||||
* expr * expr {'*', expr, nil, expr}
|
||||
* - expr {'-', nil, expr, nil}
|
||||
* (memory) {'(', nil, memory, nil}
|
||||
* offset(base)(index*n) {'O', offset, base, index*n}
|
||||
* base {'B', nil, nil, nil, base}
|
||||
* index*4 {'4', nil, nil, nil, index}
|
||||
* operand, oplist {',', operand, nil, oplist}
|
||||
* label : {':', nil, nil, nil, label}
|
||||
*
|
||||
* The precedence of operators is ignored. The expression is simply copied
|
||||
* as is, including parentheses. Problems like missing operators in the
|
||||
* target language will have to be handled by rewriting the source language.
|
||||
* 16-bit or 32-bit registers must be used where they are required by the
|
||||
* target assembler even though ACK makes no difference between 'ax' and
|
||||
* 'eax'. Asmconv is smart enough to transform compiler output. Human made
|
||||
* assembly can be fixed up to be transformable.
|
||||
*/
|
|
@ -1,157 +0,0 @@
|
|||
/* asmconv 1.11 - convert 80X86 assembly Author: Kees J. Bot
|
||||
* 24 Dec 1993
|
||||
*/
|
||||
static char version[] = "1.11";
|
||||
|
||||
#define nil 0
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "asmconv.h"
|
||||
#include "asm86.h"
|
||||
#include "languages.h"
|
||||
|
||||
void fatal(char *label)
|
||||
{
|
||||
fprintf(stderr, "asmconv: %s: %s\n", label, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void *allocate(void *mem, size_t size)
|
||||
/* A checked malloc/realloc(). Yes, I know ISO C allows realloc(NULL, size). */
|
||||
{
|
||||
mem= mem == nil ? malloc(size) : realloc(mem, size);
|
||||
if (mem == nil) fatal("malloc()");
|
||||
return mem;
|
||||
}
|
||||
|
||||
void deallocate(void *mem)
|
||||
/* Free a malloc()d cell. (Yes I know ISO C allows free(NULL) */
|
||||
{
|
||||
if (mem != nil) free(mem);
|
||||
}
|
||||
|
||||
char *copystr(const char *s)
|
||||
{
|
||||
char *c;
|
||||
|
||||
c= allocate(nil, (strlen(s) + 1) * sizeof(s[0]));
|
||||
strcpy(c, s);
|
||||
return c;
|
||||
}
|
||||
|
||||
int isanumber(const char *s)
|
||||
/* True if s can be turned into a number. */
|
||||
{
|
||||
char *end;
|
||||
|
||||
(void) strtol(s, &end, 0);
|
||||
return end != s && *end == 0;
|
||||
}
|
||||
|
||||
/* "Invisible" globals. */
|
||||
int asm_mode32= (sizeof(int) == 4);
|
||||
int err_code= EXIT_SUCCESS;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void (*parse_init)(char *file);
|
||||
asm86_t *(*get_instruction)(void);
|
||||
void (*emit_init)(char *file, const char *banner);
|
||||
void (*emit_instruction)(asm86_t *instr);
|
||||
char *lang_parse, *lang_emit, *input_file, *output_file;
|
||||
asm86_t *instr;
|
||||
char banner[80];
|
||||
|
||||
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'm') {
|
||||
if (strcmp(argv[1], "-mi86") == 0) {
|
||||
set_use16();
|
||||
} else
|
||||
if (strcmp(argv[1], "-mi386") == 0) {
|
||||
set_use32();
|
||||
} else {
|
||||
fprintf(stderr, "asmconv: '%s': unknown machine\n",
|
||||
argv[1]+2);
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc < 3 || argc > 5) {
|
||||
fprintf(stderr,
|
||||
"Usage: asmconv <input-type> <output-type> [input-file [output-file]]\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
lang_parse= argv[1];
|
||||
lang_emit= argv[2];
|
||||
input_file= argc < 4 ? nil : argv[3];
|
||||
output_file= argc < 5 ? nil : argv[4];
|
||||
|
||||
/* Choose the parsing routines. */
|
||||
if (strcmp(lang_parse, "ack") == 0) {
|
||||
/* Standard ACK. */
|
||||
parse_init= ack_parse_init;
|
||||
get_instruction= ack_get_instruction;
|
||||
} else
|
||||
if (strcmp(lang_parse, "ncc") == 0) {
|
||||
/* ACK Xenix assembly, a black sheep among ACK assemblies. */
|
||||
parse_init= ncc_parse_init;
|
||||
get_instruction= ncc_get_instruction;
|
||||
} else
|
||||
if (strcmp(lang_parse, "gnu") == 0) {
|
||||
/* GNU assembly. Parser by R.S. Veldema. */
|
||||
parse_init= gnu_parse_init;
|
||||
get_instruction= gnu_get_instruction;
|
||||
} else
|
||||
if (strcmp(lang_parse, "bas") == 0) {
|
||||
/* Bruce Evans' assembler. */
|
||||
parse_init= bas_parse_init;
|
||||
get_instruction= bas_get_instruction;
|
||||
} else {
|
||||
fprintf(stderr, "asmconv: '%s': unknown input language\n",
|
||||
lang_parse);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Choose the output language. */
|
||||
if (strcmp(lang_emit, "ack") == 0) {
|
||||
/* Standard ACK. */
|
||||
emit_init= ack_emit_init;
|
||||
emit_instruction= ack_emit_instruction;
|
||||
} else
|
||||
if (strcmp(lang_emit, "ncc") == 0) {
|
||||
/* ACK Xenix assembly, can be read by BAS and the 8086 ACK
|
||||
* ANSI C compiler. (Allows us to compile the Boot Monitor.)
|
||||
*/
|
||||
emit_init= ncc_emit_init;
|
||||
emit_instruction= ncc_emit_instruction;
|
||||
} else
|
||||
if (strcmp(lang_emit, "gnu") == 0) {
|
||||
/* GNU assembler. So we can assemble the ACK stuff among the
|
||||
* kernel sources and in the library.
|
||||
*/
|
||||
emit_init= gnu_emit_init;
|
||||
emit_instruction= gnu_emit_instruction;
|
||||
} else {
|
||||
fprintf(stderr, "asmconv: '%s': unknown output language\n",
|
||||
lang_emit);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sprintf(banner, "Translated from %s to %s by asmconv %s",
|
||||
lang_parse, lang_emit, version);
|
||||
|
||||
(*parse_init)(input_file);
|
||||
(*emit_init)(output_file, banner);
|
||||
for (;;) {
|
||||
instr= (*get_instruction)();
|
||||
(*emit_instruction)(instr);
|
||||
if (instr == nil) break;
|
||||
del_asm86(instr);
|
||||
}
|
||||
exit(err_code);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/* asmconv.h - shared functions Author: Kees J. Bot
|
||||
* 19 Dec 1993
|
||||
*/
|
||||
|
||||
#define arraysize(a) (sizeof(a)/sizeof((a)[0]))
|
||||
#define arraylimit(a) ((a) + arraysize(a))
|
||||
#define between(a, c, z) \
|
||||
((unsigned)((c) - (a)) <= (unsigned)((z) - (a)))
|
||||
|
||||
void *allocate(void *mem, size_t size);
|
||||
void deallocate(void *mem);
|
||||
void fatal(char *label);
|
||||
char *copystr(const char *s);
|
||||
int isanumber(const char *s);
|
||||
|
||||
extern int asm_mode32; /* In 32 bit mode if true. */
|
||||
|
||||
#define use16() (!asm_mode32)
|
||||
#define use32() ((int) asm_mode32)
|
||||
#define set_use16() ((void) (asm_mode32= 0))
|
||||
#define set_use32() ((void) (asm_mode32= 1))
|
||||
|
||||
extern int err_code; /* Exit code. */
|
||||
#define set_error() ((void) (err_code= EXIT_FAILURE))
|
|
@ -1,621 +0,0 @@
|
|||
/* emit_ack.c - emit ACK assembly Author: Kees J. Bot
|
||||
* emit NCC assembly 27 Dec 1993
|
||||
*/
|
||||
#define nil 0
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "asmconv.h"
|
||||
#include "token.h"
|
||||
#include "asm86.h"
|
||||
#include "languages.h"
|
||||
|
||||
typedef struct mnemonic { /* ACK as86 mnemonics translation table. */
|
||||
opcode_t opcode;
|
||||
char *name;
|
||||
} mnemonic_t;
|
||||
|
||||
static mnemonic_t mnemtab[] = {
|
||||
{ AAA, "aaa" },
|
||||
{ AAD, "aad" },
|
||||
{ AAM, "aam" },
|
||||
{ AAS, "aas" },
|
||||
{ ADC, "adc%" },
|
||||
{ ADD, "add%" },
|
||||
{ AND, "and%" },
|
||||
{ ARPL, "arpl" },
|
||||
{ BOUND, "bound" },
|
||||
{ BSF, "bsf" },
|
||||
{ BSR, "bsr" },
|
||||
{ BSWAP, "bswap" },
|
||||
{ BT, "bt" },
|
||||
{ BTC, "btc" },
|
||||
{ BTR, "btr" },
|
||||
{ BTS, "bts" },
|
||||
{ CALL, "call" },
|
||||
{ CALLF, "callf" },
|
||||
{ CBW, "cbw" },
|
||||
{ CLC, "clc" },
|
||||
{ CLD, "cld" },
|
||||
{ CLI, "cli" },
|
||||
{ CLTS, "clts" },
|
||||
{ CMC, "cmc" },
|
||||
{ CMP, "cmp%" },
|
||||
{ CMPS, "cmps%" },
|
||||
{ CMPXCHG, "cmpxchg" },
|
||||
{ CWD, "cwd" },
|
||||
{ DAA, "daa" },
|
||||
{ DAS, "das" },
|
||||
{ DEC, "dec%" },
|
||||
{ DIV, "div%" },
|
||||
{ DOT_ALIGN, ".align" },
|
||||
{ DOT_ASCII, ".ascii" },
|
||||
{ DOT_ASCIZ, ".asciz" },
|
||||
{ DOT_ASSERT, ".assert" },
|
||||
{ DOT_BASE, ".base" },
|
||||
{ DOT_BSS, ".sect .bss" },
|
||||
{ DOT_COMM, ".comm" },
|
||||
{ DOT_DATA, ".sect .data" },
|
||||
{ DOT_DATA1, ".data1" },
|
||||
{ DOT_DATA2, ".data2" },
|
||||
{ DOT_DATA4, ".data4" },
|
||||
{ DOT_DEFINE, ".define" },
|
||||
{ DOT_END, ".sect .end" },
|
||||
{ DOT_EXTERN, ".extern" },
|
||||
{ DOT_FILE, ".file" },
|
||||
{ DOT_LCOMM, ".comm" },
|
||||
{ DOT_LINE, ".line" },
|
||||
{ DOT_LIST, ".list" },
|
||||
{ DOT_NOLIST, ".nolist" },
|
||||
{ DOT_ROM, ".sect .rom" },
|
||||
{ DOT_SPACE, ".space" },
|
||||
{ DOT_SYMB, ".symb" },
|
||||
{ DOT_TEXT, ".sect .text" },
|
||||
{ DOT_USE16, ".use16" },
|
||||
{ DOT_USE32, ".use32" },
|
||||
{ ENTER, "enter" },
|
||||
{ F2XM1, "f2xm1" },
|
||||
{ FABS, "fabs" },
|
||||
{ FADD, "fadd" },
|
||||
{ FADDD, "faddd" },
|
||||
{ FADDP, "faddp" },
|
||||
{ FADDS, "fadds" },
|
||||
{ FBLD, "fbld" },
|
||||
{ FBSTP, "fbstp" },
|
||||
{ FCHS, "fchs" },
|
||||
{ FCLEX, "fclex" },
|
||||
{ FCOMD, "fcomd" },
|
||||
{ FCOMPD, "fcompd" },
|
||||
{ FCOMPP, "fcompp" },
|
||||
{ FCOMPS, "fcomps" },
|
||||
{ FCOMS, "fcoms" },
|
||||
{ FCOS, "fcos" },
|
||||
{ FDECSTP, "fdecstp" },
|
||||
{ FDIVD, "fdivd" },
|
||||
{ FDIVP, "fdivp" },
|
||||
{ FDIVRD, "fdivrd" },
|
||||
{ FDIVRP, "fdivrp" },
|
||||
{ FDIVRS, "fdivrs" },
|
||||
{ FDIVS, "fdivs" },
|
||||
{ FFREE, "ffree" },
|
||||
{ FIADDL, "fiaddl" },
|
||||
{ FIADDS, "fiadds" },
|
||||
{ FICOM, "ficom" },
|
||||
{ FICOMP, "ficomp" },
|
||||
{ FIDIVL, "fidivl" },
|
||||
{ FIDIVRL, "fidivrl" },
|
||||
{ FIDIVRS, "fidivrs" },
|
||||
{ FIDIVS, "fidivs" },
|
||||
{ FILDL, "fildl" },
|
||||
{ FILDQ, "fildq" },
|
||||
{ FILDS, "filds" },
|
||||
{ FIMULL, "fimull" },
|
||||
{ FIMULS, "fimuls" },
|
||||
{ FINCSTP, "fincstp" },
|
||||
{ FINIT, "finit" },
|
||||
{ FISTL, "fistl" },
|
||||
{ FISTP, "fistp" },
|
||||
{ FISTS, "fists" },
|
||||
{ FISUBL, "fisubl" },
|
||||
{ FISUBRL, "fisubrl" },
|
||||
{ FISUBRS, "fisubrs" },
|
||||
{ FISUBS, "fisubs" },
|
||||
{ FLD1, "fld1" },
|
||||
{ FLDCW, "fldcw" },
|
||||
{ FLDD, "fldd" },
|
||||
{ FLDENV, "fldenv" },
|
||||
{ FLDL2E, "fldl2e" },
|
||||
{ FLDL2T, "fldl2t" },
|
||||
{ FLDLG2, "fldlg2" },
|
||||
{ FLDLN2, "fldln2" },
|
||||
{ FLDPI, "fldpi" },
|
||||
{ FLDS, "flds" },
|
||||
{ FLDX, "fldx" },
|
||||
{ FLDZ, "fldz" },
|
||||
{ FMULD, "fmuld" },
|
||||
{ FMULP, "fmulp" },
|
||||
{ FMULS, "fmuls" },
|
||||
{ FNOP, "fnop" },
|
||||
{ FPATAN, "fpatan" },
|
||||
{ FPREM, "fprem" },
|
||||
{ FPREM1, "fprem1" },
|
||||
{ FPTAN, "fptan" },
|
||||
{ FRNDINT, "frndint" },
|
||||
{ FRSTOR, "frstor" },
|
||||
{ FSAVE, "fsave" },
|
||||
{ FSCALE, "fscale" },
|
||||
{ FSIN, "fsin" },
|
||||
{ FSINCOS, "fsincos" },
|
||||
{ FSQRT, "fsqrt" },
|
||||
{ FSTCW, "fstcw" },
|
||||
{ FSTD, "fstd" },
|
||||
{ FSTENV, "fstenv" },
|
||||
{ FSTPD, "fstpd" },
|
||||
{ FSTPS, "fstps" },
|
||||
{ FSTPX, "fstpx" },
|
||||
{ FSTS, "fsts" },
|
||||
{ FSTSW, "fstsw" },
|
||||
{ FSUBD, "fsubd" },
|
||||
{ FSUBP, "fsubp" },
|
||||
{ FSUBPR, "fsubpr" },
|
||||
{ FSUBRD, "fsubrd" },
|
||||
{ FSUBRS, "fsubrs" },
|
||||
{ FSUBS, "fsubs" },
|
||||
{ FTST, "ftst" },
|
||||
{ FUCOM, "fucom" },
|
||||
{ FUCOMP, "fucomp" },
|
||||
{ FUCOMPP, "fucompp" },
|
||||
{ FXAM, "fxam" },
|
||||
{ FXCH, "fxch" },
|
||||
{ FXTRACT, "fxtract" },
|
||||
{ FYL2X, "fyl2x" },
|
||||
{ FYL2XP1, "fyl2xp1" },
|
||||
{ HLT, "hlt" },
|
||||
{ IDIV, "idiv%" },
|
||||
{ IMUL, "imul%" },
|
||||
{ IN, "in%" },
|
||||
{ INC, "inc%" },
|
||||
{ INS, "ins%" },
|
||||
{ INT, "int" },
|
||||
{ INTO, "into" },
|
||||
{ INVD, "invd" },
|
||||
{ INVLPG, "invlpg" },
|
||||
{ IRET, "iret" },
|
||||
{ IRETD, "iretd" },
|
||||
{ JA, "ja" },
|
||||
{ JAE, "jae" },
|
||||
{ JB, "jb" },
|
||||
{ JBE, "jbe" },
|
||||
{ JCXZ, "jcxz" },
|
||||
{ JE, "je" },
|
||||
{ JG, "jg" },
|
||||
{ JGE, "jge" },
|
||||
{ JL, "jl" },
|
||||
{ JLE, "jle" },
|
||||
{ JMP, "jmp" },
|
||||
{ JMPF, "jmpf" },
|
||||
{ JNE, "jne" },
|
||||
{ JNO, "jno" },
|
||||
{ JNP, "jnp" },
|
||||
{ JNS, "jns" },
|
||||
{ JO, "jo" },
|
||||
{ JP, "jp" },
|
||||
{ JS, "js" },
|
||||
{ LAHF, "lahf" },
|
||||
{ LAR, "lar" },
|
||||
{ LDS, "lds" },
|
||||
{ LEA, "lea" },
|
||||
{ LEAVE, "leave" },
|
||||
{ LES, "les" },
|
||||
{ LFS, "lfs" },
|
||||
{ LGDT, "lgdt" },
|
||||
{ LGS, "lgs" },
|
||||
{ LIDT, "lidt" },
|
||||
{ LLDT, "lldt" },
|
||||
{ LMSW, "lmsw" },
|
||||
{ LOCK, "lock" },
|
||||
{ LODS, "lods%" },
|
||||
{ LOOP, "loop" },
|
||||
{ LOOPE, "loope" },
|
||||
{ LOOPNE, "loopne" },
|
||||
{ LSL, "lsl" },
|
||||
{ LSS, "lss" },
|
||||
{ LTR, "ltr" },
|
||||
{ MOV, "mov%" },
|
||||
{ MOVS, "movs%" },
|
||||
{ MOVSX, "movsx" },
|
||||
{ MOVSXB, "movsxb" },
|
||||
{ MOVZX, "movzx" },
|
||||
{ MOVZXB, "movzxb" },
|
||||
{ MUL, "mul%" },
|
||||
{ NEG, "neg%" },
|
||||
{ NOP, "nop" },
|
||||
{ NOT, "not%" },
|
||||
{ OR, "or%" },
|
||||
{ OUT, "out%" },
|
||||
{ OUTS, "outs%" },
|
||||
{ POP, "pop" },
|
||||
{ POPA, "popa" },
|
||||
{ POPF, "popf" },
|
||||
{ PUSH, "push" },
|
||||
{ PUSHA, "pusha" },
|
||||
{ PUSHF, "pushf" },
|
||||
{ RCL, "rcl%" },
|
||||
{ RCR, "rcr%" },
|
||||
{ RET, "ret" },
|
||||
{ RETF, "retf" },
|
||||
{ ROL, "rol%" },
|
||||
{ ROR, "ror%" },
|
||||
{ SAHF, "sahf" },
|
||||
{ SAL, "sal%" },
|
||||
{ SAR, "sar%" },
|
||||
{ SBB, "sbb%" },
|
||||
{ SCAS, "scas%" },
|
||||
{ SETA, "seta" },
|
||||
{ SETAE, "setae" },
|
||||
{ SETB, "setb" },
|
||||
{ SETBE, "setbe" },
|
||||
{ SETE, "sete" },
|
||||
{ SETG, "setg" },
|
||||
{ SETGE, "setge" },
|
||||
{ SETL, "setl" },
|
||||
{ SETLE, "setle" },
|
||||
{ SETNE, "setne" },
|
||||
{ SETNO, "setno" },
|
||||
{ SETNP, "setnp" },
|
||||
{ SETNS, "setns" },
|
||||
{ SETO, "seto" },
|
||||
{ SETP, "setp" },
|
||||
{ SETS, "sets" },
|
||||
{ SGDT, "sgdt" },
|
||||
{ SHL, "shl%" },
|
||||
{ SHLD, "shld" },
|
||||
{ SHR, "shr%" },
|
||||
{ SHRD, "shrd" },
|
||||
{ SIDT, "sidt" },
|
||||
{ SLDT, "sldt" },
|
||||
{ SMSW, "smsw" },
|
||||
{ STC, "stc" },
|
||||
{ STD, "std" },
|
||||
{ STI, "sti" },
|
||||
{ STOS, "stos%" },
|
||||
{ STR, "str" },
|
||||
{ SUB, "sub%" },
|
||||
{ TEST, "test%" },
|
||||
{ VERR, "verr" },
|
||||
{ VERW, "verw" },
|
||||
{ WAIT, "wait" },
|
||||
{ WBINVD, "wbinvd" },
|
||||
{ XADD, "xadd" },
|
||||
{ XCHG, "xchg%" },
|
||||
{ XLAT, "xlat" },
|
||||
{ XOR, "xor%" },
|
||||
};
|
||||
|
||||
#define farjmp(o) ((o) == JMPF || (o) == CALLF)
|
||||
|
||||
static FILE *ef;
|
||||
static long eline= 1;
|
||||
static char *efile;
|
||||
static char *orig_efile;
|
||||
static char *opcode2name_tab[N_OPCODES];
|
||||
static enum dialect { ACK, NCC } dialect= ACK;
|
||||
|
||||
static void ack_putchar(int c)
|
||||
/* LOOK, this programmer checks the return code of putc! What an idiot, noone
|
||||
* does that!
|
||||
*/
|
||||
{
|
||||
if (putc(c, ef) == EOF) fatal(orig_efile);
|
||||
}
|
||||
|
||||
static void ack_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (vfprintf(ef, fmt, ap) == EOF) fatal(orig_efile);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void ack_emit_init(char *file, const char *banner)
|
||||
/* Prepare producing an ACK assembly file. */
|
||||
{
|
||||
mnemonic_t *mp;
|
||||
|
||||
if (file == nil) {
|
||||
file= "stdout";
|
||||
ef= stdout;
|
||||
} else {
|
||||
if ((ef= fopen(file, "w")) == nil) fatal(file);
|
||||
}
|
||||
orig_efile= file;
|
||||
efile= file;
|
||||
ack_printf("! %s", banner);
|
||||
if (dialect == ACK) {
|
||||
/* Declare the four sections used under Minix. */
|
||||
ack_printf(
|
||||
"\n.sect .text; .sect .rom; .sect .data; .sect .bss\n.sect .text");
|
||||
}
|
||||
|
||||
/* Initialize the opcode to mnemonic translation table. */
|
||||
for (mp= mnemtab; mp < arraylimit(mnemtab); mp++) {
|
||||
assert(opcode2name_tab[mp->opcode] == nil);
|
||||
opcode2name_tab[mp->opcode]= mp->name;
|
||||
}
|
||||
}
|
||||
|
||||
#define opcode2name(op) (opcode2name_tab[op] + 0)
|
||||
|
||||
static void ack_put_string(const char *s, size_t n)
|
||||
/* Emit a string with weird characters quoted. */
|
||||
{
|
||||
while (n > 0) {
|
||||
int c= *s;
|
||||
|
||||
if (c < ' ' || c > 0177) {
|
||||
ack_printf("\\%03o", c & 0xFF);
|
||||
} else
|
||||
if (c == '"' || c == '\\') {
|
||||
ack_printf("\\%c", c);
|
||||
} else {
|
||||
ack_putchar(c);
|
||||
}
|
||||
s++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
static void ack_put_expression(asm86_t *a, expression_t *e, int deref)
|
||||
/* Send an expression, i.e. instruction operands, to the output file. Deref
|
||||
* is true when the rewrite for the ncc dialect may be made.
|
||||
*/
|
||||
{
|
||||
assert(e != nil);
|
||||
|
||||
switch (e->operator) {
|
||||
case ',':
|
||||
if (dialect == NCC && farjmp(a->opcode)) {
|
||||
/* ACK jmpf seg:off -> NCC jmpf off,seg */
|
||||
ack_put_expression(a, e->right, deref);
|
||||
ack_printf(", ");
|
||||
ack_put_expression(a, e->left, deref);
|
||||
} else {
|
||||
ack_put_expression(a, e->left, deref);
|
||||
ack_printf(farjmp(a->opcode) ? ":" : ", ");
|
||||
ack_put_expression(a, e->right, deref);
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
if (deref && a->optype == JUMP) ack_putchar('@');
|
||||
if (e->left != nil) ack_put_expression(a, e->left, 0);
|
||||
if (e->middle != nil) ack_put_expression(a, e->middle, 0);
|
||||
if (e->right != nil) ack_put_expression(a, e->right, 0);
|
||||
break;
|
||||
case '(':
|
||||
if (deref && a->optype == JUMP) ack_putchar('@');
|
||||
if (!deref) ack_putchar('(');
|
||||
ack_put_expression(a, e->middle, 0);
|
||||
if (!deref) ack_putchar(')');
|
||||
break;
|
||||
case 'B':
|
||||
ack_printf("(%s)", e->name);
|
||||
break;
|
||||
case '1':
|
||||
case '2':
|
||||
case '4':
|
||||
case '8':
|
||||
ack_printf((use16() && e->operator == '1')
|
||||
? "(%s)" : "(%s*%c)", e->name, e->operator);
|
||||
break;
|
||||
case '+':
|
||||
case '-':
|
||||
case '~':
|
||||
if (e->middle != nil) {
|
||||
if (deref && a->optype != JUMP) ack_putchar('#');
|
||||
ack_putchar(e->operator);
|
||||
ack_put_expression(a, e->middle, 0);
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
case '*':
|
||||
case '/':
|
||||
case '%':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case S_LEFTSHIFT:
|
||||
case S_RIGHTSHIFT:
|
||||
if (deref && a->optype != JUMP) ack_putchar('#');
|
||||
ack_put_expression(a, e->left, 0);
|
||||
if (e->operator == S_LEFTSHIFT) {
|
||||
ack_printf("<<");
|
||||
} else
|
||||
if (e->operator == S_RIGHTSHIFT) {
|
||||
ack_printf(">>");
|
||||
} else {
|
||||
ack_putchar(e->operator);
|
||||
}
|
||||
ack_put_expression(a, e->right, 0);
|
||||
break;
|
||||
case '[':
|
||||
if (deref && a->optype != JUMP) ack_putchar('#');
|
||||
ack_putchar('[');
|
||||
ack_put_expression(a, e->middle, 0);
|
||||
ack_putchar(']');
|
||||
break;
|
||||
case 'W':
|
||||
if (deref && a->optype == JUMP && isregister(e->name))
|
||||
{
|
||||
ack_printf("(%s)", e->name);
|
||||
break;
|
||||
}
|
||||
if (deref && a->optype != JUMP && !isregister(e->name)) {
|
||||
ack_putchar('#');
|
||||
}
|
||||
ack_printf("%s", e->name);
|
||||
break;
|
||||
case 'S':
|
||||
ack_putchar('"');
|
||||
ack_put_string(e->name, e->len);
|
||||
ack_putchar('"');
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"asmconv: internal error, unknown expression operator '%d'\n",
|
||||
e->operator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void ack_emit_instruction(asm86_t *a)
|
||||
/* Output one instruction and its operands. */
|
||||
{
|
||||
int same= 0;
|
||||
char *p;
|
||||
static int high_seg;
|
||||
int deref;
|
||||
|
||||
if (a == nil) {
|
||||
/* Last call */
|
||||
ack_putchar('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure the line number of the line to be emitted is ok. */
|
||||
if ((a->file != efile && strcmp(a->file, efile) != 0)
|
||||
|| a->line < eline || a->line > eline+10) {
|
||||
ack_putchar('\n');
|
||||
ack_printf("# %ld \"%s\"\n", a->line, a->file);
|
||||
efile= a->file;
|
||||
eline= a->line;
|
||||
} else {
|
||||
if (a->line == eline) {
|
||||
ack_printf("; ");
|
||||
same= 1;
|
||||
}
|
||||
while (eline < a->line) {
|
||||
ack_putchar('\n');
|
||||
eline++;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->opcode == DOT_LABEL) {
|
||||
assert(a->args->operator == ':');
|
||||
ack_printf("%s:", a->args->name);
|
||||
} else
|
||||
if (a->opcode == DOT_EQU) {
|
||||
assert(a->args->operator == '=');
|
||||
ack_printf("\t%s = ", a->args->name);
|
||||
ack_put_expression(a, a->args->middle, 0);
|
||||
} else
|
||||
if ((p= opcode2name(a->opcode)) != nil) {
|
||||
char *sep= dialect == ACK ? "" : ";";
|
||||
|
||||
if (!is_pseudo(a->opcode) && !same) ack_putchar('\t');
|
||||
|
||||
switch (a->rep) {
|
||||
case ONCE: break;
|
||||
case REP: ack_printf("rep"); break;
|
||||
case REPE: ack_printf("repe"); break;
|
||||
case REPNE: ack_printf("repne"); break;
|
||||
default: assert(0);
|
||||
}
|
||||
if (a->rep != ONCE) {
|
||||
ack_printf(dialect == ACK ? " " : "; ");
|
||||
}
|
||||
switch (a->seg) {
|
||||
case DEFSEG: break;
|
||||
case CSEG: ack_printf("cseg"); break;
|
||||
case DSEG: ack_printf("dseg"); break;
|
||||
case ESEG: ack_printf("eseg"); break;
|
||||
case FSEG: ack_printf("fseg"); break;
|
||||
case GSEG: ack_printf("gseg"); break;
|
||||
case SSEG: ack_printf("sseg"); break;
|
||||
default: assert(0);
|
||||
}
|
||||
if (a->seg != DEFSEG) {
|
||||
ack_printf(dialect == ACK ? " " : "; ");
|
||||
}
|
||||
if (a->oaz & OPZ) ack_printf(use16() ? "o32 " : "o16 ");
|
||||
if (a->oaz & ADZ) ack_printf(use16() ? "a32 " : "a16 ");
|
||||
|
||||
if (a->opcode == CBW) {
|
||||
p= !(a->oaz & OPZ) == use16() ? "cbw" : "cwde";
|
||||
}
|
||||
|
||||
if (a->opcode == CWD) {
|
||||
p= !(a->oaz & OPZ) == use16() ? "cwd" : "cdq";
|
||||
}
|
||||
|
||||
if (a->opcode == DOT_COMM && a->args != nil
|
||||
&& a->args->operator == ','
|
||||
&& a->args->left->operator == 'W'
|
||||
) {
|
||||
ack_printf(".define\t%s; ", a->args->left->name);
|
||||
}
|
||||
while (*p != 0) {
|
||||
if (*p == '%') {
|
||||
if (a->optype == BYTE) ack_putchar('b');
|
||||
} else {
|
||||
ack_putchar(*p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (a->args != nil) {
|
||||
ack_putchar('\t');
|
||||
switch (a->opcode) {
|
||||
case IN:
|
||||
case OUT:
|
||||
case INT:
|
||||
deref= 0;
|
||||
break;
|
||||
default:
|
||||
deref= (dialect == NCC && a->optype != PSEUDO);
|
||||
}
|
||||
ack_put_expression(a, a->args, deref);
|
||||
}
|
||||
if (a->opcode == DOT_USE16) set_use16();
|
||||
if (a->opcode == DOT_USE32) set_use32();
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"asmconv: internal error, unknown opcode '%d'\n",
|
||||
a->opcode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* A few ncc mnemonics are different. */
|
||||
static mnemonic_t ncc_mnemtab[] = {
|
||||
{ DOT_BSS, ".bss" },
|
||||
{ DOT_DATA, ".data" },
|
||||
{ DOT_END, ".end" },
|
||||
{ DOT_ROM, ".rom" },
|
||||
{ DOT_TEXT, ".text" },
|
||||
};
|
||||
|
||||
void ncc_emit_init(char *file, const char *banner)
|
||||
/* The assembly produced by the Minix ACK ANSI C compiler for the 8086 is
|
||||
* different from the normal ACK assembly, and different from the old K&R
|
||||
* assembler. This brings us endless joy. (It was supposed to make
|
||||
* translation of the assembly used by the old K&R assembler easier by
|
||||
* not deviating too much from that dialect.)
|
||||
*/
|
||||
{
|
||||
mnemonic_t *mp;
|
||||
|
||||
dialect= NCC;
|
||||
ack_emit_init(file, banner);
|
||||
|
||||
/* Replace a few mnemonics. */
|
||||
for (mp= ncc_mnemtab; mp < arraylimit(ncc_mnemtab); mp++) {
|
||||
opcode2name_tab[mp->opcode]= mp->name;
|
||||
}
|
||||
}
|
||||
|
||||
void ncc_emit_instruction(asm86_t *a)
|
||||
{
|
||||
ack_emit_instruction(a);
|
||||
}
|
|
@ -1,679 +0,0 @@
|
|||
/* emit_gnu.c - emit GNU assembly Author: Kees J. Bot
|
||||
* 28 Dec 1993
|
||||
*/
|
||||
#define nil 0
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "asmconv.h"
|
||||
#include "token.h"
|
||||
#include "asm86.h"
|
||||
#include "languages.h"
|
||||
|
||||
typedef struct mnemonic { /* GNU as386 mnemonics translation table. */
|
||||
opcode_t opcode;
|
||||
char *name;
|
||||
} mnemonic_t;
|
||||
|
||||
static mnemonic_t mnemtab[] = {
|
||||
{ AAA, "aaa" },
|
||||
{ AAD, "aad" },
|
||||
{ AAM, "aam" },
|
||||
{ AAS, "aas" },
|
||||
{ ADC, "adc%" },
|
||||
{ ADD, "add%" },
|
||||
{ AND, "and%" },
|
||||
{ ARPL, "arpl" },
|
||||
{ BOUND, "bound%" },
|
||||
{ BSF, "bsf%" },
|
||||
{ BSR, "bsr%" },
|
||||
{ BSWAP, "bswap" },
|
||||
{ BT, "bt%" },
|
||||
{ BTC, "btc%" },
|
||||
{ BTR, "btr%" },
|
||||
{ BTS, "bts%" },
|
||||
{ CALL, "call" },
|
||||
{ CALLF, "lcall" },
|
||||
{ CBW, "cbtw" },
|
||||
{ CLC, "clc" },
|
||||
{ CLD, "cld" },
|
||||
{ CLI, "cli" },
|
||||
{ CLTS, "clts" },
|
||||
{ CMC, "cmc" },
|
||||
{ CMP, "cmp%" },
|
||||
{ CMPS, "cmps%" },
|
||||
{ CMPXCHG, "cmpxchg" },
|
||||
{ CWD, "cwtd" },
|
||||
{ DAA, "daa" },
|
||||
{ DAS, "das" },
|
||||
{ DEC, "dec%" },
|
||||
{ DIV, "div%" },
|
||||
{ DOT_ALIGN, ".align" },
|
||||
{ DOT_ASCII, ".ascii" },
|
||||
{ DOT_ASCIZ, ".asciz" },
|
||||
{ DOT_ASSERT, ".assert" },
|
||||
{ DOT_BASE, ".base" },
|
||||
{ DOT_BSS, ".bss" },
|
||||
{ DOT_COMM, ".comm" },
|
||||
{ DOT_DATA, ".data" },
|
||||
{ DOT_DATA1, ".byte" },
|
||||
{ DOT_DATA2, ".short" },
|
||||
{ DOT_DATA4, ".long" },
|
||||
{ DOT_DEFINE, ".globl" },
|
||||
{ DOT_EXTERN, ".globl" },
|
||||
{ DOT_FILE, ".file" },
|
||||
{ DOT_LCOMM, ".lcomm" },
|
||||
{ DOT_LINE, ".line" },
|
||||
{ DOT_LIST, ".list" },
|
||||
{ DOT_NOLIST, ".nolist" },
|
||||
{ DOT_ROM, ".data" }, /* Minix -- separate I&D. */
|
||||
{ DOT_SPACE, ".space" },
|
||||
{ DOT_SYMB, ".symb" },
|
||||
{ DOT_TEXT, ".text" },
|
||||
{ DOT_USE16, ".use16" },
|
||||
{ DOT_USE32, ".use32" },
|
||||
{ ENTER, "enter" },
|
||||
{ F2XM1, "f2xm1" },
|
||||
{ FABS, "fabs" },
|
||||
{ FADD, "fadd" },
|
||||
{ FADDD, "faddl" },
|
||||
{ FADDP, "faddp" },
|
||||
{ FADDS, "fadds" },
|
||||
{ FBLD, "fbld" },
|
||||
{ FBSTP, "fbstp" },
|
||||
{ FCHS, "fchs" },
|
||||
{ FCLEX, "fnclex" },
|
||||
{ FCOMD, "fcoml" },
|
||||
{ FCOMPD, "fcompl" },
|
||||
{ FCOMPP, "fcompp" },
|
||||
{ FCOMPS, "fcomps" },
|
||||
{ FCOMS, "fcoms" },
|
||||
{ FCOS, "fcos" },
|
||||
{ FDECSTP, "fdecstp" },
|
||||
{ FDIVD, "fdivl" },
|
||||
{ FDIVP, "fdivp" },
|
||||
{ FDIVRD, "fdivrl" },
|
||||
{ FDIVRP, "fdivrp" },
|
||||
{ FDIVRS, "fdivrs" },
|
||||
{ FDIVS, "fdivs" },
|
||||
{ FFREE, "ffree" },
|
||||
{ FIADDL, "fiaddl" },
|
||||
{ FIADDS, "fiadds" },
|
||||
{ FICOM, "ficom" },
|
||||
{ FICOMP, "ficomp" },
|
||||
{ FIDIVL, "fidivl" },
|
||||
{ FIDIVRL, "fidivrl" },
|
||||
{ FIDIVRS, "fidivrs" },
|
||||
{ FIDIVS, "fidivs" },
|
||||
{ FILDL, "fildl" },
|
||||
{ FILDQ, "fildq" },
|
||||
{ FILDS, "filds" },
|
||||
{ FIMULL, "fimull" },
|
||||
{ FIMULS, "fimuls" },
|
||||
{ FINCSTP, "fincstp" },
|
||||
{ FINIT, "fninit" },
|
||||
{ FISTL, "fistl" },
|
||||
{ FISTP, "fistp" },
|
||||
{ FISTS, "fists" },
|
||||
{ FISUBL, "fisubl" },
|
||||
{ FISUBRL, "fisubrl" },
|
||||
{ FISUBRS, "fisubrs" },
|
||||
{ FISUBS, "fisubs" },
|
||||
{ FLD1, "fld1" },
|
||||
{ FLDCW, "fldcw" },
|
||||
{ FLDD, "fldl" },
|
||||
{ FLDENV, "fldenv" },
|
||||
{ FLDL2E, "fldl2e" },
|
||||
{ FLDL2T, "fldl2t" },
|
||||
{ FLDLG2, "fldlg2" },
|
||||
{ FLDLN2, "fldln2" },
|
||||
{ FLDPI, "fldpi" },
|
||||
{ FLDS, "flds" },
|
||||
{ FLDX, "fldt" },
|
||||
{ FLDZ, "fldz" },
|
||||
{ FMULD, "fmull" },
|
||||
{ FMULP, "fmulp" },
|
||||
{ FMULS, "fmuls" },
|
||||
{ FNOP, "fnop" },
|
||||
{ FPATAN, "fpatan" },
|
||||
{ FPREM, "fprem" },
|
||||
{ FPREM1, "fprem1" },
|
||||
{ FPTAN, "fptan" },
|
||||
{ FRNDINT, "frndint" },
|
||||
{ FRSTOR, "frstor" },
|
||||
{ FSAVE, "fnsave" },
|
||||
{ FSCALE, "fscale" },
|
||||
{ FSIN, "fsin" },
|
||||
{ FSINCOS, "fsincos" },
|
||||
{ FSQRT, "fsqrt" },
|
||||
{ FSTCW, "fnstcw" },
|
||||
{ FSTD, "fstl" },
|
||||
{ FSTENV, "fnstenv" },
|
||||
{ FSTP, "fstp" },
|
||||
{ FSTPD, "fstpl" },
|
||||
{ FSTPS, "fstps" },
|
||||
{ FSTPX, "fstpt" },
|
||||
{ FSTS, "fsts" },
|
||||
{ FSTSW, "fstsw" },
|
||||
{ FSUBD, "fsubl" },
|
||||
{ FSUBP, "fsubp" },
|
||||
{ FSUBPR, "fsubpr" },
|
||||
{ FSUBRD, "fsubrl" },
|
||||
{ FSUBRS, "fsubrs" },
|
||||
{ FSUBS, "fsubs" },
|
||||
{ FTST, "ftst" },
|
||||
{ FUCOM, "fucom" },
|
||||
{ FUCOMP, "fucomp" },
|
||||
{ FUCOMPP, "fucompp" },
|
||||
{ FXAM, "fxam" },
|
||||
{ FXCH, "fxch" },
|
||||
{ FXTRACT, "fxtract" },
|
||||
{ FYL2X, "fyl2x" },
|
||||
{ FYL2XP1, "fyl2xp1" },
|
||||
{ HLT, "hlt" },
|
||||
{ IDIV, "idiv%" },
|
||||
{ IMUL, "imul%" },
|
||||
{ IN, "in%" },
|
||||
{ INC, "inc%" },
|
||||
{ INS, "ins%" },
|
||||
{ INT, "int" },
|
||||
{ INTO, "into" },
|
||||
{ INVD, "invd" },
|
||||
{ INVLPG, "invlpg" },
|
||||
{ IRET, "iret" },
|
||||
{ IRETD, "iret" },
|
||||
{ JA, "ja" },
|
||||
{ JAE, "jae" },
|
||||
{ JB, "jb" },
|
||||
{ JBE, "jbe" },
|
||||
{ JCXZ, "jcxz" },
|
||||
{ JE, "je" },
|
||||
{ JG, "jg" },
|
||||
{ JGE, "jge" },
|
||||
{ JL, "jl" },
|
||||
{ JLE, "jle" },
|
||||
{ JMP, "jmp" },
|
||||
{ JMPF, "ljmp" },
|
||||
{ JNE, "jne" },
|
||||
{ JNO, "jno" },
|
||||
{ JNP, "jnp" },
|
||||
{ JNS, "jns" },
|
||||
{ JO, "jo" },
|
||||
{ JP, "jp" },
|
||||
{ JS, "js" },
|
||||
{ LAHF, "lahf" },
|
||||
{ LAR, "lar" },
|
||||
{ LDS, "lds" },
|
||||
{ LEA, "lea%" },
|
||||
{ LEAVE, "leave" },
|
||||
{ LES, "les" },
|
||||
{ LFS, "lfs" },
|
||||
{ LGDT, "lgdt" },
|
||||
{ LGS, "lgs" },
|
||||
{ LIDT, "lidt" },
|
||||
{ LLDT, "lldt" },
|
||||
{ LMSW, "lmsw" },
|
||||
{ LOCK, "lock" },
|
||||
{ LODS, "lods%" },
|
||||
{ LOOP, "loop" },
|
||||
{ LOOPE, "loope" },
|
||||
{ LOOPNE, "loopne" },
|
||||
{ LSL, "lsl" },
|
||||
{ LSS, "lss" },
|
||||
{ LTR, "ltr" },
|
||||
{ MOV, "mov%" },
|
||||
{ MOVS, "movs%" },
|
||||
{ MOVSX, "movswl" },
|
||||
{ MOVSXB, "movsb%" },
|
||||
{ MOVZX, "movzwl" },
|
||||
{ MOVZXB, "movzb%" },
|
||||
{ MUL, "mul%" },
|
||||
{ NEG, "neg%" },
|
||||
{ NOP, "nop" },
|
||||
{ NOT, "not%" },
|
||||
{ OR, "or%" },
|
||||
{ OUT, "out%" },
|
||||
{ OUTS, "outs%" },
|
||||
{ POP, "pop%" },
|
||||
{ POPA, "popa%" },
|
||||
{ POPF, "popf%" },
|
||||
{ PUSH, "push%" },
|
||||
{ PUSHA, "pusha%" },
|
||||
{ PUSHF, "pushf%" },
|
||||
{ RCL, "rcl%" },
|
||||
{ RCR, "rcr%" },
|
||||
{ RET, "ret" },
|
||||
{ RETF, "lret" },
|
||||
{ ROL, "rol%" },
|
||||
{ ROR, "ror%" },
|
||||
{ SAHF, "sahf" },
|
||||
{ SAL, "sal%" },
|
||||
{ SAR, "sar%" },
|
||||
{ SBB, "sbb%" },
|
||||
{ SCAS, "scas%" },
|
||||
{ SETA, "setab" },
|
||||
{ SETAE, "setaeb" },
|
||||
{ SETB, "setbb" },
|
||||
{ SETBE, "setbeb" },
|
||||
{ SETE, "seteb" },
|
||||
{ SETG, "setgb" },
|
||||
{ SETGE, "setgeb" },
|
||||
{ SETL, "setlb" },
|
||||
{ SETLE, "setleb" },
|
||||
{ SETNE, "setneb" },
|
||||
{ SETNO, "setnob" },
|
||||
{ SETNP, "setnpb" },
|
||||
{ SETNS, "setnsb" },
|
||||
{ SETO, "setob" },
|
||||
{ SETP, "setpb" },
|
||||
{ SETS, "setsb" },
|
||||
{ SGDT, "sgdt" },
|
||||
{ SHL, "shl%" },
|
||||
{ SHLD, "shld%" },
|
||||
{ SHR, "shr%" },
|
||||
{ SHRD, "shrd%" },
|
||||
{ SIDT, "sidt" },
|
||||
{ SLDT, "sldt" },
|
||||
{ SMSW, "smsw" },
|
||||
{ STC, "stc" },
|
||||
{ STD, "std" },
|
||||
{ STI, "sti" },
|
||||
{ STOS, "stos%" },
|
||||
{ STR, "str" },
|
||||
{ SUB, "sub%" },
|
||||
{ TEST, "test%" },
|
||||
{ VERR, "verr" },
|
||||
{ VERW, "verw" },
|
||||
{ WAIT, "wait" },
|
||||
{ WBINVD, "wbinvd" },
|
||||
{ XADD, "xadd" },
|
||||
{ XCHG, "xchg%" },
|
||||
{ XLAT, "xlat" },
|
||||
{ XOR, "xor%" },
|
||||
};
|
||||
|
||||
static FILE *ef;
|
||||
static long eline= 1;
|
||||
static char *efile;
|
||||
static char *orig_efile;
|
||||
static char *opcode2name_tab[N_OPCODES];
|
||||
|
||||
static void gnu_putchar(int c)
|
||||
/* LOOK, this programmer checks the return code of putc! What an idiot, noone
|
||||
* does that!
|
||||
*/
|
||||
{
|
||||
if (putc(c, ef) == EOF) fatal(orig_efile);
|
||||
}
|
||||
|
||||
static void gnu_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (vfprintf(ef, fmt, ap) == EOF) fatal(orig_efile);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void gnu_emit_init(char *file, const char *banner)
|
||||
/* Prepare producing a GNU assembly file. */
|
||||
{
|
||||
mnemonic_t *mp;
|
||||
|
||||
if (file == nil) {
|
||||
file= "stdout";
|
||||
ef= stdout;
|
||||
} else {
|
||||
if ((ef= fopen(file, "w")) == nil) fatal(file);
|
||||
}
|
||||
orig_efile= file;
|
||||
efile= file;
|
||||
gnu_printf("/ %s", banner);
|
||||
|
||||
/* Initialize the opcode to mnemonic translation table. */
|
||||
for (mp= mnemtab; mp < arraylimit(mnemtab); mp++) {
|
||||
assert(opcode2name_tab[mp->opcode] == nil);
|
||||
opcode2name_tab[mp->opcode]= mp->name;
|
||||
}
|
||||
}
|
||||
|
||||
#define opcode2name(op) (opcode2name_tab[op] + 0)
|
||||
|
||||
static void gnu_put_string(const char *s, size_t n)
|
||||
/* Emit a string with weird characters quoted. */
|
||||
{
|
||||
while (n > 0) {
|
||||
int c= *s;
|
||||
|
||||
if (c < ' ' || c > 0177) {
|
||||
gnu_printf("\\%03o", c);
|
||||
} else
|
||||
if (c == '"' || c == '\\') {
|
||||
gnu_printf("\\%c", c & 0xFF);
|
||||
} else {
|
||||
gnu_putchar(c);
|
||||
}
|
||||
s++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
static void gnu_put_expression(asm86_t *a, expression_t *e, int deref)
|
||||
/* Send an expression, i.e. instruction operands, to the output file. Deref
|
||||
* is true when the rewrite of "x" -> "#x" or "(x)" -> "x" may be made.
|
||||
*/
|
||||
{
|
||||
assert(e != nil);
|
||||
|
||||
switch (e->operator) {
|
||||
case ',':
|
||||
if (is_pseudo(a->opcode)) {
|
||||
/* Pseudo's are normal. */
|
||||
gnu_put_expression(a, e->left, deref);
|
||||
gnu_printf(", ");
|
||||
gnu_put_expression(a, e->right, deref);
|
||||
} else {
|
||||
/* He who invented GNU assembly has seen one VAX too
|
||||
* many, operands are given in the wrong order. This
|
||||
* makes coding from an Intel databook a real delight.
|
||||
* A good thing this program allows us to write the
|
||||
* more normal ACK assembly.
|
||||
*/
|
||||
gnu_put_expression(a, e->right, deref);
|
||||
gnu_printf(", ");
|
||||
gnu_put_expression(a, e->left, deref);
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
if (deref && a->optype == JUMP) gnu_putchar('*');
|
||||
if (e->left != nil) gnu_put_expression(a, e->left, 0);
|
||||
gnu_putchar('(');
|
||||
if (e->middle != nil) gnu_put_expression(a, e->middle, 0);
|
||||
if (e->right != nil) {
|
||||
gnu_putchar(',');
|
||||
gnu_put_expression(a, e->right, 0);
|
||||
}
|
||||
gnu_putchar(')');
|
||||
break;
|
||||
case '(':
|
||||
if (!deref) gnu_putchar('(');
|
||||
if (deref && a->optype == JUMP) gnu_putchar('*');
|
||||
gnu_put_expression(a, e->middle, 0);
|
||||
if (!deref) gnu_putchar(')');
|
||||
break;
|
||||
case 'B':
|
||||
gnu_printf("%%%s", e->name);
|
||||
break;
|
||||
case '1':
|
||||
case '2':
|
||||
case '4':
|
||||
case '8':
|
||||
gnu_printf("%%%s,%c", e->name, e->operator);
|
||||
break;
|
||||
case '+':
|
||||
case '-':
|
||||
case '~':
|
||||
if (e->middle != nil) {
|
||||
if (deref && a->optype >= BYTE) gnu_putchar('$');
|
||||
gnu_putchar(e->operator);
|
||||
gnu_put_expression(a, e->middle, 0);
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
case '*':
|
||||
case '/':
|
||||
case '%':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case S_LEFTSHIFT:
|
||||
case S_RIGHTSHIFT:
|
||||
if (deref && a->optype >= BYTE) gnu_putchar('$');
|
||||
gnu_put_expression(a, e->left, 0);
|
||||
if (e->operator == S_LEFTSHIFT) {
|
||||
gnu_printf("<<");
|
||||
} else
|
||||
if (e->operator == S_RIGHTSHIFT) {
|
||||
gnu_printf(">>");
|
||||
} else {
|
||||
gnu_putchar(e->operator);
|
||||
}
|
||||
gnu_put_expression(a, e->right, 0);
|
||||
break;
|
||||
case '[':
|
||||
if (deref && a->optype >= BYTE) gnu_putchar('$');
|
||||
gnu_putchar('(');
|
||||
gnu_put_expression(a, e->middle, 0);
|
||||
gnu_putchar(')');
|
||||
break;
|
||||
case 'W':
|
||||
if (isregister(e->name)) {
|
||||
if (a->optype == JUMP) gnu_putchar('*');
|
||||
gnu_printf("%%%s", e->name);
|
||||
} else {
|
||||
if (deref && a->optype >= BYTE) gnu_putchar('$');
|
||||
gnu_printf("%s", e->name);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
gnu_putchar('"');
|
||||
gnu_put_string(e->name, e->len);
|
||||
gnu_putchar('"');
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"asmconv: internal error, unknown expression operator '%d'\n",
|
||||
e->operator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void gnu_emit_instruction(asm86_t *a)
|
||||
/* Output one instruction and its operands. */
|
||||
{
|
||||
int same= 0;
|
||||
char *p;
|
||||
|
||||
if (a == nil) {
|
||||
/* Last call */
|
||||
gnu_putchar('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
if (use16()) {
|
||||
fprintf(stderr,
|
||||
"asmconv: the GNU assembler can't translate 8086 code\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Make sure the line number of the line to be emitted is ok. */
|
||||
if ((a->file != efile && strcmp(a->file, efile) != 0)
|
||||
|| a->line < eline || a->line > eline+10) {
|
||||
gnu_putchar('\n');
|
||||
gnu_printf("# %ld \"%s\"\n", a->line, a->file);
|
||||
efile= a->file;
|
||||
eline= a->line;
|
||||
} else {
|
||||
if (a->line == eline) {
|
||||
gnu_printf("; ");
|
||||
same= 1;
|
||||
}
|
||||
while (eline < a->line) {
|
||||
gnu_putchar('\n');
|
||||
eline++;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->opcode == DOT_END) {
|
||||
/* Stop translating after .sect .end. */
|
||||
exit(0);
|
||||
} else
|
||||
if (a->opcode == DOT_LABEL) {
|
||||
assert(a->args->operator == ':');
|
||||
gnu_printf("%s:", a->args->name);
|
||||
} else
|
||||
if (a->opcode == DOT_EQU) {
|
||||
assert(a->args->operator == '=');
|
||||
gnu_printf("\t%s = ", a->args->name);
|
||||
gnu_put_expression(a, a->args->middle, 0);
|
||||
} else
|
||||
if (a->opcode == DOT_ALIGN) {
|
||||
/* GNU .align thinks in powers of two. */
|
||||
unsigned long n;
|
||||
unsigned s;
|
||||
|
||||
assert(a->args->operator == 'W' && isanumber(a->args->name));
|
||||
n= strtoul(a->args->name, nil, 0);
|
||||
for (s= 0; s <= 16 && (1 << s) < n; s++) {}
|
||||
gnu_printf(".align\t%u", s);
|
||||
} else
|
||||
if ((p= opcode2name(a->opcode)) != nil) {
|
||||
if (!is_pseudo(a->opcode) && !same) gnu_putchar('\t');
|
||||
|
||||
switch (a->rep) {
|
||||
case ONCE: break;
|
||||
case REP: gnu_printf("rep; "); break;
|
||||
case REPE: gnu_printf("repe; "); break;
|
||||
case REPNE: gnu_printf("repne; "); break;
|
||||
default: assert(0);
|
||||
}
|
||||
switch (a->seg) {
|
||||
/* Kludge to avoid knowing where to put the "%es:" */
|
||||
case DEFSEG: break;
|
||||
case CSEG: gnu_printf(".byte 0x2e; "); break;
|
||||
case DSEG: gnu_printf(".byte 0x3e; "); break;
|
||||
case ESEG: gnu_printf(".byte 0x26; "); break;
|
||||
case FSEG: gnu_printf(".byte 0x64; "); break;
|
||||
case GSEG: gnu_printf(".byte 0x65; "); break;
|
||||
case SSEG: gnu_printf(".byte 0x36; "); break;
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
/* Exceptions, exceptions... */
|
||||
if (a->opcode == CBW) {
|
||||
if (!(a->oaz & OPZ)) p= "cwtl";
|
||||
a->oaz&= ~OPZ;
|
||||
}
|
||||
if (a->opcode == CWD) {
|
||||
if (!(a->oaz & OPZ)) p= "cltd";
|
||||
a->oaz&= ~OPZ;
|
||||
}
|
||||
|
||||
if (a->opcode == RET || a->opcode == RETF) {
|
||||
/* Argument of RET needs a '$'. */
|
||||
a->optype= WORD;
|
||||
}
|
||||
|
||||
if (a->opcode == MUL && a->args != nil
|
||||
&& a->args->operator == ',') {
|
||||
/* Two operand MUL is an IMUL? */
|
||||
p="imul%";
|
||||
}
|
||||
|
||||
/* GAS doesn't understand the interesting combinations. */
|
||||
if (a->oaz & ADZ) gnu_printf(".byte 0x67; ");
|
||||
if (a->oaz & OPZ && strchr(p, '%') == nil)
|
||||
gnu_printf(".byte 0x66; ");
|
||||
|
||||
/* Unsupported instructions that Minix code needs. */
|
||||
if (a->opcode == JMPF && a->args != nil
|
||||
&& a->args->operator == ',') {
|
||||
/* JMPF seg:off. */
|
||||
gnu_printf(".byte 0xEA; .long ");
|
||||
gnu_put_expression(a, a->args->right, 0);
|
||||
gnu_printf("; .short ");
|
||||
gnu_put_expression(a, a->args->left, 0);
|
||||
return;
|
||||
}
|
||||
if (a->opcode == JMPF && a->args != nil
|
||||
&& a->args->operator == 'O'
|
||||
&& a->args->left != nil
|
||||
&& a->args->right == nil
|
||||
&& a->args->middle != nil
|
||||
&& a->args->middle->operator == 'B'
|
||||
&& strcmp(a->args->middle->name, "esp") == 0
|
||||
) {
|
||||
/* JMPF offset(ESP). */
|
||||
gnu_printf(".byte 0xFF,0x6C,0x24,");
|
||||
gnu_put_expression(a, a->args->left, 0);
|
||||
return;
|
||||
}
|
||||
if (a->opcode == MOV && a->args != nil
|
||||
&& a->args->operator == ','
|
||||
&& a->args->left != nil
|
||||
&& a->args->left->operator == 'W'
|
||||
&& (strcmp(a->args->left->name, "ds") == 0
|
||||
|| strcmp(a->args->left->name, "es") == 0)
|
||||
&& a->args->right->operator == 'O'
|
||||
&& a->args->right->left != nil
|
||||
&& a->args->right->right == nil
|
||||
&& a->args->right->middle != nil
|
||||
&& a->args->right->middle->operator == 'B'
|
||||
&& strcmp(a->args->right->middle->name, "esp") == 0
|
||||
) {
|
||||
/* MOV DS, offset(ESP); MOV ES, offset(ESP) */
|
||||
gnu_printf(".byte 0x8E,0x%02X,0x24,",
|
||||
a->args->left->name[0] == 'd' ? 0x5C : 0x44);
|
||||
gnu_put_expression(a, a->args->right->left, 0);
|
||||
return;
|
||||
}
|
||||
if (a->opcode == MOV && a->args != nil
|
||||
&& a->args->operator == ','
|
||||
&& a->args->left != nil
|
||||
&& a->args->left->operator == 'W'
|
||||
&& (strcmp(a->args->left->name, "ds") == 0
|
||||
|| strcmp(a->args->left->name, "es") == 0)
|
||||
&& a->args->right->operator == '('
|
||||
&& a->args->right->middle != nil
|
||||
) {
|
||||
/* MOV DS, (memory); MOV ES, (memory) */
|
||||
gnu_printf(".byte 0x8E,0x%02X; .long ",
|
||||
a->args->left->name[0] == 'd' ? 0x1D : 0x05);
|
||||
gnu_put_expression(a, a->args->right->middle, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
while (*p != 0) {
|
||||
if (*p == '%') {
|
||||
if (a->optype == BYTE) {
|
||||
gnu_putchar('b');
|
||||
} else
|
||||
if (a->optype == WORD) {
|
||||
gnu_putchar((a->oaz & OPZ) ? 'w' : 'l');
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
} else {
|
||||
gnu_putchar(*p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
if (a->args != nil) {
|
||||
static char *aregs[] = { "al", "ax", "eax" };
|
||||
|
||||
gnu_putchar('\t');
|
||||
switch (a->opcode) {
|
||||
case IN:
|
||||
gnu_put_expression(a, a->args, 1);
|
||||
gnu_printf(", %%%s", aregs[a->optype - BYTE]);
|
||||
break;
|
||||
case OUT:
|
||||
gnu_printf("%%%s, ", aregs[a->optype - BYTE]);
|
||||
gnu_put_expression(a, a->args, 1);
|
||||
break;
|
||||
default:
|
||||
gnu_put_expression(a, a->args, 1);
|
||||
}
|
||||
}
|
||||
if (a->opcode == DOT_USE16) set_use16();
|
||||
if (a->opcode == DOT_USE32) set_use32();
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"asmconv: internal error, unknown opcode '%d'\n",
|
||||
a->opcode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/* languages.h - functions that parse or emit assembly
|
||||
* Author: Kees J. Bot
|
||||
* 27 Dec 1993
|
||||
*/
|
||||
|
||||
void ack_parse_init(char *file);
|
||||
asm86_t *ack_get_instruction(void);
|
||||
|
||||
void ncc_parse_init(char *file);
|
||||
asm86_t *ncc_get_instruction(void);
|
||||
|
||||
void gnu_parse_init(char *file);
|
||||
asm86_t *gnu_get_instruction(void);
|
||||
|
||||
void bas_parse_init(char *file);
|
||||
asm86_t *bas_get_instruction(void);
|
||||
|
||||
void ack_emit_init(char *file, const char *banner);
|
||||
void ack_emit_instruction(asm86_t *instr);
|
||||
|
||||
void ncc_emit_init(char *file, const char *banner);
|
||||
void ncc_emit_instruction(asm86_t *instr);
|
||||
|
||||
void gnu_emit_init(char *file, const char *banner);
|
||||
void gnu_emit_instruction(asm86_t *instr);
|
|
@ -1,911 +0,0 @@
|
|||
/* parse_ack.c - parse ACK assembly Author: Kees J. Bot
|
||||
* parse NCC assembly 18 Dec 1993
|
||||
*/
|
||||
#define nil 0
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "asmconv.h"
|
||||
#include "token.h"
|
||||
#include "asm86.h"
|
||||
#include "languages.h"
|
||||
|
||||
typedef struct mnemonic { /* ACK as86 mnemonics translation table. */
|
||||
char *name;
|
||||
opcode_t opcode;
|
||||
optype_t optype;
|
||||
} mnemonic_t;
|
||||
|
||||
static mnemonic_t mnemtab[] = { /* This array is sorted. */
|
||||
{ ".align", DOT_ALIGN, PSEUDO },
|
||||
{ ".ascii", DOT_ASCII, PSEUDO },
|
||||
{ ".asciz", DOT_ASCIZ, PSEUDO },
|
||||
{ ".assert", DOT_ASSERT, PSEUDO },
|
||||
{ ".base", DOT_BASE, PSEUDO },
|
||||
{ ".bss", DOT_BSS, PSEUDO },
|
||||
{ ".comm", DOT_LCOMM, PSEUDO },
|
||||
{ ".data", DOT_DATA, PSEUDO },
|
||||
{ ".data1", DOT_DATA1, PSEUDO },
|
||||
{ ".data2", DOT_DATA2, PSEUDO },
|
||||
{ ".data4", DOT_DATA4, PSEUDO },
|
||||
{ ".define", DOT_DEFINE, PSEUDO },
|
||||
{ ".end", DOT_END, PSEUDO },
|
||||
{ ".extern", DOT_EXTERN, PSEUDO },
|
||||
{ ".file", DOT_FILE, PSEUDO },
|
||||
{ ".line", DOT_LINE, PSEUDO },
|
||||
{ ".list", DOT_LIST, PSEUDO },
|
||||
{ ".nolist", DOT_NOLIST, PSEUDO },
|
||||
{ ".rom", DOT_ROM, PSEUDO },
|
||||
{ ".space", DOT_SPACE, PSEUDO },
|
||||
{ ".symb", DOT_SYMB, PSEUDO },
|
||||
{ ".text", DOT_TEXT, PSEUDO },
|
||||
{ ".use16", DOT_USE16, PSEUDO },
|
||||
{ ".use32", DOT_USE32, PSEUDO },
|
||||
{ "aaa", AAA, WORD },
|
||||
{ "aad", AAD, WORD },
|
||||
{ "aam", AAM, WORD },
|
||||
{ "aas", AAS, WORD },
|
||||
{ "adc", ADC, WORD },
|
||||
{ "adcb", ADC, BYTE },
|
||||
{ "add", ADD, WORD },
|
||||
{ "addb", ADD, BYTE },
|
||||
{ "and", AND, WORD },
|
||||
{ "andb", AND, BYTE },
|
||||
{ "arpl", ARPL, WORD },
|
||||
{ "bound", BOUND, WORD },
|
||||
{ "bsf", BSF, WORD },
|
||||
{ "bsr", BSR, WORD },
|
||||
{ "bswap", BSWAP, WORD },
|
||||
{ "bt", BT, WORD },
|
||||
{ "btc", BTC, WORD },
|
||||
{ "btr", BTR, WORD },
|
||||
{ "bts", BTS, WORD },
|
||||
{ "call", CALL, JUMP },
|
||||
{ "callf", CALLF, JUMP },
|
||||
{ "cbw", CBW, WORD },
|
||||
{ "cdq", CWD, WORD },
|
||||
{ "clc", CLC, WORD },
|
||||
{ "cld", CLD, WORD },
|
||||
{ "cli", CLI, WORD },
|
||||
{ "clts", CLTS, WORD },
|
||||
{ "cmc", CMC, WORD },
|
||||
{ "cmp", CMP, WORD },
|
||||
{ "cmpb", CMP, BYTE },
|
||||
{ "cmps", CMPS, WORD },
|
||||
{ "cmpsb", CMPS, BYTE },
|
||||
{ "cmpxchg", CMPXCHG, WORD },
|
||||
{ "cwd", CWD, WORD },
|
||||
{ "cwde", CBW, WORD },
|
||||
{ "daa", DAA, WORD },
|
||||
{ "das", DAS, WORD },
|
||||
{ "dec", DEC, WORD },
|
||||
{ "decb", DEC, BYTE },
|
||||
{ "div", DIV, WORD },
|
||||
{ "divb", DIV, BYTE },
|
||||
{ "enter", ENTER, WORD },
|
||||
{ "f2xm1", F2XM1, WORD },
|
||||
{ "fabs", FABS, WORD },
|
||||
{ "fadd", FADD, WORD },
|
||||
{ "faddd", FADDD, WORD },
|
||||
{ "faddp", FADDP, WORD },
|
||||
{ "fadds", FADDS, WORD },
|
||||
{ "fbld", FBLD, WORD },
|
||||
{ "fbstp", FBSTP, WORD },
|
||||
{ "fchs", FCHS, WORD },
|
||||
{ "fclex", FCLEX, WORD },
|
||||
{ "fcomd", FCOMD, WORD },
|
||||
{ "fcompd", FCOMPD, WORD },
|
||||
{ "fcompp", FCOMPP, WORD },
|
||||
{ "fcomps", FCOMPS, WORD },
|
||||
{ "fcoms", FCOMS, WORD },
|
||||
{ "fcos", FCOS, WORD },
|
||||
{ "fdecstp", FDECSTP, WORD },
|
||||
{ "fdivd", FDIVD, WORD },
|
||||
{ "fdivp", FDIVP, WORD },
|
||||
{ "fdivrd", FDIVRD, WORD },
|
||||
{ "fdivrp", FDIVRP, WORD },
|
||||
{ "fdivrs", FDIVRS, WORD },
|
||||
{ "fdivs", FDIVS, WORD },
|
||||
{ "ffree", FFREE, WORD },
|
||||
{ "fiaddl", FIADDL, WORD },
|
||||
{ "fiadds", FIADDS, WORD },
|
||||
{ "ficom", FICOM, WORD },
|
||||
{ "ficomp", FICOMP, WORD },
|
||||
{ "fidivl", FIDIVL, WORD },
|
||||
{ "fidivrl", FIDIVRL, WORD },
|
||||
{ "fidivrs", FIDIVRS, WORD },
|
||||
{ "fidivs", FIDIVS, WORD },
|
||||
{ "fildl", FILDL, WORD },
|
||||
{ "fildq", FILDQ, WORD },
|
||||
{ "filds", FILDS, WORD },
|
||||
{ "fimull", FIMULL, WORD },
|
||||
{ "fimuls", FIMULS, WORD },
|
||||
{ "fincstp", FINCSTP, WORD },
|
||||
{ "finit", FINIT, WORD },
|
||||
{ "fistl", FISTL, WORD },
|
||||
{ "fistp", FISTP, WORD },
|
||||
{ "fists", FISTS, WORD },
|
||||
{ "fisubl", FISUBL, WORD },
|
||||
{ "fisubrl", FISUBRL, WORD },
|
||||
{ "fisubrs", FISUBRS, WORD },
|
||||
{ "fisubs", FISUBS, WORD },
|
||||
{ "fld1", FLD1, WORD },
|
||||
{ "fldcw", FLDCW, WORD },
|
||||
{ "fldd", FLDD, WORD },
|
||||
{ "fldenv", FLDENV, WORD },
|
||||
{ "fldl2e", FLDL2E, WORD },
|
||||
{ "fldl2t", FLDL2T, WORD },
|
||||
{ "fldlg2", FLDLG2, WORD },
|
||||
{ "fldln2", FLDLN2, WORD },
|
||||
{ "fldpi", FLDPI, WORD },
|
||||
{ "flds", FLDS, WORD },
|
||||
{ "fldx", FLDX, WORD },
|
||||
{ "fldz", FLDZ, WORD },
|
||||
{ "fmuld", FMULD, WORD },
|
||||
{ "fmulp", FMULP, WORD },
|
||||
{ "fmuls", FMULS, WORD },
|
||||
{ "fnop", FNOP, WORD },
|
||||
{ "fpatan", FPATAN, WORD },
|
||||
{ "fprem", FPREM, WORD },
|
||||
{ "fprem1", FPREM1, WORD },
|
||||
{ "fptan", FPTAN, WORD },
|
||||
{ "frndint", FRNDINT, WORD },
|
||||
{ "frstor", FRSTOR, WORD },
|
||||
{ "fsave", FSAVE, WORD },
|
||||
{ "fscale", FSCALE, WORD },
|
||||
{ "fsin", FSIN, WORD },
|
||||
{ "fsincos", FSINCOS, WORD },
|
||||
{ "fsqrt", FSQRT, WORD },
|
||||
{ "fstcw", FSTCW, WORD },
|
||||
{ "fstd", FSTD, WORD },
|
||||
{ "fstenv", FSTENV, WORD },
|
||||
{ "fstp", FSTP, WORD },
|
||||
{ "fstpd", FSTPD, WORD },
|
||||
{ "fstps", FSTPS, WORD },
|
||||
{ "fstpx", FSTPX, WORD },
|
||||
{ "fsts", FSTS, WORD },
|
||||
{ "fstsw", FSTSW, WORD },
|
||||
{ "fsubd", FSUBD, WORD },
|
||||
{ "fsubp", FSUBP, WORD },
|
||||
{ "fsubpr", FSUBPR, WORD },
|
||||
{ "fsubrd", FSUBRD, WORD },
|
||||
{ "fsubrs", FSUBRS, WORD },
|
||||
{ "fsubs", FSUBS, WORD },
|
||||
{ "ftst", FTST, WORD },
|
||||
{ "fucom", FUCOM, WORD },
|
||||
{ "fucomp", FUCOMP, WORD },
|
||||
{ "fucompp", FUCOMPP, WORD },
|
||||
{ "fxam", FXAM, WORD },
|
||||
{ "fxch", FXCH, WORD },
|
||||
{ "fxtract", FXTRACT, WORD },
|
||||
{ "fyl2x", FYL2X, WORD },
|
||||
{ "fyl2xp1", FYL2XP1, WORD },
|
||||
{ "hlt", HLT, WORD },
|
||||
{ "idiv", IDIV, WORD },
|
||||
{ "idivb", IDIV, BYTE },
|
||||
{ "imul", IMUL, WORD },
|
||||
{ "imulb", IMUL, BYTE },
|
||||
{ "in", IN, WORD },
|
||||
{ "inb", IN, BYTE },
|
||||
{ "inc", INC, WORD },
|
||||
{ "incb", INC, BYTE },
|
||||
{ "ins", INS, WORD },
|
||||
{ "insb", INS, BYTE },
|
||||
{ "int", INT, WORD },
|
||||
{ "into", INTO, JUMP },
|
||||
{ "invd", INVD, WORD },
|
||||
{ "invlpg", INVLPG, WORD },
|
||||
{ "iret", IRET, JUMP },
|
||||
{ "iretd", IRETD, JUMP },
|
||||
{ "ja", JA, JUMP },
|
||||
{ "jae", JAE, JUMP },
|
||||
{ "jb", JB, JUMP },
|
||||
{ "jbe", JBE, JUMP },
|
||||
{ "jc", JB, JUMP },
|
||||
{ "jcxz", JCXZ, JUMP },
|
||||
{ "je", JE, JUMP },
|
||||
{ "jecxz", JCXZ, JUMP },
|
||||
{ "jg", JG, JUMP },
|
||||
{ "jge", JGE, JUMP },
|
||||
{ "jl", JL, JUMP },
|
||||
{ "jle", JLE, JUMP },
|
||||
{ "jmp", JMP, JUMP },
|
||||
{ "jmpf", JMPF, JUMP },
|
||||
{ "jna", JBE, JUMP },
|
||||
{ "jnae", JB, JUMP },
|
||||
{ "jnb", JAE, JUMP },
|
||||
{ "jnbe", JA, JUMP },
|
||||
{ "jnc", JAE, JUMP },
|
||||
{ "jne", JNE, JUMP },
|
||||
{ "jng", JLE, JUMP },
|
||||
{ "jnge", JL, JUMP },
|
||||
{ "jnl", JGE, JUMP },
|
||||
{ "jnle", JG, JUMP },
|
||||
{ "jno", JNO, JUMP },
|
||||
{ "jnp", JNP, JUMP },
|
||||
{ "jns", JNS, JUMP },
|
||||
{ "jnz", JNE, JUMP },
|
||||
{ "jo", JO, JUMP },
|
||||
{ "jp", JP, JUMP },
|
||||
{ "js", JS, JUMP },
|
||||
{ "jz", JE, JUMP },
|
||||
{ "lahf", LAHF, WORD },
|
||||
{ "lar", LAR, WORD },
|
||||
{ "lds", LDS, WORD },
|
||||
{ "lea", LEA, WORD },
|
||||
{ "leave", LEAVE, WORD },
|
||||
{ "les", LES, WORD },
|
||||
{ "lfs", LFS, WORD },
|
||||
{ "lgdt", LGDT, WORD },
|
||||
{ "lgs", LGS, WORD },
|
||||
{ "lidt", LIDT, WORD },
|
||||
{ "lldt", LLDT, WORD },
|
||||
{ "lmsw", LMSW, WORD },
|
||||
{ "lock", LOCK, WORD },
|
||||
{ "lods", LODS, WORD },
|
||||
{ "lodsb", LODS, BYTE },
|
||||
{ "loop", LOOP, JUMP },
|
||||
{ "loope", LOOPE, JUMP },
|
||||
{ "loopne", LOOPNE, JUMP },
|
||||
{ "loopnz", LOOPNE, JUMP },
|
||||
{ "loopz", LOOPE, JUMP },
|
||||
{ "lsl", LSL, WORD },
|
||||
{ "lss", LSS, WORD },
|
||||
{ "ltr", LTR, WORD },
|
||||
{ "mov", MOV, WORD },
|
||||
{ "movb", MOV, BYTE },
|
||||
{ "movs", MOVS, WORD },
|
||||
{ "movsb", MOVS, BYTE },
|
||||
{ "movsx", MOVSX, WORD },
|
||||
{ "movsxb", MOVSXB, WORD },
|
||||
{ "movzx", MOVZX, WORD },
|
||||
{ "movzxb", MOVZXB, WORD },
|
||||
{ "mul", MUL, WORD },
|
||||
{ "mulb", MUL, BYTE },
|
||||
{ "neg", NEG, WORD },
|
||||
{ "negb", NEG, BYTE },
|
||||
{ "nop", NOP, WORD },
|
||||
{ "not", NOT, WORD },
|
||||
{ "notb", NOT, BYTE },
|
||||
{ "or", OR, WORD },
|
||||
{ "orb", OR, BYTE },
|
||||
{ "out", OUT, WORD },
|
||||
{ "outb", OUT, BYTE },
|
||||
{ "outs", OUTS, WORD },
|
||||
{ "outsb", OUTS, BYTE },
|
||||
{ "pop", POP, WORD },
|
||||
{ "popa", POPA, WORD },
|
||||
{ "popad", POPA, WORD },
|
||||
{ "popf", POPF, WORD },
|
||||
{ "push", PUSH, WORD },
|
||||
{ "pusha", PUSHA, WORD },
|
||||
{ "pushad", PUSHA, WORD },
|
||||
{ "pushf", PUSHF, WORD },
|
||||
{ "rcl", RCL, WORD },
|
||||
{ "rclb", RCL, BYTE },
|
||||
{ "rcr", RCR, WORD },
|
||||
{ "rcrb", RCR, BYTE },
|
||||
{ "ret", RET, JUMP },
|
||||
{ "retf", RETF, JUMP },
|
||||
{ "rol", ROL, WORD },
|
||||
{ "rolb", ROL, BYTE },
|
||||
{ "ror", ROR, WORD },
|
||||
{ "rorb", ROR, BYTE },
|
||||
{ "sahf", SAHF, WORD },
|
||||
{ "sal", SAL, WORD },
|
||||
{ "salb", SAL, BYTE },
|
||||
{ "sar", SAR, WORD },
|
||||
{ "sarb", SAR, BYTE },
|
||||
{ "sbb", SBB, WORD },
|
||||
{ "sbbb", SBB, BYTE },
|
||||
{ "scas", SCAS, WORD },
|
||||
{ "scasb", SCAS, BYTE },
|
||||
{ "seta", SETA, BYTE },
|
||||
{ "setae", SETAE, BYTE },
|
||||
{ "setb", SETB, BYTE },
|
||||
{ "setbe", SETBE, BYTE },
|
||||
{ "sete", SETE, BYTE },
|
||||
{ "setg", SETG, BYTE },
|
||||
{ "setge", SETGE, BYTE },
|
||||
{ "setl", SETL, BYTE },
|
||||
{ "setna", SETBE, BYTE },
|
||||
{ "setnae", SETB, BYTE },
|
||||
{ "setnb", SETAE, BYTE },
|
||||
{ "setnbe", SETA, BYTE },
|
||||
{ "setne", SETNE, BYTE },
|
||||
{ "setng", SETLE, BYTE },
|
||||
{ "setnge", SETL, BYTE },
|
||||
{ "setnl", SETGE, BYTE },
|
||||
{ "setnle", SETG, BYTE },
|
||||
{ "setno", SETNO, BYTE },
|
||||
{ "setnp", SETNP, BYTE },
|
||||
{ "setns", SETNS, BYTE },
|
||||
{ "seto", SETO, BYTE },
|
||||
{ "setp", SETP, BYTE },
|
||||
{ "sets", SETS, BYTE },
|
||||
{ "setz", SETE, BYTE },
|
||||
{ "sgdt", SGDT, WORD },
|
||||
{ "shl", SHL, WORD },
|
||||
{ "shlb", SHL, BYTE },
|
||||
{ "shld", SHLD, WORD },
|
||||
{ "shr", SHR, WORD },
|
||||
{ "shrb", SHR, BYTE },
|
||||
{ "shrd", SHRD, WORD },
|
||||
{ "sidt", SIDT, WORD },
|
||||
{ "sldt", SLDT, WORD },
|
||||
{ "smsw", SMSW, WORD },
|
||||
{ "stc", STC, WORD },
|
||||
{ "std", STD, WORD },
|
||||
{ "sti", STI, WORD },
|
||||
{ "stos", STOS, WORD },
|
||||
{ "stosb", STOS, BYTE },
|
||||
{ "str", STR, WORD },
|
||||
{ "sub", SUB, WORD },
|
||||
{ "subb", SUB, BYTE },
|
||||
{ "test", TEST, WORD },
|
||||
{ "testb", TEST, BYTE },
|
||||
{ "verr", VERR, WORD },
|
||||
{ "verw", VERW, WORD },
|
||||
{ "wait", WAIT, WORD },
|
||||
{ "wbinvd", WBINVD, WORD },
|
||||
{ "xadd", XADD, WORD },
|
||||
{ "xchg", XCHG, WORD },
|
||||
{ "xchgb", XCHG, BYTE },
|
||||
{ "xlat", XLAT, WORD },
|
||||
{ "xor", XOR, WORD },
|
||||
{ "xorb", XOR, BYTE },
|
||||
};
|
||||
|
||||
static enum dialect { ACK, NCC } dialect= ACK;
|
||||
|
||||
void ack_parse_init(char *file)
|
||||
/* Prepare parsing of an ACK assembly file. */
|
||||
{
|
||||
tok_init(file, '!');
|
||||
}
|
||||
|
||||
void ncc_parse_init(char *file)
|
||||
/* Prepare parsing of an ACK Xenix assembly file. See emit_ack.c for comments
|
||||
* on this fine assembly dialect.
|
||||
*/
|
||||
{
|
||||
dialect= NCC;
|
||||
ack_parse_init(file);
|
||||
}
|
||||
|
||||
static void zap(void)
|
||||
/* An error, zap the rest of the line. */
|
||||
{
|
||||
token_t *t;
|
||||
|
||||
while ((t= get_token(0))->type != T_EOF && t->symbol != ';')
|
||||
skip_token(1);
|
||||
}
|
||||
|
||||
static mnemonic_t *search_mnem(char *name)
|
||||
/* Binary search for a mnemonic. (That's why the table is sorted.) */
|
||||
{
|
||||
int low, mid, high;
|
||||
int cmp;
|
||||
mnemonic_t *m;
|
||||
|
||||
low= 0;
|
||||
high= arraysize(mnemtab)-1;
|
||||
while (low <= high) {
|
||||
mid= (low + high) / 2;
|
||||
m= &mnemtab[mid];
|
||||
|
||||
if ((cmp= strcmp(name, m->name)) == 0) return m;
|
||||
|
||||
if (cmp < 0) high= mid-1; else low= mid+1;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static expression_t *ack_get_C_expression(int *pn)
|
||||
/* Read a "C-like" expression. Note that we don't worry about precedence,
|
||||
* the expression is printed later like it is read. If the target language
|
||||
* does not have all the operators (like ~) then this has to be repaired by
|
||||
* changing the source file. (No problem, you still have one source file
|
||||
* to maintain, not two.)
|
||||
*/
|
||||
{
|
||||
expression_t *e, *a1, *a2;
|
||||
token_t *t;
|
||||
|
||||
if ((t= get_token(*pn))->symbol == '[') {
|
||||
/* [ expr ]: grouping. */
|
||||
(*pn)++;
|
||||
if ((a1= ack_get_C_expression(pn)) == nil) return nil;
|
||||
if (get_token(*pn)->symbol != ']') {
|
||||
parse_err(1, t, "missing ]\n");
|
||||
del_expr(a1);
|
||||
return nil;
|
||||
}
|
||||
(*pn)++;
|
||||
e= new_expr();
|
||||
e->operator= '[';
|
||||
e->middle= a1;
|
||||
} else
|
||||
if (t->type == T_WORD || t->type == T_STRING) {
|
||||
/* Label, number, or string. */
|
||||
e= new_expr();
|
||||
e->operator= t->type == T_WORD ? 'W' : 'S';
|
||||
e->name= allocate(nil, (t->len+1) * sizeof(e->name[0]));
|
||||
memcpy(e->name, t->name, t->len+1);
|
||||
e->len= t->len;
|
||||
(*pn)++;
|
||||
} else
|
||||
if (t->symbol == '+' || t->symbol == '-' || t->symbol == '~') {
|
||||
/* Unary operator. */
|
||||
(*pn)++;
|
||||
if ((a1= ack_get_C_expression(pn)) == nil) return nil;
|
||||
e= new_expr();
|
||||
e->operator= t->symbol;
|
||||
e->middle= a1;
|
||||
} else {
|
||||
parse_err(1, t, "expression syntax error\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
switch ((t= get_token(*pn))->symbol) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case '%':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case S_LEFTSHIFT:
|
||||
case S_RIGHTSHIFT:
|
||||
(*pn)++;
|
||||
a1= e;
|
||||
if ((a2= ack_get_C_expression(pn)) == nil) {
|
||||
del_expr(a1);
|
||||
return nil;
|
||||
}
|
||||
e= new_expr();
|
||||
e->operator= t->symbol;
|
||||
e->left= a1;
|
||||
e->right= a2;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expression_t *ack_get_operand(int *pn, int deref)
|
||||
/* Get something like: (memory), offset(base)(index*scale), or simpler. */
|
||||
{
|
||||
expression_t *e, *offset, *base, *index;
|
||||
token_t *t;
|
||||
int c;
|
||||
|
||||
/* Is it (memory)? */
|
||||
if (get_token(*pn)->symbol == '('
|
||||
&& ((t= get_token(*pn + 1))->type != T_WORD
|
||||
|| !isregister(t->name))
|
||||
) {
|
||||
/* A memory dereference. */
|
||||
(*pn)++;
|
||||
if ((offset= ack_get_C_expression(pn)) == nil) return nil;
|
||||
if (get_token(*pn)->symbol != ')') {
|
||||
parse_err(1, t, "operand syntax error\n");
|
||||
del_expr(offset);
|
||||
return nil;
|
||||
}
|
||||
(*pn)++;
|
||||
e= new_expr();
|
||||
e->operator= '(';
|
||||
e->middle= offset;
|
||||
return e;
|
||||
}
|
||||
|
||||
/* #constant? */
|
||||
if (dialect == NCC && deref
|
||||
&& ((c= get_token(*pn)->symbol) == '#' || c == '*')) {
|
||||
/* NCC: mov ax,#constant -> ACK: mov ax,constant */
|
||||
(*pn)++;
|
||||
return ack_get_C_expression(pn);
|
||||
}
|
||||
|
||||
/* @address? */
|
||||
if (dialect == NCC && get_token(*pn)->symbol == '@') {
|
||||
/* NCC: jmp @address -> ACK: jmp (address) */
|
||||
(*pn)++;
|
||||
if ((offset= ack_get_operand(pn, deref)) == nil) return nil;
|
||||
e= new_expr();
|
||||
e->operator= '(';
|
||||
e->middle= offset;
|
||||
return e;
|
||||
}
|
||||
|
||||
/* Offset? */
|
||||
if (get_token(*pn)->symbol != '(') {
|
||||
/* There is an offset. */
|
||||
if ((offset= ack_get_C_expression(pn)) == nil) return nil;
|
||||
} else {
|
||||
/* No offset. */
|
||||
offset= nil;
|
||||
}
|
||||
|
||||
/* (base)? */
|
||||
if (get_token(*pn)->symbol == '('
|
||||
&& (t= get_token(*pn + 1))->type == T_WORD
|
||||
&& isregister(t->name)
|
||||
&& get_token(*pn + 2)->symbol == ')'
|
||||
) {
|
||||
/* A base register expression. */
|
||||
base= new_expr();
|
||||
base->operator= 'B';
|
||||
base->name= copystr(t->name);
|
||||
(*pn)+= 3;
|
||||
} else {
|
||||
/* No base register expression. */
|
||||
base= nil;
|
||||
}
|
||||
|
||||
/* (index*scale)? */
|
||||
if (get_token(*pn)->symbol == '(') {
|
||||
/* An index most likely. */
|
||||
token_t *m= nil;
|
||||
|
||||
if (!( /* This must be true: */
|
||||
(t= get_token(*pn + 1))->type == T_WORD
|
||||
&& isregister(t->name)
|
||||
&& (get_token(*pn + 2)->symbol == ')' || (
|
||||
get_token(*pn + 2)->symbol == '*'
|
||||
&& (m= get_token(*pn + 3))->type == T_WORD
|
||||
&& strchr("1248", m->name[0]) != nil
|
||||
&& m->name[1] == 0
|
||||
&& get_token(*pn + 4)->symbol == ')'
|
||||
))
|
||||
)) {
|
||||
/* Alas it isn't */
|
||||
parse_err(1, t, "operand syntax error\n");
|
||||
del_expr(offset);
|
||||
del_expr(base);
|
||||
return nil;
|
||||
}
|
||||
/* Found an index. */
|
||||
index= new_expr();
|
||||
index->operator= m == nil ? '1' : m->name[0];
|
||||
index->name= copystr(t->name);
|
||||
(*pn)+= (m == nil ? 3 : 5);
|
||||
} else {
|
||||
/* No index. */
|
||||
index= nil;
|
||||
}
|
||||
|
||||
if (dialect == NCC && deref && base == nil && index == nil
|
||||
&& !(offset != nil && offset->operator == 'W'
|
||||
&& isregister(offset->name))
|
||||
) {
|
||||
/* NCC: mov ax,thing -> ACK mov ax,(thing) */
|
||||
e= new_expr();
|
||||
e->operator= '(';
|
||||
e->middle= offset;
|
||||
return e;
|
||||
}
|
||||
|
||||
if (base == nil && index == nil) {
|
||||
/* Return a lone offset as is. */
|
||||
e= offset;
|
||||
} else {
|
||||
e= new_expr();
|
||||
e->operator= 'O';
|
||||
e->left= offset;
|
||||
e->middle= base;
|
||||
e->right= index;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expression_t *ack_get_oplist(int *pn, int deref)
|
||||
/* Get a comma (or colon for jmpf and callf) separated list of instruction
|
||||
* operands.
|
||||
*/
|
||||
{
|
||||
expression_t *e, *o1, *o2;
|
||||
token_t *t;
|
||||
|
||||
if ((e= ack_get_operand(pn, deref)) == nil) return nil;
|
||||
|
||||
if ((t= get_token(*pn))->symbol == ',' || t->symbol == ':') {
|
||||
o1= e;
|
||||
(*pn)++;
|
||||
if ((o2= ack_get_oplist(pn, deref)) == nil) {
|
||||
del_expr(o1);
|
||||
return nil;
|
||||
}
|
||||
e= new_expr();
|
||||
e->operator= ',';
|
||||
e->left= o1;
|
||||
e->right= o2;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static asm86_t *ack_get_statement(void)
|
||||
/* Get a pseudo op or machine instruction with arguments. */
|
||||
{
|
||||
token_t *t= get_token(0);
|
||||
asm86_t *a;
|
||||
mnemonic_t *m;
|
||||
int n;
|
||||
int prefix_seen;
|
||||
int oaz_prefix;
|
||||
int deref;
|
||||
|
||||
assert(t->type == T_WORD);
|
||||
|
||||
if (strcmp(t->name, ".sect") == 0) {
|
||||
/* .sect .text etc. Accept only four segment names. */
|
||||
skip_token(1);
|
||||
t= get_token(0);
|
||||
if (t->type != T_WORD || (
|
||||
strcmp(t->name, ".text") != 0
|
||||
&& strcmp(t->name, ".rom") != 0
|
||||
&& strcmp(t->name, ".data") != 0
|
||||
&& strcmp(t->name, ".bss") != 0
|
||||
&& strcmp(t->name, ".end") != 0
|
||||
)) {
|
||||
parse_err(1, t, "weird section name to .sect\n");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
a= new_asm86();
|
||||
|
||||
/* Process instruction prefixes. */
|
||||
oaz_prefix= 0;
|
||||
for (prefix_seen= 0;; prefix_seen= 1) {
|
||||
if (strcmp(t->name, "o16") == 0) {
|
||||
if (use16()) {
|
||||
parse_err(1, t, "o16 in an 8086 section\n");
|
||||
}
|
||||
oaz_prefix|= OPZ;
|
||||
} else
|
||||
if (strcmp(t->name, "o32") == 0) {
|
||||
if (use32()) {
|
||||
parse_err(1, t, "o32 in an 80386 section\n");
|
||||
}
|
||||
oaz_prefix|= OPZ;
|
||||
} else
|
||||
if (strcmp(t->name, "a16") == 0) {
|
||||
if (use16()) {
|
||||
parse_err(1, t, "a16 in an 8086 section\n");
|
||||
}
|
||||
oaz_prefix|= ADZ;
|
||||
} else
|
||||
if (strcmp(t->name, "a32") == 0) {
|
||||
if (use32()) {
|
||||
parse_err(1, t, "a32 in an 80386 section\n");
|
||||
}
|
||||
oaz_prefix|= ADZ;
|
||||
} else
|
||||
if (strcmp(t->name, "rep") == 0
|
||||
|| strcmp(t->name, "repe") == 0
|
||||
|| strcmp(t->name, "repne") == 0
|
||||
|| strcmp(t->name, "repz") == 0
|
||||
|| strcmp(t->name, "repnz") == 0
|
||||
) {
|
||||
if (a->rep != ONCE) {
|
||||
parse_err(1, t,
|
||||
"can't have more than one rep\n");
|
||||
}
|
||||
switch (t->name[3]) {
|
||||
case 0: a->rep= REP; break;
|
||||
case 'e':
|
||||
case 'z': a->rep= REPE; break;
|
||||
case 'n': a->rep= REPNE; break;
|
||||
}
|
||||
} else
|
||||
if (strchr("cdefgs", t->name[0]) != nil
|
||||
&& strcmp(t->name+1, "seg") == 0) {
|
||||
if (a->seg != DEFSEG) {
|
||||
parse_err(1, t,
|
||||
"can't have more than one segment prefix\n");
|
||||
}
|
||||
switch (t->name[0]) {
|
||||
case 'c': a->seg= CSEG; break;
|
||||
case 'd': a->seg= DSEG; break;
|
||||
case 'e': a->seg= ESEG; break;
|
||||
case 'f': a->seg= FSEG; break;
|
||||
case 'g': a->seg= GSEG; break;
|
||||
case 's': a->seg= SSEG; break;
|
||||
}
|
||||
} else
|
||||
if (!prefix_seen) {
|
||||
/* No prefix here, get out! */
|
||||
break;
|
||||
} else {
|
||||
/* No more prefixes, next must be an instruction. */
|
||||
if (t->type != T_WORD
|
||||
|| (m= search_mnem(t->name)) == nil
|
||||
|| m->optype == PSEUDO
|
||||
) {
|
||||
parse_err(1, t,
|
||||
"machine instruction expected after instruction prefix\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
if (oaz_prefix != 0 && m->optype != JUMP
|
||||
&& m->optype != WORD) {
|
||||
parse_err(1, t,
|
||||
"'%s' can't have an operand size prefix\n", m->name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip the prefix and extra newlines. */
|
||||
do {
|
||||
skip_token(1);
|
||||
} while ((t= get_token(0))->symbol == ';');
|
||||
}
|
||||
|
||||
/* All the readahead being done upsets the line counter. */
|
||||
a->line= t->line;
|
||||
|
||||
/* Read a machine instruction or pseudo op. */
|
||||
if ((m= search_mnem(t->name)) == nil) {
|
||||
parse_err(1, t, "unknown instruction '%s'\n", t->name);
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
a->opcode= m->opcode;
|
||||
a->optype= m->optype;
|
||||
a->oaz= oaz_prefix;
|
||||
|
||||
switch (a->opcode) {
|
||||
case IN:
|
||||
case OUT:
|
||||
case INT:
|
||||
deref= 0;
|
||||
break;
|
||||
default:
|
||||
deref= (a->optype >= BYTE);
|
||||
}
|
||||
n= 1;
|
||||
if (get_token(1)->symbol != ';'
|
||||
&& (a->args= ack_get_oplist(&n, deref)) == nil) {
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
if (get_token(n)->symbol != ';') {
|
||||
parse_err(1, t, "garbage at end of instruction\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
switch (a->opcode) {
|
||||
case DOT_ALIGN:
|
||||
/* Restrict .align to have a single numeric argument, some
|
||||
* assemblers think of the argument as a power of two, so
|
||||
* we need to be able to change the value.
|
||||
*/
|
||||
if (a->args == nil || a->args->operator != 'W'
|
||||
|| !isanumber(a->args->name)) {
|
||||
parse_err(1, t,
|
||||
".align is restricted to one numeric argument\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
case JMPF:
|
||||
case CALLF:
|
||||
/* NCC jmpf off,seg -> ACK jmpf seg:off */
|
||||
if (dialect == NCC && a->args != nil
|
||||
&& a->args->operator == ',') {
|
||||
expression_t *t;
|
||||
|
||||
t= a->args->left;
|
||||
a->args->left= a->args->right;
|
||||
a->args->right= t;
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
case JMP:
|
||||
case CALL:
|
||||
/* NCC jmp @(reg) -> ACK jmp (reg) */
|
||||
if (dialect == NCC && a->args != nil && (
|
||||
(a->args->operator == '('
|
||||
&& a->args->middle != nil
|
||||
&& a->args->middle->operator == 'O')
|
||||
|| (a->args->operator == 'O'
|
||||
&& a->args->left == nil
|
||||
&& a->args->middle != nil
|
||||
&& a->args->right == nil)
|
||||
)) {
|
||||
expression_t *t;
|
||||
|
||||
t= a->args;
|
||||
a->args= a->args->middle;
|
||||
t->middle= nil;
|
||||
del_expr(t);
|
||||
if (a->args->operator == 'B') a->args->operator= 'W';
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
skip_token(n+1);
|
||||
return a;
|
||||
}
|
||||
|
||||
asm86_t *ack_get_instruction(void)
|
||||
{
|
||||
asm86_t *a= nil;
|
||||
expression_t *e;
|
||||
token_t *t;
|
||||
|
||||
while ((t= get_token(0))->symbol == ';')
|
||||
skip_token(1);
|
||||
|
||||
if (t->type == T_EOF) return nil;
|
||||
|
||||
if (t->symbol == '#') {
|
||||
/* Preprocessor line and file change. */
|
||||
|
||||
if ((t= get_token(1))->type != T_WORD || !isanumber(t->name)
|
||||
|| get_token(2)->type != T_STRING
|
||||
) {
|
||||
parse_err(1, t, "file not preprocessed?\n");
|
||||
zap();
|
||||
} else {
|
||||
set_file(get_token(2)->name,
|
||||
strtol(get_token(1)->name, nil, 0) - 1);
|
||||
|
||||
/* GNU CPP adds extra cruft, simply zap the line. */
|
||||
zap();
|
||||
}
|
||||
a= ack_get_instruction();
|
||||
} else
|
||||
if (t->type == T_WORD && get_token(1)->symbol == ':') {
|
||||
/* A label definition. */
|
||||
a= new_asm86();
|
||||
a->line= t->line;
|
||||
a->opcode= DOT_LABEL;
|
||||
a->optype= PSEUDO;
|
||||
a->args= e= new_expr();
|
||||
e->operator= ':';
|
||||
e->name= copystr(t->name);
|
||||
skip_token(2);
|
||||
} else
|
||||
if (t->type == T_WORD && get_token(1)->symbol == '=') {
|
||||
int n= 2;
|
||||
|
||||
if ((e= ack_get_C_expression(&n)) == nil) {
|
||||
zap();
|
||||
a= ack_get_instruction();
|
||||
} else
|
||||
if (get_token(n)->symbol != ';') {
|
||||
parse_err(1, t, "garbage after assignment\n");
|
||||
zap();
|
||||
a= ack_get_instruction();
|
||||
} else {
|
||||
a= new_asm86();
|
||||
a->line= t->line;
|
||||
a->opcode= DOT_EQU;
|
||||
a->optype= PSEUDO;
|
||||
a->args= new_expr();
|
||||
a->args->operator= '=';
|
||||
a->args->name= copystr(t->name);
|
||||
a->args->middle= e;
|
||||
skip_token(n+1);
|
||||
}
|
||||
} else
|
||||
if (t->type == T_WORD) {
|
||||
if ((a= ack_get_statement()) == nil) {
|
||||
zap();
|
||||
a= ack_get_instruction();
|
||||
}
|
||||
} else {
|
||||
parse_err(1, t, "syntax error\n");
|
||||
zap();
|
||||
a= ack_get_instruction();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
asm86_t *ncc_get_instruction(void)
|
||||
{
|
||||
return ack_get_instruction();
|
||||
}
|
|
@ -1,940 +0,0 @@
|
|||
/* parse_bas.c - parse BCC AS assembly Author: Kees J. Bot
|
||||
* 13 Nov 1994
|
||||
*/
|
||||
#define nil 0
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "asmconv.h"
|
||||
#include "token.h"
|
||||
#include "asm86.h"
|
||||
#include "languages.h"
|
||||
|
||||
typedef struct mnemonic { /* BAS mnemonics translation table. */
|
||||
char *name;
|
||||
opcode_t opcode;
|
||||
optype_t optype;
|
||||
} mnemonic_t;
|
||||
|
||||
static mnemonic_t mnemtab[] = { /* This array is sorted. */
|
||||
{ ".align", DOT_ALIGN, PSEUDO },
|
||||
{ ".ascii", DOT_ASCII, PSEUDO },
|
||||
{ ".asciz", DOT_ASCIZ, PSEUDO },
|
||||
{ ".assert", DOT_ASSERT, PSEUDO },
|
||||
{ ".base", DOT_BASE, PSEUDO },
|
||||
{ ".blkb", DOT_SPACE, PSEUDO },
|
||||
{ ".bss", DOT_BSS, PSEUDO },
|
||||
{ ".byte", DOT_DATA1, PSEUDO },
|
||||
{ ".comm", DOT_COMM, PSEUDO },
|
||||
{ ".data", DOT_DATA, PSEUDO },
|
||||
{ ".define", DOT_DEFINE, PSEUDO },
|
||||
{ ".end", DOT_END, PSEUDO },
|
||||
{ ".even", DOT_ALIGN, PSEUDO },
|
||||
{ ".extern", DOT_EXTERN, PSEUDO },
|
||||
{ ".file", DOT_FILE, PSEUDO },
|
||||
{ ".globl", DOT_DEFINE, PSEUDO },
|
||||
{ ".lcomm", DOT_LCOMM, PSEUDO },
|
||||
{ ".line", DOT_LINE, PSEUDO },
|
||||
{ ".list", DOT_LIST, PSEUDO },
|
||||
{ ".long", DOT_DATA4, PSEUDO },
|
||||
{ ".nolist", DOT_NOLIST, PSEUDO },
|
||||
{ ".rom", DOT_ROM, PSEUDO },
|
||||
{ ".space", DOT_SPACE, PSEUDO },
|
||||
{ ".symb", DOT_SYMB, PSEUDO },
|
||||
{ ".text", DOT_TEXT, PSEUDO },
|
||||
{ ".use16", DOT_USE16, PSEUDO },
|
||||
{ ".use32", DOT_USE32, PSEUDO },
|
||||
{ ".word", DOT_DATA2, PSEUDO },
|
||||
{ ".zerob", DOT_SPACE, PSEUDO },
|
||||
{ ".zerow", DOT_SPACE, PSEUDO },
|
||||
{ "aaa", AAA, WORD },
|
||||
{ "aad", AAD, WORD },
|
||||
{ "aam", AAM, WORD },
|
||||
{ "aas", AAS, WORD },
|
||||
{ "adc", ADC, WORD },
|
||||
{ "add", ADD, WORD },
|
||||
{ "and", AND, WORD },
|
||||
{ "arpl", ARPL, WORD },
|
||||
{ "bc", JB, JUMP },
|
||||
{ "beq", JE, JUMP },
|
||||
{ "bge", JGE, JUMP },
|
||||
{ "bgt", JG, JUMP },
|
||||
{ "bhi", JA, JUMP },
|
||||
{ "bhis", JAE, JUMP },
|
||||
{ "ble", JLE, JUMP },
|
||||
{ "blo", JB, JUMP },
|
||||
{ "blos", JBE, JUMP },
|
||||
{ "blt", JL, JUMP },
|
||||
{ "bnc", JAE, JUMP },
|
||||
{ "bne", JNE, JUMP },
|
||||
{ "bound", BOUND, WORD },
|
||||
{ "br", JMP, JUMP },
|
||||
{ "bsf", BSF, WORD },
|
||||
{ "bsr", BSR, WORD },
|
||||
{ "bswap", BSWAP, WORD },
|
||||
{ "bt", BT, WORD },
|
||||
{ "btc", BTC, WORD },
|
||||
{ "btr", BTR, WORD },
|
||||
{ "bts", BTS, WORD },
|
||||
{ "bz", JE, JUMP },
|
||||
{ "call", CALL, JUMP },
|
||||
{ "callf", CALLF, JUMP },
|
||||
{ "cbw", CBW, WORD },
|
||||
{ "cdq", CWD, WORD },
|
||||
{ "clc", CLC, WORD },
|
||||
{ "cld", CLD, WORD },
|
||||
{ "cli", CLI, WORD },
|
||||
{ "clts", CLTS, WORD },
|
||||
{ "cmc", CMC, WORD },
|
||||
{ "cmp", CMP, WORD },
|
||||
{ "cmps", CMPS, WORD },
|
||||
{ "cmpsb", CMPS, BYTE },
|
||||
{ "cmpxchg", CMPXCHG, WORD },
|
||||
{ "cwd", CWD, WORD },
|
||||
{ "cwde", CBW, WORD },
|
||||
{ "daa", DAA, WORD },
|
||||
{ "das", DAS, WORD },
|
||||
{ "dd", DOT_DATA4, PSEUDO },
|
||||
{ "dec", DEC, WORD },
|
||||
{ "div", DIV, WORD },
|
||||
{ "enter", ENTER, WORD },
|
||||
{ "export", DOT_DEFINE, PSEUDO },
|
||||
{ "f2xm1", F2XM1, WORD },
|
||||
{ "fabs", FABS, WORD },
|
||||
{ "fadd", FADD, WORD },
|
||||
{ "faddd", FADDD, WORD },
|
||||
{ "faddp", FADDP, WORD },
|
||||
{ "fadds", FADDS, WORD },
|
||||
{ "fbld", FBLD, WORD },
|
||||
{ "fbstp", FBSTP, WORD },
|
||||
{ "fchs", FCHS, WORD },
|
||||
{ "fclex", FCLEX, WORD },
|
||||
{ "fcomd", FCOMD, WORD },
|
||||
{ "fcompd", FCOMPD, WORD },
|
||||
{ "fcompp", FCOMPP, WORD },
|
||||
{ "fcomps", FCOMPS, WORD },
|
||||
{ "fcoms", FCOMS, WORD },
|
||||
{ "fcos", FCOS, WORD },
|
||||
{ "fdecstp", FDECSTP, WORD },
|
||||
{ "fdivd", FDIVD, WORD },
|
||||
{ "fdivp", FDIVP, WORD },
|
||||
{ "fdivrd", FDIVRD, WORD },
|
||||
{ "fdivrp", FDIVRP, WORD },
|
||||
{ "fdivrs", FDIVRS, WORD },
|
||||
{ "fdivs", FDIVS, WORD },
|
||||
{ "ffree", FFREE, WORD },
|
||||
{ "fiaddl", FIADDL, WORD },
|
||||
{ "fiadds", FIADDS, WORD },
|
||||
{ "ficom", FICOM, WORD },
|
||||
{ "ficomp", FICOMP, WORD },
|
||||
{ "fidivl", FIDIVL, WORD },
|
||||
{ "fidivrl", FIDIVRL, WORD },
|
||||
{ "fidivrs", FIDIVRS, WORD },
|
||||
{ "fidivs", FIDIVS, WORD },
|
||||
{ "fildl", FILDL, WORD },
|
||||
{ "fildq", FILDQ, WORD },
|
||||
{ "filds", FILDS, WORD },
|
||||
{ "fimull", FIMULL, WORD },
|
||||
{ "fimuls", FIMULS, WORD },
|
||||
{ "fincstp", FINCSTP, WORD },
|
||||
{ "finit", FINIT, WORD },
|
||||
{ "fistl", FISTL, WORD },
|
||||
{ "fistp", FISTP, WORD },
|
||||
{ "fists", FISTS, WORD },
|
||||
{ "fisubl", FISUBL, WORD },
|
||||
{ "fisubrl", FISUBRL, WORD },
|
||||
{ "fisubrs", FISUBRS, WORD },
|
||||
{ "fisubs", FISUBS, WORD },
|
||||
{ "fld1", FLD1, WORD },
|
||||
{ "fldcw", FLDCW, WORD },
|
||||
{ "fldd", FLDD, WORD },
|
||||
{ "fldenv", FLDENV, WORD },
|
||||
{ "fldl2e", FLDL2E, WORD },
|
||||
{ "fldl2t", FLDL2T, WORD },
|
||||
{ "fldlg2", FLDLG2, WORD },
|
||||
{ "fldln2", FLDLN2, WORD },
|
||||
{ "fldpi", FLDPI, WORD },
|
||||
{ "flds", FLDS, WORD },
|
||||
{ "fldx", FLDX, WORD },
|
||||
{ "fldz", FLDZ, WORD },
|
||||
{ "fmuld", FMULD, WORD },
|
||||
{ "fmulp", FMULP, WORD },
|
||||
{ "fmuls", FMULS, WORD },
|
||||
{ "fnop", FNOP, WORD },
|
||||
{ "fpatan", FPATAN, WORD },
|
||||
{ "fprem", FPREM, WORD },
|
||||
{ "fprem1", FPREM1, WORD },
|
||||
{ "fptan", FPTAN, WORD },
|
||||
{ "frndint", FRNDINT, WORD },
|
||||
{ "frstor", FRSTOR, WORD },
|
||||
{ "fsave", FSAVE, WORD },
|
||||
{ "fscale", FSCALE, WORD },
|
||||
{ "fsin", FSIN, WORD },
|
||||
{ "fsincos", FSINCOS, WORD },
|
||||
{ "fsqrt", FSQRT, WORD },
|
||||
{ "fstcw", FSTCW, WORD },
|
||||
{ "fstd", FSTD, WORD },
|
||||
{ "fstenv", FSTENV, WORD },
|
||||
{ "fstpd", FSTPD, WORD },
|
||||
{ "fstps", FSTPS, WORD },
|
||||
{ "fstpx", FSTPX, WORD },
|
||||
{ "fsts", FSTS, WORD },
|
||||
{ "fstsw", FSTSW, WORD },
|
||||
{ "fsubd", FSUBD, WORD },
|
||||
{ "fsubp", FSUBP, WORD },
|
||||
{ "fsubpr", FSUBPR, WORD },
|
||||
{ "fsubrd", FSUBRD, WORD },
|
||||
{ "fsubrs", FSUBRS, WORD },
|
||||
{ "fsubs", FSUBS, WORD },
|
||||
{ "ftst", FTST, WORD },
|
||||
{ "fucom", FUCOM, WORD },
|
||||
{ "fucomp", FUCOMP, WORD },
|
||||
{ "fucompp", FUCOMPP, WORD },
|
||||
{ "fxam", FXAM, WORD },
|
||||
{ "fxch", FXCH, WORD },
|
||||
{ "fxtract", FXTRACT, WORD },
|
||||
{ "fyl2x", FYL2X, WORD },
|
||||
{ "fyl2xp1", FYL2XP1, WORD },
|
||||
{ "hlt", HLT, WORD },
|
||||
{ "idiv", IDIV, WORD },
|
||||
{ "imul", IMUL, WORD },
|
||||
{ "in", IN, WORD },
|
||||
{ "inb", IN, BYTE },
|
||||
{ "inc", INC, WORD },
|
||||
{ "ins", INS, WORD },
|
||||
{ "insb", INS, BYTE },
|
||||
{ "int", INT, WORD },
|
||||
{ "into", INTO, JUMP },
|
||||
{ "invd", INVD, WORD },
|
||||
{ "invlpg", INVLPG, WORD },
|
||||
{ "iret", IRET, JUMP },
|
||||
{ "iretd", IRETD, JUMP },
|
||||
{ "j", JMP, JUMP },
|
||||
{ "ja", JA, JUMP },
|
||||
{ "jae", JAE, JUMP },
|
||||
{ "jb", JB, JUMP },
|
||||
{ "jbe", JBE, JUMP },
|
||||
{ "jc", JB, JUMP },
|
||||
{ "jcxz", JCXZ, JUMP },
|
||||
{ "je", JE, JUMP },
|
||||
{ "jecxz", JCXZ, JUMP },
|
||||
{ "jeq", JE, JUMP },
|
||||
{ "jg", JG, JUMP },
|
||||
{ "jge", JGE, JUMP },
|
||||
{ "jgt", JG, JUMP },
|
||||
{ "jhi", JA, JUMP },
|
||||
{ "jhis", JAE, JUMP },
|
||||
{ "jl", JL, JUMP },
|
||||
{ "jle", JLE, JUMP },
|
||||
{ "jlo", JB, JUMP },
|
||||
{ "jlos", JBE, JUMP },
|
||||
{ "jlt", JL, JUMP },
|
||||
{ "jmp", JMP, JUMP },
|
||||
{ "jmpf", JMPF, JUMP },
|
||||
{ "jna", JBE, JUMP },
|
||||
{ "jnae", JB, JUMP },
|
||||
{ "jnb", JAE, JUMP },
|
||||
{ "jnbe", JA, JUMP },
|
||||
{ "jnc", JAE, JUMP },
|
||||
{ "jne", JNE, JUMP },
|
||||
{ "jng", JLE, JUMP },
|
||||
{ "jnge", JL, JUMP },
|
||||
{ "jnl", JGE, JUMP },
|
||||
{ "jnle", JG, JUMP },
|
||||
{ "jno", JNO, JUMP },
|
||||
{ "jnp", JNP, JUMP },
|
||||
{ "jns", JNS, JUMP },
|
||||
{ "jnz", JNE, JUMP },
|
||||
{ "jo", JO, JUMP },
|
||||
{ "jp", JP, JUMP },
|
||||
{ "js", JS, JUMP },
|
||||
{ "jz", JE, JUMP },
|
||||
{ "lahf", LAHF, WORD },
|
||||
{ "lar", LAR, WORD },
|
||||
{ "lds", LDS, WORD },
|
||||
{ "lea", LEA, WORD },
|
||||
{ "leave", LEAVE, WORD },
|
||||
{ "les", LES, WORD },
|
||||
{ "lfs", LFS, WORD },
|
||||
{ "lgdt", LGDT, WORD },
|
||||
{ "lgs", LGS, WORD },
|
||||
{ "lidt", LIDT, WORD },
|
||||
{ "lldt", LLDT, WORD },
|
||||
{ "lmsw", LMSW, WORD },
|
||||
{ "lock", LOCK, WORD },
|
||||
{ "lods", LODS, WORD },
|
||||
{ "lodsb", LODS, BYTE },
|
||||
{ "loop", LOOP, JUMP },
|
||||
{ "loope", LOOPE, JUMP },
|
||||
{ "loopne", LOOPNE, JUMP },
|
||||
{ "loopnz", LOOPNE, JUMP },
|
||||
{ "loopz", LOOPE, JUMP },
|
||||
{ "lsl", LSL, WORD },
|
||||
{ "lss", LSS, WORD },
|
||||
{ "ltr", LTR, WORD },
|
||||
{ "mov", MOV, WORD },
|
||||
{ "movs", MOVS, WORD },
|
||||
{ "movsb", MOVS, BYTE },
|
||||
{ "movsx", MOVSX, WORD },
|
||||
{ "movzx", MOVZX, WORD },
|
||||
{ "mul", MUL, WORD },
|
||||
{ "neg", NEG, WORD },
|
||||
{ "nop", NOP, WORD },
|
||||
{ "not", NOT, WORD },
|
||||
{ "or", OR, WORD },
|
||||
{ "out", OUT, WORD },
|
||||
{ "outb", OUT, BYTE },
|
||||
{ "outs", OUTS, WORD },
|
||||
{ "outsb", OUTS, BYTE },
|
||||
{ "pop", POP, WORD },
|
||||
{ "popa", POPA, WORD },
|
||||
{ "popad", POPA, WORD },
|
||||
{ "popf", POPF, WORD },
|
||||
{ "popfd", POPF, WORD },
|
||||
{ "push", PUSH, WORD },
|
||||
{ "pusha", PUSHA, WORD },
|
||||
{ "pushad", PUSHA, WORD },
|
||||
{ "pushf", PUSHF, WORD },
|
||||
{ "pushfd", PUSHF, WORD },
|
||||
{ "rcl", RCL, WORD },
|
||||
{ "rcr", RCR, WORD },
|
||||
{ "ret", RET, JUMP },
|
||||
{ "retf", RETF, JUMP },
|
||||
{ "rol", ROL, WORD },
|
||||
{ "ror", ROR, WORD },
|
||||
{ "sahf", SAHF, WORD },
|
||||
{ "sal", SAL, WORD },
|
||||
{ "sar", SAR, WORD },
|
||||
{ "sbb", SBB, WORD },
|
||||
{ "scas", SCAS, WORD },
|
||||
{ "seta", SETA, BYTE },
|
||||
{ "setae", SETAE, BYTE },
|
||||
{ "setb", SETB, BYTE },
|
||||
{ "setbe", SETBE, BYTE },
|
||||
{ "sete", SETE, BYTE },
|
||||
{ "setg", SETG, BYTE },
|
||||
{ "setge", SETGE, BYTE },
|
||||
{ "setl", SETL, BYTE },
|
||||
{ "setna", SETBE, BYTE },
|
||||
{ "setnae", SETB, BYTE },
|
||||
{ "setnb", SETAE, BYTE },
|
||||
{ "setnbe", SETA, BYTE },
|
||||
{ "setne", SETNE, BYTE },
|
||||
{ "setng", SETLE, BYTE },
|
||||
{ "setnge", SETL, BYTE },
|
||||
{ "setnl", SETGE, BYTE },
|
||||
{ "setnle", SETG, BYTE },
|
||||
{ "setno", SETNO, BYTE },
|
||||
{ "setnp", SETNP, BYTE },
|
||||
{ "setns", SETNS, BYTE },
|
||||
{ "seto", SETO, BYTE },
|
||||
{ "setp", SETP, BYTE },
|
||||
{ "sets", SETS, BYTE },
|
||||
{ "setz", SETE, BYTE },
|
||||
{ "sgdt", SGDT, WORD },
|
||||
{ "shl", SHL, WORD },
|
||||
{ "shld", SHLD, WORD },
|
||||
{ "shr", SHR, WORD },
|
||||
{ "shrd", SHRD, WORD },
|
||||
{ "sidt", SIDT, WORD },
|
||||
{ "sldt", SLDT, WORD },
|
||||
{ "smsw", SMSW, WORD },
|
||||
{ "stc", STC, WORD },
|
||||
{ "std", STD, WORD },
|
||||
{ "sti", STI, WORD },
|
||||
{ "stos", STOS, WORD },
|
||||
{ "stosb", STOS, BYTE },
|
||||
{ "str", STR, WORD },
|
||||
{ "sub", SUB, WORD },
|
||||
{ "test", TEST, WORD },
|
||||
{ "verr", VERR, WORD },
|
||||
{ "verw", VERW, WORD },
|
||||
{ "wait", WAIT, WORD },
|
||||
{ "wbinvd", WBINVD, WORD },
|
||||
{ "xadd", XADD, WORD },
|
||||
{ "xchg", XCHG, WORD },
|
||||
{ "xlat", XLAT, WORD },
|
||||
{ "xor", XOR, WORD },
|
||||
};
|
||||
|
||||
void bas_parse_init(char *file)
|
||||
/* Prepare parsing of an BAS assembly file. */
|
||||
{
|
||||
tok_init(file, '!');
|
||||
}
|
||||
|
||||
static void zap(void)
|
||||
/* An error, zap the rest of the line. */
|
||||
{
|
||||
token_t *t;
|
||||
|
||||
while ((t= get_token(0))->type != T_EOF && t->symbol != ';')
|
||||
skip_token(1);
|
||||
}
|
||||
|
||||
static mnemonic_t *search_mnem(char *name)
|
||||
/* Binary search for a mnemonic. (That's why the table is sorted.) */
|
||||
{
|
||||
int low, mid, high;
|
||||
int cmp;
|
||||
mnemonic_t *m;
|
||||
|
||||
low= 0;
|
||||
high= arraysize(mnemtab)-1;
|
||||
while (low <= high) {
|
||||
mid= (low + high) / 2;
|
||||
m= &mnemtab[mid];
|
||||
|
||||
if ((cmp= strcmp(name, m->name)) == 0) return m;
|
||||
|
||||
if (cmp < 0) high= mid-1; else low= mid+1;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static expression_t *bas_get_C_expression(int *pn)
|
||||
/* Read a "C-like" expression. Note that we don't worry about precedence,
|
||||
* the expression is printed later like it is read. If the target language
|
||||
* does not have all the operators (like ~) then this has to be repaired by
|
||||
* changing the source file. (No problem, you still have one source file
|
||||
* to maintain, not two.)
|
||||
*/
|
||||
{
|
||||
expression_t *e, *a1, *a2;
|
||||
token_t *t;
|
||||
|
||||
if ((t= get_token(*pn))->symbol == '(') {
|
||||
/* ( expr ): grouping. */
|
||||
(*pn)++;
|
||||
if ((a1= bas_get_C_expression(pn)) == nil) return nil;
|
||||
if (get_token(*pn)->symbol != ')') {
|
||||
parse_err(1, t, "missing )\n");
|
||||
del_expr(a1);
|
||||
return nil;
|
||||
}
|
||||
(*pn)++;
|
||||
e= new_expr();
|
||||
e->operator= '[';
|
||||
e->middle= a1;
|
||||
} else
|
||||
if (t->type == T_WORD || t->type == T_STRING) {
|
||||
/* Label, number, or string. */
|
||||
e= new_expr();
|
||||
e->operator= t->type == T_WORD ? 'W' : 'S';
|
||||
e->name= allocate(nil, (t->len+1) * sizeof(e->name[0]));
|
||||
memcpy(e->name, t->name, t->len+1);
|
||||
e->len= t->len;
|
||||
(*pn)++;
|
||||
} else
|
||||
if (t->symbol == '+' || t->symbol == '-' || t->symbol == '~') {
|
||||
/* Unary operator. */
|
||||
(*pn)++;
|
||||
if ((a1= bas_get_C_expression(pn)) == nil) return nil;
|
||||
e= new_expr();
|
||||
e->operator= t->symbol;
|
||||
e->middle= a1;
|
||||
} else
|
||||
if (t->symbol == '$' && get_token(*pn + 1)->type == T_WORD) {
|
||||
/* A hexadecimal number. */
|
||||
t= get_token(*pn + 1);
|
||||
e= new_expr();
|
||||
e->operator= 'W';
|
||||
e->name= allocate(nil, (t->len+3) * sizeof(e->name[0]));
|
||||
strcpy(e->name, "0x");
|
||||
memcpy(e->name+2, t->name, t->len+1);
|
||||
e->len= t->len+2;
|
||||
(*pn)+= 2;
|
||||
} else {
|
||||
parse_err(1, t, "expression syntax error\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
switch ((t= get_token(*pn))->symbol) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case '%':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case S_LEFTSHIFT:
|
||||
case S_RIGHTSHIFT:
|
||||
(*pn)++;
|
||||
a1= e;
|
||||
if ((a2= bas_get_C_expression(pn)) == nil) {
|
||||
del_expr(a1);
|
||||
return nil;
|
||||
}
|
||||
e= new_expr();
|
||||
e->operator= t->symbol;
|
||||
e->left= a1;
|
||||
e->right= a2;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/* We want to know the sizes of the first two operands. */
|
||||
static optype_t optypes[2];
|
||||
static int op_idx;
|
||||
|
||||
static expression_t *bas_get_operand(int *pn)
|
||||
/* Get something like: [memory], offset[base+index*scale], or simpler. */
|
||||
{
|
||||
expression_t *e, *offset, *base, *index;
|
||||
token_t *t;
|
||||
int c;
|
||||
optype_t optype;
|
||||
|
||||
/* Prefixed by 'byte', 'word' or 'dword'? */
|
||||
if ((t= get_token(*pn))->type == T_WORD && (
|
||||
strcmp(t->name, "byte") == 0
|
||||
|| strcmp(t->name, "word") == 0
|
||||
|| strcmp(t->name, "dword") == 0)
|
||||
) {
|
||||
switch (t->name[0]) {
|
||||
case 'b': optype= BYTE; break;
|
||||
case 'w': optype= use16() ? WORD : OWORD; break;
|
||||
case 'd': optype= use32() ? WORD : OWORD; break;
|
||||
}
|
||||
if (op_idx < arraysize(optypes)) optypes[op_idx++]= optype;
|
||||
(*pn)++;
|
||||
|
||||
/* It may even be "byte ptr"... */
|
||||
if ((t= get_token(*pn))->type == T_WORD
|
||||
&& strcmp(t->name, "ptr") == 0) {
|
||||
(*pn)++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is it [memory]? */
|
||||
if (get_token(*pn)->symbol == '['
|
||||
&& ((t= get_token(*pn + 1))->type != T_WORD
|
||||
|| !isregister(t->name))
|
||||
) {
|
||||
/* A memory dereference. */
|
||||
(*pn)++;
|
||||
if ((offset= bas_get_C_expression(pn)) == nil) return nil;
|
||||
if (get_token(*pn)->symbol != ']') {
|
||||
parse_err(1, t, "operand syntax error\n");
|
||||
del_expr(offset);
|
||||
return nil;
|
||||
}
|
||||
(*pn)++;
|
||||
e= new_expr();
|
||||
e->operator= '(';
|
||||
e->middle= offset;
|
||||
return e;
|
||||
}
|
||||
|
||||
/* #something? *something? */
|
||||
if ((c= get_token(*pn)->symbol) == '#' || c == '*') {
|
||||
/* '#' and '*' are often used to introduce some constant. */
|
||||
(*pn)++;
|
||||
}
|
||||
|
||||
/* Offset? */
|
||||
if (get_token(*pn)->symbol != '[') {
|
||||
/* There is an offset. */
|
||||
if ((offset= bas_get_C_expression(pn)) == nil) return nil;
|
||||
} else {
|
||||
/* No offset. */
|
||||
offset= nil;
|
||||
}
|
||||
|
||||
/* [base]? [base+? base-? */
|
||||
c= 0;
|
||||
if (get_token(*pn)->symbol == '['
|
||||
&& (t= get_token(*pn + 1))->type == T_WORD
|
||||
&& isregister(t->name)
|
||||
&& ((c= get_token(*pn + 2)->symbol) == ']' || c=='+' || c=='-')
|
||||
) {
|
||||
/* A base register expression. */
|
||||
base= new_expr();
|
||||
base->operator= 'B';
|
||||
base->name= copystr(t->name);
|
||||
(*pn)+= c == ']' ? 3 : 2;
|
||||
} else {
|
||||
/* No base register expression. */
|
||||
base= nil;
|
||||
}
|
||||
|
||||
/* +offset]? -offset]? */
|
||||
if (offset == nil
|
||||
&& (c == '+' || c == '-')
|
||||
&& (t= get_token(*pn + 1))->type == T_WORD
|
||||
&& !isregister(t->name)
|
||||
) {
|
||||
(*pn)++;
|
||||
if ((offset= bas_get_C_expression(pn)) == nil) return nil;
|
||||
if (get_token(*pn)->symbol != ']') {
|
||||
parse_err(1, t, "operand syntax error\n");
|
||||
del_expr(offset);
|
||||
del_expr(base);
|
||||
return nil;
|
||||
}
|
||||
(*pn)++;
|
||||
c= 0;
|
||||
}
|
||||
|
||||
/* [index*scale]? +index*scale]? */
|
||||
if (c == '+' || get_token(*pn)->symbol == '[') {
|
||||
/* An index most likely. */
|
||||
token_t *m= nil;
|
||||
|
||||
if (!( /* This must be true: */
|
||||
(t= get_token(*pn + 1))->type == T_WORD
|
||||
&& isregister(t->name)
|
||||
&& (get_token(*pn + 2)->symbol == ']' || (
|
||||
get_token(*pn + 2)->symbol == '*'
|
||||
&& (m= get_token(*pn + 3))->type == T_WORD
|
||||
&& strchr("1248", m->name[0]) != nil
|
||||
&& m->name[1] == 0
|
||||
&& get_token(*pn + 4)->symbol == ']'
|
||||
))
|
||||
)) {
|
||||
/* Alas it isn't */
|
||||
parse_err(1, t, "operand syntax error\n");
|
||||
del_expr(offset);
|
||||
del_expr(base);
|
||||
return nil;
|
||||
}
|
||||
/* Found an index. */
|
||||
index= new_expr();
|
||||
index->operator= m == nil ? '1' : m->name[0];
|
||||
index->name= copystr(t->name);
|
||||
(*pn)+= (m == nil ? 3 : 5);
|
||||
} else {
|
||||
/* No index. */
|
||||
index= nil;
|
||||
}
|
||||
|
||||
if (base == nil && index == nil) {
|
||||
/* Return a lone offset as is. */
|
||||
e= offset;
|
||||
|
||||
/* Lone registers tell operand size. */
|
||||
if (offset->operator == 'W' && isregister(offset->name)) {
|
||||
switch (isregister(offset->name)) {
|
||||
case 1: optype= BYTE; break;
|
||||
case 2: optype= use16() ? WORD : OWORD; break;
|
||||
case 4: optype= use32() ? WORD : OWORD; break;
|
||||
}
|
||||
if (op_idx < arraysize(optypes))
|
||||
optypes[op_idx++]= optype;
|
||||
}
|
||||
} else {
|
||||
e= new_expr();
|
||||
e->operator= 'O';
|
||||
e->left= offset;
|
||||
e->middle= base;
|
||||
e->right= index;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expression_t *bas_get_oplist(int *pn)
|
||||
/* Get a comma (or colon for jmpf and callf) separated list of instruction
|
||||
* operands.
|
||||
*/
|
||||
{
|
||||
expression_t *e, *o1, *o2;
|
||||
token_t *t;
|
||||
|
||||
if ((e= bas_get_operand(pn)) == nil) return nil;
|
||||
|
||||
if ((t= get_token(*pn))->symbol == ',' || t->symbol == ':') {
|
||||
o1= e;
|
||||
(*pn)++;
|
||||
if ((o2= bas_get_oplist(pn)) == nil) {
|
||||
del_expr(o1);
|
||||
return nil;
|
||||
}
|
||||
e= new_expr();
|
||||
e->operator= ',';
|
||||
e->left= o1;
|
||||
e->right= o2;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static asm86_t *bas_get_statement(void)
|
||||
/* Get a pseudo op or machine instruction with arguments. */
|
||||
{
|
||||
token_t *t= get_token(0);
|
||||
asm86_t *a;
|
||||
mnemonic_t *m;
|
||||
int n;
|
||||
int prefix_seen;
|
||||
|
||||
|
||||
assert(t->type == T_WORD);
|
||||
|
||||
if (strcmp(t->name, ".sect") == 0) {
|
||||
/* .sect .text etc. Accept only four segment names. */
|
||||
skip_token(1);
|
||||
t= get_token(0);
|
||||
if (t->type != T_WORD || (
|
||||
strcmp(t->name, ".text") != 0
|
||||
&& strcmp(t->name, ".rom") != 0
|
||||
&& strcmp(t->name, ".data") != 0
|
||||
&& strcmp(t->name, ".bss") != 0
|
||||
&& strcmp(t->name, ".end") != 0
|
||||
)) {
|
||||
parse_err(1, t, "weird section name to .sect\n");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
a= new_asm86();
|
||||
|
||||
/* Process instruction prefixes. */
|
||||
for (prefix_seen= 0;; prefix_seen= 1) {
|
||||
if (strcmp(t->name, "rep") == 0
|
||||
|| strcmp(t->name, "repe") == 0
|
||||
|| strcmp(t->name, "repne") == 0
|
||||
|| strcmp(t->name, "repz") == 0
|
||||
|| strcmp(t->name, "repnz") == 0
|
||||
) {
|
||||
if (a->rep != ONCE) {
|
||||
parse_err(1, t,
|
||||
"can't have more than one rep\n");
|
||||
}
|
||||
switch (t->name[3]) {
|
||||
case 0: a->rep= REP; break;
|
||||
case 'e':
|
||||
case 'z': a->rep= REPE; break;
|
||||
case 'n': a->rep= REPNE; break;
|
||||
}
|
||||
} else
|
||||
if (strcmp(t->name, "seg") == 0
|
||||
&& get_token(1)->type == T_WORD) {
|
||||
if (a->seg != DEFSEG) {
|
||||
parse_err(1, t,
|
||||
"can't have more than one segment prefix\n");
|
||||
}
|
||||
switch (get_token(1)->name[0]) {
|
||||
case 'c': a->seg= CSEG; break;
|
||||
case 'd': a->seg= DSEG; break;
|
||||
case 'e': a->seg= ESEG; break;
|
||||
case 'f': a->seg= FSEG; break;
|
||||
case 'g': a->seg= GSEG; break;
|
||||
case 's': a->seg= SSEG; break;
|
||||
}
|
||||
skip_token(1);
|
||||
} else
|
||||
if (!prefix_seen) {
|
||||
/* No prefix here, get out! */
|
||||
break;
|
||||
} else {
|
||||
/* No more prefixes, next must be an instruction. */
|
||||
if (t->type != T_WORD
|
||||
|| (m= search_mnem(t->name)) == nil
|
||||
|| m->optype == PSEUDO
|
||||
) {
|
||||
parse_err(1, t,
|
||||
"machine instruction expected after instruction prefix\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip the prefix and extra newlines. */
|
||||
do {
|
||||
skip_token(1);
|
||||
} while ((t= get_token(0))->symbol == ';');
|
||||
}
|
||||
|
||||
/* All the readahead being done upsets the line counter. */
|
||||
a->line= t->line;
|
||||
|
||||
/* Read a machine instruction or pseudo op. */
|
||||
if ((m= search_mnem(t->name)) == nil) {
|
||||
parse_err(1, t, "unknown instruction '%s'\n", t->name);
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
a->opcode= m->opcode;
|
||||
a->optype= m->optype;
|
||||
if (a->opcode == CBW || a->opcode == CWD) {
|
||||
a->optype= (strcmp(t->name, "cbw") == 0
|
||||
|| strcmp(t->name, "cwd") == 0) == use16() ? WORD : OWORD;
|
||||
}
|
||||
for (op_idx= 0; op_idx < arraysize(optypes); op_idx++)
|
||||
optypes[op_idx]= m->optype;
|
||||
op_idx= 0;
|
||||
|
||||
n= 1;
|
||||
if (get_token(1)->symbol != ';'
|
||||
&& (a->args= bas_get_oplist(&n)) == nil) {
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (m->optype == WORD) {
|
||||
/* Does one of the operands overide the optype? */
|
||||
for (op_idx= 0; op_idx < arraysize(optypes); op_idx++) {
|
||||
if (optypes[op_idx] != m->optype)
|
||||
a->optype= optypes[op_idx];
|
||||
}
|
||||
}
|
||||
|
||||
if (get_token(n)->symbol != ';') {
|
||||
parse_err(1, t, "garbage at end of instruction\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
switch (a->opcode) {
|
||||
case DOT_ALIGN:
|
||||
/* Restrict .align to have a single numeric argument, some
|
||||
* assemblers think of the argument as a power of two, so
|
||||
* we need to be able to change the value.
|
||||
*/
|
||||
if (strcmp(t->name, ".even") == 0 && a->args == nil) {
|
||||
/* .even becomes .align 2. */
|
||||
expression_t *e;
|
||||
a->args= e= new_expr();
|
||||
e->operator= 'W';
|
||||
e->name= copystr("2");
|
||||
e->len= 2;
|
||||
}
|
||||
if (a->args == nil || a->args->operator != 'W'
|
||||
|| !isanumber(a->args->name)) {
|
||||
parse_err(1, t,
|
||||
".align is restricted to one numeric argument\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
case MOVSX:
|
||||
case MOVZX:
|
||||
/* Types of both operands tell the instruction type. */
|
||||
a->optype= optypes[0];
|
||||
if (optypes[1] == BYTE) {
|
||||
a->opcode= a->opcode == MOVSX ? MOVSXB : MOVZXB;
|
||||
}
|
||||
break;
|
||||
case SAL:
|
||||
case SAR:
|
||||
case SHL:
|
||||
case SHR:
|
||||
case RCL:
|
||||
case RCR:
|
||||
case ROL:
|
||||
case ROR:
|
||||
/* Only the first operand tells the operand size. */
|
||||
a->optype= optypes[0];
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
skip_token(n+1);
|
||||
return a;
|
||||
}
|
||||
|
||||
asm86_t *bas_get_instruction(void)
|
||||
{
|
||||
asm86_t *a= nil;
|
||||
expression_t *e;
|
||||
token_t *t;
|
||||
|
||||
while ((t= get_token(0))->symbol == ';')
|
||||
skip_token(1);
|
||||
|
||||
if (t->type == T_EOF) return nil;
|
||||
|
||||
if (t->symbol == '#') {
|
||||
/* Preprocessor line and file change. */
|
||||
|
||||
if ((t= get_token(1))->type != T_WORD || !isanumber(t->name)
|
||||
|| get_token(2)->type != T_STRING
|
||||
) {
|
||||
parse_err(1, t, "file not preprocessed?\n");
|
||||
zap();
|
||||
} else {
|
||||
set_file(get_token(2)->name,
|
||||
strtol(get_token(1)->name, nil, 0) - 1);
|
||||
|
||||
/* GNU CPP adds extra cruft, simply zap the line. */
|
||||
zap();
|
||||
}
|
||||
a= bas_get_instruction();
|
||||
} else
|
||||
if (t->type == T_WORD && get_token(1)->symbol == ':') {
|
||||
/* A label definition. */
|
||||
a= new_asm86();
|
||||
a->line= t->line;
|
||||
a->opcode= DOT_LABEL;
|
||||
a->optype= PSEUDO;
|
||||
a->args= e= new_expr();
|
||||
e->operator= ':';
|
||||
e->name= copystr(t->name);
|
||||
skip_token(2);
|
||||
} else
|
||||
if (t->type == T_WORD && get_token(1)->symbol == '=') {
|
||||
int n= 2;
|
||||
|
||||
if ((e= bas_get_C_expression(&n)) == nil) {
|
||||
zap();
|
||||
a= bas_get_instruction();
|
||||
} else
|
||||
if (get_token(n)->symbol != ';') {
|
||||
parse_err(1, t, "garbage after assignment\n");
|
||||
zap();
|
||||
a= bas_get_instruction();
|
||||
} else {
|
||||
a= new_asm86();
|
||||
a->line= t->line;
|
||||
a->opcode= DOT_EQU;
|
||||
a->optype= PSEUDO;
|
||||
a->args= new_expr();
|
||||
a->args->operator= '=';
|
||||
a->args->name= copystr(t->name);
|
||||
a->args->middle= e;
|
||||
skip_token(n+1);
|
||||
}
|
||||
} else
|
||||
if (t->type == T_WORD && get_token(1)->type == T_WORD
|
||||
&& strcmp(get_token(1)->name, "lcomm") == 0) {
|
||||
/* Local common block definition. */
|
||||
int n= 2;
|
||||
|
||||
if ((e= bas_get_C_expression(&n)) == nil) {
|
||||
zap();
|
||||
a= bas_get_instruction();
|
||||
} else
|
||||
if (get_token(n)->symbol != ';') {
|
||||
parse_err(1, t, "garbage after lcomm\n");
|
||||
zap();
|
||||
a= bas_get_instruction();
|
||||
} else {
|
||||
a= new_asm86();
|
||||
a->line= t->line;
|
||||
a->opcode= DOT_LCOMM;
|
||||
a->optype= PSEUDO;
|
||||
a->args= new_expr();
|
||||
a->args->operator= ',';
|
||||
a->args->right= e;
|
||||
a->args->left= e= new_expr();
|
||||
e->operator= 'W';
|
||||
e->name= copystr(t->name);
|
||||
e->len= strlen(e->name)+1;
|
||||
skip_token(n+1);
|
||||
}
|
||||
} else
|
||||
if (t->type == T_WORD) {
|
||||
if ((a= bas_get_statement()) == nil) {
|
||||
zap();
|
||||
a= bas_get_instruction();
|
||||
}
|
||||
} else {
|
||||
parse_err(1, t, "syntax error\n");
|
||||
zap();
|
||||
a= bas_get_instruction();
|
||||
}
|
||||
if (a->optype == OWORD) {
|
||||
a->optype= WORD;
|
||||
a->oaz|= OPZ;
|
||||
}
|
||||
return a;
|
||||
}
|
|
@ -1,879 +0,0 @@
|
|||
/* parse_ack.c - parse GNU assembly Author: R.S. Veldema
|
||||
* <rveldema@cs.vu.nl>
|
||||
* 26 Aug 1996
|
||||
*/
|
||||
#define nil 0
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include "asmconv.h"
|
||||
#include "token.h"
|
||||
#include "asm86.h"
|
||||
#include "languages.h"
|
||||
|
||||
typedef struct mnemonic { /* GNU as86 mnemonics translation table. */
|
||||
char *name;
|
||||
opcode_t opcode;
|
||||
optype_t optype;
|
||||
} mnemonic_t;
|
||||
|
||||
static mnemonic_t mnemtab[] = { /* This array is sorted. */
|
||||
{ ".align", DOT_ALIGN, PSEUDO },
|
||||
{ ".ascii", DOT_ASCII, PSEUDO },
|
||||
{ ".asciz", DOT_ASCIZ, PSEUDO },
|
||||
{ ".assert", DOT_ASSERT, PSEUDO },
|
||||
{ ".base", DOT_BASE, PSEUDO },
|
||||
{ ".bss", DOT_BSS, PSEUDO },
|
||||
{ ".byte", DOT_DATA1, PSEUDO },
|
||||
{ ".comm", DOT_COMM, PSEUDO },
|
||||
{ ".data", DOT_DATA, PSEUDO },
|
||||
{ ".data1", DOT_DATA1, PSEUDO },
|
||||
{ ".data2", DOT_DATA2, PSEUDO },
|
||||
{ ".data4", DOT_DATA4, PSEUDO },
|
||||
{ ".end", DOT_END, PSEUDO },
|
||||
{ ".extern", DOT_EXTERN, PSEUDO },
|
||||
{ ".file", DOT_FILE, PSEUDO },
|
||||
{ ".globl", DOT_DEFINE, PSEUDO },
|
||||
{ ".lcomm", DOT_LCOMM, PSEUDO },
|
||||
{ ".line", DOT_LINE, PSEUDO },
|
||||
{ ".list", DOT_LIST, PSEUDO },
|
||||
{ ".long", DOT_DATA4, PSEUDO },
|
||||
{ ".nolist", DOT_NOLIST, PSEUDO },
|
||||
{ ".rom", DOT_ROM, PSEUDO },
|
||||
{ ".space", DOT_SPACE, PSEUDO },
|
||||
{ ".symb", DOT_SYMB, PSEUDO },
|
||||
{ ".text", DOT_TEXT, PSEUDO },
|
||||
{ ".word", DOT_DATA2, PSEUDO },
|
||||
{ "aaa", AAA, WORD },
|
||||
{ "aad", AAD, WORD },
|
||||
{ "aam", AAM, WORD },
|
||||
{ "aas", AAS, WORD },
|
||||
{ "adcb", ADC, BYTE },
|
||||
{ "adcl", ADC, WORD },
|
||||
{ "adcw", ADC, OWORD },
|
||||
{ "addb", ADD, BYTE },
|
||||
{ "addl", ADD, WORD },
|
||||
{ "addw", ADD, OWORD },
|
||||
{ "andb", AND, BYTE },
|
||||
{ "andl", AND, WORD },
|
||||
{ "andw", AND, OWORD },
|
||||
{ "arpl", ARPL, WORD },
|
||||
{ "bound", BOUND, WORD },
|
||||
{ "bsf", BSF, WORD },
|
||||
{ "bsr", BSR, WORD },
|
||||
{ "bswap", BSWAP, WORD },
|
||||
{ "btc", BTC, WORD },
|
||||
{ "btl", BT, WORD },
|
||||
{ "btr", BTR, WORD },
|
||||
{ "bts", BTS, WORD },
|
||||
{ "btw", BT, OWORD },
|
||||
{ "call", CALL, JUMP },
|
||||
{ "callf", CALLF, JUMP },
|
||||
{ "cbtw", CBW, OWORD },
|
||||
{ "cbw", CBW, WORD },
|
||||
{ "cdq", CWD, WORD },
|
||||
{ "clc", CLC, WORD },
|
||||
{ "cld", CLD, WORD },
|
||||
{ "cli", CLI, WORD },
|
||||
{ "cltd", CWD, WORD },
|
||||
{ "clts", CLTS, WORD },
|
||||
{ "cmc", CMC, WORD },
|
||||
{ "cmpb", CMP, BYTE },
|
||||
{ "cmpl", CMP, WORD },
|
||||
{ "cmps", CMPS, WORD },
|
||||
{ "cmpsb", CMPS, BYTE },
|
||||
{ "cmpw", CMP, OWORD },
|
||||
{ "cmpxchg", CMPXCHG, WORD },
|
||||
{ "cwd", CWD, WORD },
|
||||
{ "cwde", CBW, WORD },
|
||||
{ "cwtd", CWD, OWORD },
|
||||
{ "cwtl", CBW, WORD },
|
||||
{ "daa", DAA, WORD },
|
||||
{ "das", DAS, WORD },
|
||||
{ "decb", DEC, BYTE },
|
||||
{ "decl", DEC, WORD },
|
||||
{ "decw", DEC, OWORD },
|
||||
{ "divb", DIV, BYTE },
|
||||
{ "divl", DIV, WORD },
|
||||
{ "divw", DIV, OWORD },
|
||||
{ "enter", ENTER, WORD },
|
||||
{ "f2xm1", F2XM1, WORD },
|
||||
{ "fabs", FABS, WORD },
|
||||
{ "fadd", FADD, WORD },
|
||||
{ "faddd", FADDD, WORD },
|
||||
{ "faddp", FADDP, WORD },
|
||||
{ "fadds", FADDS, WORD },
|
||||
{ "fbld", FBLD, WORD },
|
||||
{ "fbstp", FBSTP, WORD },
|
||||
{ "fchs", FCHS, WORD },
|
||||
{ "fcomd", FCOMD, WORD },
|
||||
{ "fcompd", FCOMPD, WORD },
|
||||
{ "fcompp", FCOMPP, WORD },
|
||||
{ "fcomps", FCOMPS, WORD },
|
||||
{ "fcoms", FCOMS, WORD },
|
||||
{ "fcos", FCOS, WORD },
|
||||
{ "fdecstp", FDECSTP, WORD },
|
||||
{ "fdivd", FDIVD, WORD },
|
||||
{ "fdivp", FDIVP, WORD },
|
||||
{ "fdivrd", FDIVRD, WORD },
|
||||
{ "fdivrp", FDIVRP, WORD },
|
||||
{ "fdivrs", FDIVRS, WORD },
|
||||
{ "fdivs", FDIVS, WORD },
|
||||
{ "ffree", FFREE, WORD },
|
||||
{ "fiaddl", FIADDL, WORD },
|
||||
{ "fiadds", FIADDS, WORD },
|
||||
{ "ficom", FICOM, WORD },
|
||||
{ "ficomp", FICOMP, WORD },
|
||||
{ "fidivl", FIDIVL, WORD },
|
||||
{ "fidivrl", FIDIVRL, WORD },
|
||||
{ "fidivrs", FIDIVRS, WORD },
|
||||
{ "fidivs", FIDIVS, WORD },
|
||||
{ "fildl", FILDL, WORD },
|
||||
{ "fildq", FILDQ, WORD },
|
||||
{ "filds", FILDS, WORD },
|
||||
{ "fimull", FIMULL, WORD },
|
||||
{ "fimuls", FIMULS, WORD },
|
||||
{ "fincstp", FINCSTP, WORD },
|
||||
{ "fistl", FISTL, WORD },
|
||||
{ "fistp", FISTP, WORD },
|
||||
{ "fists", FISTS, WORD },
|
||||
{ "fisubl", FISUBL, WORD },
|
||||
{ "fisubrl", FISUBRL, WORD },
|
||||
{ "fisubrs", FISUBRS, WORD },
|
||||
{ "fisubs", FISUBS, WORD },
|
||||
{ "fld1", FLD1, WORD },
|
||||
{ "fldcw", FLDCW, WORD },
|
||||
{ "fldd", FLDD, WORD },
|
||||
{ "fldenv", FLDENV, WORD },
|
||||
{ "fldl2e", FLDL2E, WORD },
|
||||
{ "fldl2t", FLDL2T, WORD },
|
||||
{ "fldlg2", FLDLG2, WORD },
|
||||
{ "fldln2", FLDLN2, WORD },
|
||||
{ "fldpi", FLDPI, WORD },
|
||||
{ "flds", FLDS, WORD },
|
||||
{ "fldx", FLDX, WORD },
|
||||
{ "fldz", FLDZ, WORD },
|
||||
{ "fmuld", FMULD, WORD },
|
||||
{ "fmulp", FMULP, WORD },
|
||||
{ "fmuls", FMULS, WORD },
|
||||
{ "fnclex", FCLEX, WORD },
|
||||
{ "fninit", FINIT, WORD },
|
||||
{ "fnop", FNOP, WORD },
|
||||
{ "fnsave", FSAVE, WORD },
|
||||
{ "fnstcw", FSTCW, WORD },
|
||||
{ "fnstenv", FSTENV, WORD },
|
||||
{ "fpatan", FPATAN, WORD },
|
||||
{ "fprem", FPREM, WORD },
|
||||
{ "fprem1", FPREM1, WORD },
|
||||
{ "fptan", FPTAN, WORD },
|
||||
{ "frndint", FRNDINT, WORD },
|
||||
{ "frstor", FRSTOR, WORD },
|
||||
{ "fscale", FSCALE, WORD },
|
||||
{ "fsin", FSIN, WORD },
|
||||
{ "fsincos", FSINCOS, WORD },
|
||||
{ "fsqrt", FSQRT, WORD },
|
||||
{ "fstd", FSTD, WORD },
|
||||
{ "fstpd", FSTPD, WORD },
|
||||
{ "fstps", FSTPS, WORD },
|
||||
{ "fstpx", FSTPX, WORD },
|
||||
{ "fsts", FSTS, WORD },
|
||||
{ "fstsw", FSTSW, WORD },
|
||||
{ "fsubd", FSUBD, WORD },
|
||||
{ "fsubp", FSUBP, WORD },
|
||||
{ "fsubpr", FSUBPR, WORD },
|
||||
{ "fsubrd", FSUBRD, WORD },
|
||||
{ "fsubrs", FSUBRS, WORD },
|
||||
{ "fsubs", FSUBS, WORD },
|
||||
{ "ftst", FTST, WORD },
|
||||
{ "fucom", FUCOM, WORD },
|
||||
{ "fucomp", FUCOMP, WORD },
|
||||
{ "fucompp", FUCOMPP, WORD },
|
||||
{ "fxam", FXAM, WORD },
|
||||
{ "fxch", FXCH, WORD },
|
||||
{ "fxtract", FXTRACT, WORD },
|
||||
{ "fyl2x", FYL2X, WORD },
|
||||
{ "fyl2xp1", FYL2XP1, WORD },
|
||||
{ "hlt", HLT, WORD },
|
||||
{ "idivb", IDIV, BYTE },
|
||||
{ "idivl", IDIV, WORD },
|
||||
{ "idivw", IDIV, OWORD },
|
||||
{ "imulb", IMUL, BYTE },
|
||||
{ "imull", IMUL, WORD },
|
||||
{ "imulw", IMUL, OWORD },
|
||||
{ "inb", IN, BYTE },
|
||||
{ "incb", INC, BYTE },
|
||||
{ "incl", INC, WORD },
|
||||
{ "incw", INC, OWORD },
|
||||
{ "inl", IN, WORD },
|
||||
{ "insb", INS, BYTE },
|
||||
{ "insl", INS, WORD },
|
||||
{ "insw", INS, OWORD },
|
||||
{ "int", INT, WORD },
|
||||
{ "into", INTO, JUMP },
|
||||
{ "invd", INVD, WORD },
|
||||
{ "invlpg", INVLPG, WORD },
|
||||
{ "inw", IN, OWORD },
|
||||
{ "iret", IRET, JUMP },
|
||||
{ "iretd", IRETD, JUMP },
|
||||
{ "ja", JA, JUMP },
|
||||
{ "jae", JAE, JUMP },
|
||||
{ "jb", JB, JUMP },
|
||||
{ "jbe", JBE, JUMP },
|
||||
{ "jc", JB, JUMP },
|
||||
{ "jcxz", JCXZ, JUMP },
|
||||
{ "je", JE, JUMP },
|
||||
{ "jecxz", JCXZ, JUMP },
|
||||
{ "jg", JG, JUMP },
|
||||
{ "jge", JGE, JUMP },
|
||||
{ "jl", JL, JUMP },
|
||||
{ "jle", JLE, JUMP },
|
||||
{ "jmp", JMP, JUMP },
|
||||
{ "jmpf", JMPF, JUMP },
|
||||
{ "jna", JBE, JUMP },
|
||||
{ "jnae", JB, JUMP },
|
||||
{ "jnb", JAE, JUMP },
|
||||
{ "jnbe", JA, JUMP },
|
||||
{ "jnc", JAE, JUMP },
|
||||
{ "jne", JNE, JUMP },
|
||||
{ "jng", JLE, JUMP },
|
||||
{ "jnge", JL, JUMP },
|
||||
{ "jnl", JGE, JUMP },
|
||||
{ "jnle", JG, JUMP },
|
||||
{ "jno", JNO, JUMP },
|
||||
{ "jnp", JNP, JUMP },
|
||||
{ "jns", JNS, JUMP },
|
||||
{ "jnz", JNE, JUMP },
|
||||
{ "jo", JO, JUMP },
|
||||
{ "jp", JP, JUMP },
|
||||
{ "js", JS, JUMP },
|
||||
{ "jz", JE, JUMP },
|
||||
{ "lahf", LAHF, WORD },
|
||||
{ "lar", LAR, WORD },
|
||||
{ "lds", LDS, WORD },
|
||||
{ "leal", LEA, WORD },
|
||||
{ "leave", LEAVE, WORD },
|
||||
{ "leaw", LEA, OWORD },
|
||||
{ "les", LES, WORD },
|
||||
{ "lfs", LFS, WORD },
|
||||
{ "lgdt", LGDT, WORD },
|
||||
{ "lgs", LGS, WORD },
|
||||
{ "lidt", LIDT, WORD },
|
||||
{ "lldt", LLDT, WORD },
|
||||
{ "lmsw", LMSW, WORD },
|
||||
{ "lock", LOCK, WORD },
|
||||
{ "lods", LODS, WORD },
|
||||
{ "lodsb", LODS, BYTE },
|
||||
{ "loop", LOOP, JUMP },
|
||||
{ "loope", LOOPE, JUMP },
|
||||
{ "loopne", LOOPNE, JUMP },
|
||||
{ "loopnz", LOOPNE, JUMP },
|
||||
{ "loopz", LOOPE, JUMP },
|
||||
{ "lsl", LSL, WORD },
|
||||
{ "lss", LSS, WORD },
|
||||
{ "ltr", LTR, WORD },
|
||||
{ "movb", MOV, BYTE },
|
||||
{ "movl", MOV, WORD },
|
||||
{ "movsb", MOVS, BYTE },
|
||||
{ "movsbl", MOVSXB, WORD },
|
||||
{ "movsbw", MOVSXB, OWORD },
|
||||
{ "movsl", MOVS, WORD },
|
||||
{ "movsw", MOVS, OWORD },
|
||||
{ "movswl", MOVSX, WORD },
|
||||
{ "movw", MOV, OWORD },
|
||||
{ "movzbl", MOVZXB, WORD },
|
||||
{ "movzbw", MOVZXB, OWORD },
|
||||
{ "movzwl", MOVZX, WORD },
|
||||
{ "mulb", MUL, BYTE },
|
||||
{ "mull", MUL, WORD },
|
||||
{ "mulw", MUL, OWORD },
|
||||
{ "negb", NEG, BYTE },
|
||||
{ "negl", NEG, WORD },
|
||||
{ "negw", NEG, OWORD },
|
||||
{ "nop", NOP, WORD },
|
||||
{ "notb", NOT, BYTE },
|
||||
{ "notl", NOT, WORD },
|
||||
{ "notw", NOT, OWORD },
|
||||
{ "orb", OR, BYTE },
|
||||
{ "orl", OR, WORD },
|
||||
{ "orw", OR, OWORD },
|
||||
{ "outb", OUT, BYTE },
|
||||
{ "outl", OUT, WORD },
|
||||
{ "outsb", OUTS, BYTE },
|
||||
{ "outsl", OUTS, WORD },
|
||||
{ "outsw", OUTS, OWORD },
|
||||
{ "outw", OUT, OWORD },
|
||||
{ "pop", POP, WORD },
|
||||
{ "popa", POPA, WORD },
|
||||
{ "popad", POPA, WORD },
|
||||
{ "popf", POPF, WORD },
|
||||
{ "popl", POP, WORD },
|
||||
{ "push", PUSH, WORD },
|
||||
{ "pusha", PUSHA, WORD },
|
||||
{ "pushad", PUSHA, WORD },
|
||||
{ "pushf", PUSHF, WORD },
|
||||
{ "pushl", PUSH, WORD },
|
||||
{ "rclb", RCL, BYTE },
|
||||
{ "rcll", RCL, WORD },
|
||||
{ "rclw", RCL, OWORD },
|
||||
{ "rcrb", RCR, BYTE },
|
||||
{ "rcrl", RCR, WORD },
|
||||
{ "rcrw", RCR, OWORD },
|
||||
{ "ret", RET, JUMP },
|
||||
{ "retf", RETF, JUMP },
|
||||
{ "rolb", ROL, BYTE },
|
||||
{ "roll", ROL, WORD },
|
||||
{ "rolw", ROL, OWORD },
|
||||
{ "rorb", ROR, BYTE },
|
||||
{ "rorl", ROR, WORD },
|
||||
{ "rorw", ROR, OWORD },
|
||||
{ "sahf", SAHF, WORD },
|
||||
{ "salb", SAL, BYTE },
|
||||
{ "sall", SAL, WORD },
|
||||
{ "salw", SAL, OWORD },
|
||||
{ "sarb", SAR, BYTE },
|
||||
{ "sarl", SAR, WORD },
|
||||
{ "sarw", SAR, OWORD },
|
||||
{ "sbbb", SBB, BYTE },
|
||||
{ "sbbl", SBB, WORD },
|
||||
{ "sbbw", SBB, OWORD },
|
||||
{ "scasb", SCAS, BYTE },
|
||||
{ "scasl", SCAS, WORD },
|
||||
{ "scasw", SCAS, OWORD },
|
||||
{ "seta", SETA, BYTE },
|
||||
{ "setae", SETAE, BYTE },
|
||||
{ "setb", SETB, BYTE },
|
||||
{ "setbe", SETBE, BYTE },
|
||||
{ "sete", SETE, BYTE },
|
||||
{ "setg", SETG, BYTE },
|
||||
{ "setge", SETGE, BYTE },
|
||||
{ "setl", SETL, BYTE },
|
||||
{ "setna", SETBE, BYTE },
|
||||
{ "setnae", SETB, BYTE },
|
||||
{ "setnb", SETAE, BYTE },
|
||||
{ "setnbe", SETA, BYTE },
|
||||
{ "setne", SETNE, BYTE },
|
||||
{ "setng", SETLE, BYTE },
|
||||
{ "setnge", SETL, BYTE },
|
||||
{ "setnl", SETGE, BYTE },
|
||||
{ "setnle", SETG, BYTE },
|
||||
{ "setno", SETNO, BYTE },
|
||||
{ "setnp", SETNP, BYTE },
|
||||
{ "setns", SETNS, BYTE },
|
||||
{ "seto", SETO, BYTE },
|
||||
{ "setp", SETP, BYTE },
|
||||
{ "sets", SETS, BYTE },
|
||||
{ "setz", SETE, BYTE },
|
||||
{ "sgdt", SGDT, WORD },
|
||||
{ "shlb", SHL, BYTE },
|
||||
{ "shldl", SHLD, WORD },
|
||||
{ "shll", SHL, WORD },
|
||||
{ "shlw", SHL, OWORD },
|
||||
{ "shrb", SHR, BYTE },
|
||||
{ "shrdl", SHRD, WORD },
|
||||
{ "shrl", SHR, WORD },
|
||||
{ "shrw", SHR, OWORD },
|
||||
{ "sidt", SIDT, WORD },
|
||||
{ "sldt", SLDT, WORD },
|
||||
{ "smsw", SMSW, WORD },
|
||||
{ "stc", STC, WORD },
|
||||
{ "std", STD, WORD },
|
||||
{ "sti", STI, WORD },
|
||||
{ "stosb", STOS, BYTE },
|
||||
{ "stosl", STOS, WORD },
|
||||
{ "stosw", STOS, OWORD },
|
||||
{ "str", STR, WORD },
|
||||
{ "subb", SUB, BYTE },
|
||||
{ "subl", SUB, WORD },
|
||||
{ "subw", SUB, OWORD },
|
||||
{ "testb", TEST, BYTE },
|
||||
{ "testl", TEST, WORD },
|
||||
{ "testw", TEST, OWORD },
|
||||
{ "verr", VERR, WORD },
|
||||
{ "verw", VERW, WORD },
|
||||
{ "wait", WAIT, WORD },
|
||||
{ "wbinvd", WBINVD, WORD },
|
||||
{ "xadd", XADD, WORD },
|
||||
{ "xchgb", XCHG, BYTE },
|
||||
{ "xchgl", XCHG, WORD },
|
||||
{ "xchgw", XCHG, OWORD },
|
||||
{ "xlat", XLAT, WORD },
|
||||
{ "xorb", XOR, BYTE },
|
||||
{ "xorl", XOR, WORD },
|
||||
{ "xorw", XOR, OWORD },
|
||||
};
|
||||
|
||||
void gnu_parse_init(char *file)
|
||||
/* Prepare parsing of an GNU assembly file. */
|
||||
{
|
||||
tok_init(file, '#');
|
||||
}
|
||||
|
||||
static void zap(void)
|
||||
/* An error, zap the rest of the line. */
|
||||
{
|
||||
token_t *t;
|
||||
|
||||
while ((t= get_token(0))->type != T_EOF && t->symbol != ';')
|
||||
skip_token(1);
|
||||
}
|
||||
|
||||
static mnemonic_t *search_mnem(char *name)
|
||||
/* Binary search for a mnemonic. (That's why the table is sorted.) */
|
||||
{
|
||||
int low, mid, high;
|
||||
int cmp;
|
||||
mnemonic_t *m;
|
||||
|
||||
low= 0;
|
||||
high= arraysize(mnemtab)-1;
|
||||
while (low <= high) {
|
||||
mid= (low + high) / 2;
|
||||
m= &mnemtab[mid];
|
||||
|
||||
if ((cmp= strcmp(name, m->name)) == 0) return m;
|
||||
|
||||
if (cmp < 0) high= mid-1; else low= mid+1;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static expression_t *gnu_get_C_expression(int *pn)
|
||||
/* Read a "C-like" expression. Note that we don't worry about precedence,
|
||||
* the expression is printed later like it is read. If the target language
|
||||
* does not have all the operators (like ~) then this has to be repaired by
|
||||
* changing the source file. (No problem, you still have one source file
|
||||
* to maintain, not two.)
|
||||
*/
|
||||
{
|
||||
expression_t *e, *a1, *a2;
|
||||
token_t *t;
|
||||
|
||||
if ((t= get_token(*pn))->symbol == '(') {
|
||||
/* ( expr ): grouping. */
|
||||
(*pn)++;
|
||||
if ((a1= gnu_get_C_expression(pn)) == nil) return nil;
|
||||
if (get_token(*pn)->symbol != ')') {
|
||||
parse_err(1, t, "missing )\n");
|
||||
del_expr(a1);
|
||||
return nil;
|
||||
}
|
||||
(*pn)++;
|
||||
e= new_expr();
|
||||
e->operator= '[';
|
||||
e->middle= a1;
|
||||
} else
|
||||
if (t->type == T_WORD || t->type == T_STRING) {
|
||||
/* Label, number, or string. */
|
||||
e= new_expr();
|
||||
e->operator= t->type == T_WORD ? 'W' : 'S';
|
||||
e->name= allocate(nil, (t->len+1) * sizeof(e->name[0]));
|
||||
memcpy(e->name, t->name , t->len+1);
|
||||
e->len= t->len;
|
||||
(*pn)++;
|
||||
} else
|
||||
if (t->symbol == '+' || t->symbol == '-' || t->symbol == '~') {
|
||||
/* Unary operator. */
|
||||
(*pn)++;
|
||||
if ((a1= gnu_get_C_expression(pn)) == nil) return nil;
|
||||
e= new_expr();
|
||||
e->operator= t->symbol;
|
||||
e->middle= a1;
|
||||
} else {
|
||||
parse_err(1, t, "expression syntax error\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
switch ((t= get_token(*pn))->symbol) {
|
||||
case '%':
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case S_LEFTSHIFT:
|
||||
case S_RIGHTSHIFT:
|
||||
(*pn)++;
|
||||
a1= e;
|
||||
if ((a2= gnu_get_C_expression(pn)) == nil) {
|
||||
del_expr(a1);
|
||||
return nil;
|
||||
}
|
||||
e= new_expr();
|
||||
e->operator= t->symbol;
|
||||
e->left= a1;
|
||||
e->right= a2;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expression_t *gnu_get_operand(int *pn, int deref)
|
||||
/* Get something like: $immed, memory, offset(%base,%index,scale), or simpler. */
|
||||
{
|
||||
expression_t *e, *offset, *base, *index;
|
||||
token_t *t;
|
||||
int c;
|
||||
|
||||
if (get_token(*pn)->symbol == '$') {
|
||||
/* An immediate value. */
|
||||
(*pn)++;
|
||||
return gnu_get_C_expression(pn);
|
||||
}
|
||||
|
||||
if (get_token(*pn)->symbol == '*') {
|
||||
/* Indirection. */
|
||||
(*pn)++;
|
||||
if ((offset= gnu_get_operand(pn, deref)) == nil) return nil;
|
||||
e= new_expr();
|
||||
e->operator= '(';
|
||||
e->middle= offset;
|
||||
return e;
|
||||
}
|
||||
|
||||
if ((get_token(*pn)->symbol == '%')
|
||||
&& (t= get_token(*pn + 1))->type == T_WORD
|
||||
&& isregister(t->name)
|
||||
) {
|
||||
/* A register operand. */
|
||||
(*pn)+= 2;
|
||||
e= new_expr();
|
||||
e->operator= 'W';
|
||||
e->name= copystr(t->name);
|
||||
return e;
|
||||
}
|
||||
|
||||
/* Offset? */
|
||||
if (get_token(*pn)->symbol != '('
|
||||
|| get_token(*pn + 1)->symbol != '%') {
|
||||
/* There is an offset. */
|
||||
if ((offset= gnu_get_C_expression(pn)) == nil) return nil;
|
||||
} else {
|
||||
/* No offset. */
|
||||
offset= nil;
|
||||
}
|
||||
|
||||
/* (%base,%index,scale) ? */
|
||||
base= index= nil;
|
||||
if (get_token(*pn)->symbol == '(') {
|
||||
(*pn)++;
|
||||
|
||||
/* %base ? */
|
||||
if (get_token(*pn)->symbol == '%'
|
||||
&& (t= get_token(*pn + 1))->type == T_WORD
|
||||
&& isregister(t->name)
|
||||
) {
|
||||
/* A base register expression. */
|
||||
base= new_expr();
|
||||
base->operator= 'B';
|
||||
base->name= copystr(t->name);
|
||||
(*pn)+= 2;
|
||||
}
|
||||
|
||||
if (get_token(*pn)->symbol == ',') (*pn)++;
|
||||
|
||||
/* %index ? */
|
||||
if (get_token(*pn)->symbol == '%'
|
||||
&& (t= get_token(*pn + 1))->type == T_WORD
|
||||
&& isregister(t->name)
|
||||
) {
|
||||
/* A index register expression. */
|
||||
index= new_expr();
|
||||
index->operator= '1'; /* for now */
|
||||
index->name= copystr(t->name);
|
||||
(*pn)+= 2;
|
||||
}
|
||||
|
||||
if (get_token(*pn)->symbol == ',') (*pn)++;
|
||||
|
||||
/* scale ? */
|
||||
if ((base != nil || index != nil)
|
||||
&& (t= get_token(*pn))->type == T_WORD
|
||||
&& strchr("1248", t->name[0]) != nil
|
||||
&& t->name[1] == 0
|
||||
) {
|
||||
if (index == nil) {
|
||||
/* Base is really an index register. */
|
||||
index= base;
|
||||
base= nil;
|
||||
}
|
||||
index->operator= t->name[0];
|
||||
(*pn)++;
|
||||
}
|
||||
|
||||
if (get_token(*pn)->symbol == ')') {
|
||||
/* Ending paren. */
|
||||
(*pn)++;
|
||||
} else {
|
||||
/* Alas. */
|
||||
parse_err(1, t, "operand syntax error\n");
|
||||
del_expr(offset);
|
||||
del_expr(base);
|
||||
del_expr(index);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (base == nil && index == nil) {
|
||||
if (deref) {
|
||||
/* Return a lone offset as (offset). */
|
||||
e= new_expr();
|
||||
e->operator= '(';
|
||||
e->middle= offset;
|
||||
} else {
|
||||
/* Return a lone offset as is. */
|
||||
e= offset;
|
||||
}
|
||||
} else {
|
||||
e= new_expr();
|
||||
e->operator= 'O';
|
||||
e->left= offset;
|
||||
|
||||
e->middle= base;
|
||||
e->right= index;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expression_t *gnu_get_oplist(int *pn, int deref)
|
||||
/* Get a comma (or colon for jmpf and callf) separated list of instruction
|
||||
* operands.
|
||||
*/
|
||||
{
|
||||
expression_t *e, *o1, *o2;
|
||||
token_t *t;
|
||||
|
||||
if ((e= gnu_get_operand(pn, deref)) == nil) return nil;
|
||||
|
||||
if ((t= get_token(*pn))->symbol == ',' || t->symbol == ':') {
|
||||
o1= e;
|
||||
(*pn)++;
|
||||
if ((o2= gnu_get_oplist(pn, deref)) == nil) {
|
||||
del_expr(o1);
|
||||
return nil;
|
||||
}
|
||||
e= new_expr();
|
||||
e->operator= ',';
|
||||
e->left= o1;
|
||||
e->right= o2;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
static asm86_t *gnu_get_statement(void)
|
||||
/* Get a pseudo op or machine instruction with arguments. */
|
||||
{
|
||||
token_t *t= get_token(0);
|
||||
asm86_t *a;
|
||||
mnemonic_t *m;
|
||||
int n;
|
||||
int prefix_seen;
|
||||
int deref;
|
||||
|
||||
assert(t->type == T_WORD);
|
||||
|
||||
a= new_asm86();
|
||||
|
||||
/* Process instruction prefixes. */
|
||||
for (prefix_seen= 0;; prefix_seen= 1) {
|
||||
if (strcmp(t->name, "rep") == 0
|
||||
|| strcmp(t->name, "repe") == 0
|
||||
|| strcmp(t->name, "repne") == 0
|
||||
|| strcmp(t->name, "repz") == 0
|
||||
|| strcmp(t->name, "repnz") == 0
|
||||
) {
|
||||
if (a->rep != ONCE) {
|
||||
parse_err(1, t,
|
||||
"can't have more than one rep\n");
|
||||
}
|
||||
switch (t->name[3]) {
|
||||
case 0: a->rep= REP; break;
|
||||
case 'e':
|
||||
case 'z': a->rep= REPE; break;
|
||||
case 'n': a->rep= REPNE; break;
|
||||
}
|
||||
} else
|
||||
if (!prefix_seen) {
|
||||
/* No prefix here, get out! */
|
||||
break;
|
||||
} else {
|
||||
/* No more prefixes, next must be an instruction. */
|
||||
if (t->type != T_WORD
|
||||
|| (m= search_mnem(t->name)) == nil
|
||||
|| m->optype == PSEUDO
|
||||
) {
|
||||
parse_err(1, t,
|
||||
"machine instruction expected after instruction prefix\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip the prefix and extra newlines. */
|
||||
do {
|
||||
skip_token(1);
|
||||
} while ((t= get_token(0))->symbol == ';');
|
||||
}
|
||||
|
||||
/* All the readahead being done upsets the line counter. */
|
||||
a->line= t->line;
|
||||
|
||||
/* Read a machine instruction or pseudo op. */
|
||||
if ((m= search_mnem(t->name)) == nil) {
|
||||
parse_err(1, t, "unknown instruction '%s'\n", t->name);
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
a->opcode= m->opcode;
|
||||
a->optype= m->optype;
|
||||
a->oaz= 0;
|
||||
if (a->optype == OWORD) {
|
||||
a->oaz|= OPZ;
|
||||
a->optype= WORD;
|
||||
}
|
||||
|
||||
switch (a->opcode) {
|
||||
case IN:
|
||||
case OUT:
|
||||
case INT:
|
||||
deref= 0;
|
||||
break;
|
||||
default:
|
||||
deref= (a->optype >= BYTE);
|
||||
}
|
||||
n= 1;
|
||||
if (get_token(1)->symbol != ';'
|
||||
&& (a->args= gnu_get_oplist(&n, deref)) == nil) {
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
if (get_token(n)->symbol != ';') {
|
||||
parse_err(1, t, "garbage at end of instruction\n");
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
if (!is_pseudo(a->opcode)) {
|
||||
/* GNU operand order is the other way around. */
|
||||
expression_t *e, *t;
|
||||
|
||||
e= a->args;
|
||||
while (e != nil && e->operator == ',') {
|
||||
t= e->right; e->right= e->left; e->left= t;
|
||||
e= e->left;
|
||||
}
|
||||
}
|
||||
switch (a->opcode) {
|
||||
case DOT_ALIGN:
|
||||
/* Delete two argument .align, because ACK can't do it.
|
||||
* Raise 2 to the power of .align's argument.
|
||||
*/
|
||||
if (a->args == nil || a->args->operator != 'W') {
|
||||
del_asm86(a);
|
||||
return nil;
|
||||
}
|
||||
if (a->args != nil && a->args->operator == 'W'
|
||||
&& isanumber(a->args->name)
|
||||
) {
|
||||
unsigned n;
|
||||
char num[sizeof(int) * CHAR_BIT / 3 + 1];
|
||||
|
||||
n= 1 << strtoul(a->args->name, nil, 0);
|
||||
sprintf(num, "%u", n);
|
||||
deallocate(a->args->name);
|
||||
a->args->name= copystr(num);
|
||||
}
|
||||
break;
|
||||
case JMPF:
|
||||
case CALLF:
|
||||
/*FALL THROUGH*/
|
||||
case JMP:
|
||||
case CALL:
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
skip_token(n+1);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
asm86_t *gnu_get_instruction(void)
|
||||
{
|
||||
asm86_t *a= nil;
|
||||
expression_t *e;
|
||||
token_t *t;
|
||||
|
||||
while ((t= get_token(0))->symbol == ';' || t->symbol == '/') {
|
||||
zap(); /* if a comment started by a '/' */
|
||||
skip_token(1);
|
||||
}
|
||||
|
||||
if (t->type == T_EOF) return nil;
|
||||
|
||||
if (t->symbol == '#') {
|
||||
/* Preprocessor line and file change. */
|
||||
|
||||
if ((t= get_token(1))->type != T_WORD || !isanumber(t->name)
|
||||
|| get_token(2)->type != T_STRING
|
||||
) {
|
||||
parse_err(1, t, "file not preprocessed?\n");
|
||||
zap();
|
||||
} else {
|
||||
set_file(get_token(2)->name,
|
||||
strtol(get_token(1)->name, nil, 0) - 1);
|
||||
|
||||
/* GNU CPP adds extra cruft, simply zap the line. */
|
||||
zap();
|
||||
}
|
||||
a= gnu_get_instruction();
|
||||
} else
|
||||
if (t->type == T_WORD && get_token(1)->symbol == ':') {
|
||||
/* A label definition. */
|
||||
|
||||
a= new_asm86();
|
||||
a->line= t->line;
|
||||
a->opcode= DOT_LABEL;
|
||||
a->optype= PSEUDO;
|
||||
a->args= e= new_expr();
|
||||
e->operator= ':';
|
||||
e->name= copystr(t->name);
|
||||
skip_token(2);
|
||||
} else
|
||||
if (t->type == T_WORD && get_token(1)->symbol == '=') {
|
||||
int n= 2;
|
||||
|
||||
if ((e= gnu_get_C_expression(&n)) == nil) {
|
||||
zap();
|
||||
a= gnu_get_instruction();
|
||||
} else
|
||||
if (get_token(n)->symbol != ';') {
|
||||
parse_err(1, t, "garbage after assignment\n");
|
||||
zap();
|
||||
a= gnu_get_instruction();
|
||||
} else {
|
||||
a= new_asm86();
|
||||
a->line= t->line;
|
||||
a->opcode= DOT_EQU;
|
||||
a->optype= PSEUDO;
|
||||
a->args= new_expr();
|
||||
a->args->operator= '=';
|
||||
a->args->name= copystr(t->name);
|
||||
a->args->middle= e;
|
||||
skip_token(n+1);
|
||||
}
|
||||
} else
|
||||
if (t->type == T_WORD) {
|
||||
if ((a= gnu_get_statement()) == nil) {
|
||||
zap();
|
||||
a= gnu_get_instruction();
|
||||
}
|
||||
} else {
|
||||
parse_err(1, t, "syntax error\n");
|
||||
zap();
|
||||
a= gnu_get_instruction();
|
||||
}
|
||||
return a;
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
asmprog:
|
||||
comment ?
|
||||
statement
|
||||
asmprog ; asmprog
|
||||
asmprog comment ? \n asmprog
|
||||
|
||||
letter:
|
||||
[._a-zA-Z]
|
||||
|
||||
digit:
|
||||
[0-9]
|
||||
|
||||
identifier:
|
||||
letter (letter | digit)*
|
||||
digit [bf]
|
||||
|
||||
string:
|
||||
'C-like string sequence'
|
||||
"C-like string sequence"
|
||||
|
||||
number:
|
||||
C-like number
|
||||
|
||||
comment:
|
||||
! .*
|
||||
|
||||
statement:
|
||||
label-definition statement
|
||||
empty
|
||||
assignment
|
||||
instruction
|
||||
pseudo-instruction
|
||||
|
||||
label-definition:
|
||||
identifier :
|
||||
digit :
|
||||
|
||||
assignment:
|
||||
identifier = expression
|
||||
|
||||
instruction:
|
||||
iX86-instruction
|
||||
|
||||
pseudo-instruction:
|
||||
.extern identifier (, identifier)*
|
||||
.define identifier (, identifier)*
|
||||
.data1 expression (, expression)*
|
||||
.data2 expression (, expression)*
|
||||
.data4 expression (, expression)*
|
||||
.ascii string
|
||||
.asciz string
|
||||
.align expression
|
||||
.space expression
|
||||
.comm identifier , expression
|
||||
.sect identifier
|
||||
.base expression
|
||||
.assert expression
|
||||
.symb XXX
|
||||
.line XXX
|
||||
.file XXX
|
||||
.nolist
|
||||
.list
|
||||
iX86-pseudo
|
||||
|
||||
expression:
|
||||
C-like expression with [ and ] for grouping
|
||||
|
||||
iX86-instruction:
|
||||
prefix
|
||||
prefix iX86-instruction
|
||||
identifier
|
||||
identifier iX86operand
|
||||
identifier iX86operand , iX86operand
|
||||
identifier iX86operand : iX86operand
|
||||
|
||||
prefix:
|
||||
o16
|
||||
o32
|
||||
a16
|
||||
a32
|
||||
rep
|
||||
repz
|
||||
repnz
|
||||
repe
|
||||
repne
|
||||
cseg | dseg | eseg | fseg | gseg | sseg
|
||||
|
||||
iX86operand:
|
||||
register
|
||||
( register )
|
||||
expression
|
||||
( expression )
|
||||
expression ( register )
|
||||
expression ( register * [1248] )
|
||||
expression ? ( register ) ( register )
|
||||
expression ? ( register ) ( register * [1248] )
|
||||
|
||||
register:
|
||||
al | bl | cl | dl | ah | bh | ch | dh
|
||||
ax | bx | cx | dx | si | di | bp | sp
|
||||
eax | ebx | ecx | edx | esi | edi | ebp | esp
|
||||
cs | ds | es | fs | gs | ss
|
||||
cr0 | cr1 | cr2 | cr3
|
||||
|
||||
iX86-pseudo:
|
||||
.use16
|
||||
.use32
|
|
@ -1,29 +0,0 @@
|
|||
/* token.h - token definition Author: Kees J. Bot
|
||||
* 13 Dec 1993
|
||||
*/
|
||||
|
||||
typedef enum toktype {
|
||||
T_EOF,
|
||||
T_CHAR,
|
||||
T_WORD,
|
||||
T_STRING
|
||||
} toktype_t;
|
||||
|
||||
typedef struct token {
|
||||
struct token *next;
|
||||
long line;
|
||||
toktype_t type;
|
||||
int symbol; /* Single character symbol. */
|
||||
char *name; /* Word, number, etc. */
|
||||
size_t len; /* Length of string. */
|
||||
} token_t;
|
||||
|
||||
#define S_LEFTSHIFT 0x100 /* << */
|
||||
#define S_RIGHTSHIFT 0x101 /* >> */
|
||||
|
||||
void set_file(char *file, long line);
|
||||
void get_file(char **file, long *line);
|
||||
void parse_err(int err, token_t *where, const char *fmt, ...);
|
||||
void tok_init(char *file, int comment);
|
||||
token_t *get_token(int n);
|
||||
void skip_token(int n);
|
|
@ -1,306 +0,0 @@
|
|||
/* tokenize.c - split input into tokens Author: Kees J. Bot
|
||||
* 13 Dec 1993
|
||||
*/
|
||||
#define nil 0
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "asmconv.h"
|
||||
#include "token.h"
|
||||
|
||||
static FILE *tf;
|
||||
static char *tfile;
|
||||
static char *orig_tfile;
|
||||
static int tcomment;
|
||||
static int tc;
|
||||
static long tline;
|
||||
static token_t *tq;
|
||||
|
||||
static void readtc(void)
|
||||
/* Read one character from the input file and put it in the global 'tc'. */
|
||||
{
|
||||
static int nl= 0;
|
||||
|
||||
if (nl) tline++;
|
||||
if ((tc= getc(tf)) == EOF && ferror(tf)) fatal(orig_tfile);
|
||||
nl= (tc == '\n');
|
||||
}
|
||||
|
||||
void set_file(char *file, long line)
|
||||
/* Set file name and line number, changed by a preprocessor trick. */
|
||||
{
|
||||
deallocate(tfile);
|
||||
tfile= allocate(nil, (strlen(file) + 1) * sizeof(tfile[0]));
|
||||
strcpy(tfile, file);
|
||||
tline= line;
|
||||
}
|
||||
|
||||
void get_file(char **file, long *line)
|
||||
/* Get file name and line number. */
|
||||
{
|
||||
*file= tfile;
|
||||
*line= tline;
|
||||
}
|
||||
|
||||
void parse_err(int err, token_t *t, const char *fmt, ...)
|
||||
/* Report a parsing error. */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "\"%s\", line %ld: ", tfile,
|
||||
t == nil ? tline : t->line);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
if (err) set_error();
|
||||
}
|
||||
|
||||
void tok_init(char *file, int comment)
|
||||
/* Open the file to tokenize and initialize the tokenizer. */
|
||||
{
|
||||
if (file == nil) {
|
||||
file= "stdin";
|
||||
tf= stdin;
|
||||
} else {
|
||||
if ((tf= fopen(file, "r")) == nil) fatal(file);
|
||||
}
|
||||
orig_tfile= file;
|
||||
set_file(file, 1);
|
||||
readtc();
|
||||
tcomment= comment;
|
||||
}
|
||||
|
||||
static int isspace(int c)
|
||||
{
|
||||
return between('\0', c, ' ') && c != '\n';
|
||||
}
|
||||
|
||||
#define iscomment(c) ((c) == tcomment)
|
||||
|
||||
static int isidentchar(int c)
|
||||
{
|
||||
return between('a', c, 'z')
|
||||
|| between('A', c, 'Z')
|
||||
|| between('0', c, '9')
|
||||
|| c == '.'
|
||||
|| c == '_'
|
||||
;
|
||||
}
|
||||
|
||||
static token_t *new_token(void)
|
||||
{
|
||||
token_t *new;
|
||||
|
||||
new= allocate(nil, sizeof(*new));
|
||||
new->next= nil;
|
||||
new->line= tline;
|
||||
new->name= nil;
|
||||
new->symbol= -1;
|
||||
return new;
|
||||
}
|
||||
|
||||
static token_t *get_word(void)
|
||||
/* Read one word, an identifier, a number, a label, or a mnemonic. */
|
||||
{
|
||||
token_t *w;
|
||||
char *name;
|
||||
size_t i, len;
|
||||
|
||||
i= 0;
|
||||
len= 16;
|
||||
name= allocate(nil, len * sizeof(name[0]));
|
||||
|
||||
while (isidentchar(tc)) {
|
||||
name[i++]= tc;
|
||||
readtc();
|
||||
if (i == len) name= allocate(name, (len*= 2) * sizeof(name[0]));
|
||||
}
|
||||
name[i]= 0;
|
||||
name= allocate(name, (i+1) * sizeof(name[0]));
|
||||
w= new_token();
|
||||
w->type= T_WORD;
|
||||
w->name= name;
|
||||
w->len= i;
|
||||
return w;
|
||||
}
|
||||
|
||||
static token_t *get_string(void)
|
||||
/* Read a single or double quotes delimited string. */
|
||||
{
|
||||
token_t *s;
|
||||
int quote;
|
||||
char *str;
|
||||
size_t i, len;
|
||||
int n, j;
|
||||
int seen;
|
||||
|
||||
quote= tc;
|
||||
readtc();
|
||||
|
||||
i= 0;
|
||||
len= 16;
|
||||
str= allocate(nil, len * sizeof(str[0]));
|
||||
|
||||
while (tc != quote && tc != '\n' && tc != EOF) {
|
||||
seen= -1;
|
||||
if (tc == '\\') {
|
||||
readtc();
|
||||
if (tc == '\n' || tc == EOF) break;
|
||||
|
||||
switch (tc) {
|
||||
case 'a': tc= '\a'; break;
|
||||
case 'b': tc= '\b'; break;
|
||||
case 'f': tc= '\f'; break;
|
||||
case 'n': tc= '\n'; break;
|
||||
case 'r': tc= '\r'; break;
|
||||
case 't': tc= '\t'; break;
|
||||
case 'v': tc= '\v'; break;
|
||||
case 'x':
|
||||
n= 0;
|
||||
for (j= 0; j < 3; j++) {
|
||||
readtc();
|
||||
if (between('0', tc, '9'))
|
||||
tc-= '0' + 0x0;
|
||||
else
|
||||
if (between('A', tc, 'A'))
|
||||
tc-= 'A' + 0xA;
|
||||
else
|
||||
if (between('a', tc, 'a'))
|
||||
tc-= 'a' + 0xa;
|
||||
else {
|
||||
seen= tc;
|
||||
break;
|
||||
}
|
||||
n= n*0x10 + tc;
|
||||
}
|
||||
tc= n;
|
||||
break;
|
||||
default:
|
||||
if (!between('0', tc, '9')) break;
|
||||
n= 0;
|
||||
for (j= 0; j < 3; j++) {
|
||||
if (between('0', tc, '9'))
|
||||
tc-= '0';
|
||||
else {
|
||||
seen= tc;
|
||||
break;
|
||||
}
|
||||
n= n*010 + tc;
|
||||
readtc();
|
||||
}
|
||||
tc= n;
|
||||
}
|
||||
}
|
||||
str[i++]= tc;
|
||||
if (i == len) str= allocate(str, (len*= 2) * sizeof(str[0]));
|
||||
|
||||
if (seen < 0) readtc(); else tc= seen;
|
||||
}
|
||||
|
||||
if (tc == quote) {
|
||||
readtc();
|
||||
} else {
|
||||
parse_err(1, nil, "string contains newline\n");
|
||||
}
|
||||
str[i]= 0;
|
||||
str= allocate(str, (i+1) * sizeof(str[0]));
|
||||
s= new_token();
|
||||
s->type= T_STRING;
|
||||
s->name= str;
|
||||
s->len= i;
|
||||
return s;
|
||||
}
|
||||
|
||||
static int old_n= 0; /* To speed up n, n+1, n+2, ... accesses. */
|
||||
static token_t **old_ptq= &tq;
|
||||
|
||||
token_t *get_token(int n)
|
||||
/* Return the n-th token on the input queue. */
|
||||
{
|
||||
token_t *t, **ptq;
|
||||
|
||||
assert(n >= 0);
|
||||
|
||||
if (0 && n >= old_n) {
|
||||
/* Go forward from the previous point. */
|
||||
n-= old_n;
|
||||
old_n+= n;
|
||||
ptq= old_ptq;
|
||||
} else {
|
||||
/* Restart from the head of the queue. */
|
||||
old_n= n;
|
||||
ptq= &tq;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if ((t= *ptq) == nil) {
|
||||
/* Token queue doesn't have element <n>, read a
|
||||
* new token from the input stream.
|
||||
*/
|
||||
while (isspace(tc) || iscomment(tc)) {
|
||||
if (iscomment(tc)) {
|
||||
while (tc != '\n' && tc != EOF)
|
||||
readtc();
|
||||
} else {
|
||||
readtc();
|
||||
}
|
||||
}
|
||||
|
||||
if (tc == EOF) {
|
||||
t= new_token();
|
||||
t->type= T_EOF;
|
||||
} else
|
||||
if (isidentchar(tc)) {
|
||||
t= get_word();
|
||||
} else
|
||||
if (tc == '\'' || tc == '"') {
|
||||
t= get_string();
|
||||
} else {
|
||||
if (tc == '\n') tc= ';';
|
||||
t= new_token();
|
||||
t->type= T_CHAR;
|
||||
t->symbol= tc;
|
||||
readtc();
|
||||
if (t->symbol == '<' && tc == '<') {
|
||||
t->symbol= S_LEFTSHIFT;
|
||||
readtc();
|
||||
} else
|
||||
if (t->symbol == '>' && tc == '>') {
|
||||
t->symbol= S_RIGHTSHIFT;
|
||||
readtc();
|
||||
}
|
||||
}
|
||||
*ptq= t;
|
||||
}
|
||||
if (n == 0) break;
|
||||
n--;
|
||||
ptq= &t->next;
|
||||
}
|
||||
old_ptq= ptq;
|
||||
return t;
|
||||
}
|
||||
|
||||
void skip_token(int n)
|
||||
/* Remove n tokens from the input queue. One is not allowed to skip unread
|
||||
* tokens.
|
||||
*/
|
||||
{
|
||||
token_t *junk;
|
||||
|
||||
assert(n >= 0);
|
||||
|
||||
while (n > 0) {
|
||||
assert(tq != nil);
|
||||
|
||||
junk= tq;
|
||||
tq= tq->next;
|
||||
deallocate(junk->name);
|
||||
deallocate(junk);
|
||||
n--;
|
||||
}
|
||||
/* Reset the old reference. */
|
||||
old_n= 0;
|
||||
old_ptq= &tq;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
SCRIPTS= binpackage.sh
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,78 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin
|
||||
PI=.postinstall
|
||||
INFO=.minixpackage
|
||||
|
||||
set -e
|
||||
|
||||
# No trailing slashes in the directory, because we want to base the
|
||||
# package filename on it.
|
||||
dir=`echo "$1" | sed 's/\/*$//'`
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then echo "Usage: $0 sourcedir packagedir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$dir" ]
|
||||
then echo "Error: $dir isn't a directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
here=`pwd`
|
||||
|
||||
case "$dir" in
|
||||
/*) srcdir="$dir" ;;
|
||||
*) srcdir="$here/$dir" ;;
|
||||
esac
|
||||
|
||||
case $2 in
|
||||
/*) pdir="$2" ;;
|
||||
*) pdir="$here/$2" ;;
|
||||
esac
|
||||
|
||||
packagestart=$srcdir/now
|
||||
findlist=$srcdir/findlist
|
||||
tar=$srcdir/"`basename ${dir}`".tar
|
||||
tarbz=$tar.bz2
|
||||
|
||||
mkdir $pdir 2>/dev/null || true
|
||||
rc=$dir/.binpackage
|
||||
if [ -f $rc ]
|
||||
then . $rc
|
||||
fi
|
||||
|
||||
prunedirs="$srcdir dev tmp usr/bigports usr/src usr/tmp usr/log usr/adm usr/run home etc/utmp var/run var/log /var/spool"
|
||||
|
||||
for d in $prunedirs
|
||||
do pruneexpr="$pruneexpr $n -path /$d -prune"
|
||||
n="-o "
|
||||
done
|
||||
|
||||
touch $packagestart
|
||||
sleep 1
|
||||
cd $dir
|
||||
|
||||
if [ ! -f build -a ! -f build.minix ]
|
||||
then echo "Error: No build or build.minix script in $dir."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f build.minix ]
|
||||
then sh -e build.minix
|
||||
else sh -e build
|
||||
fi
|
||||
|
||||
echo " * Building package"
|
||||
echo "Minix package $dir built `date`." >$INFO
|
||||
(
|
||||
echo $INFO
|
||||
if [ -f $PI ]
|
||||
then echo $PI
|
||||
fi
|
||||
find / \( $pruneexpr \) -o -cnewer $packagestart -print | fgrep -v /.svn
|
||||
) | pax -w -d | bzip2 >$tarbz
|
||||
rm -f $packagestart $findlist $tarcmd
|
||||
mv $tarbz $pdir
|
||||
exit 0
|
|
@ -1,4 +0,0 @@
|
|||
SCRIPTS= binpackages.sh
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
pdir=Packages
|
||||
|
||||
for d in */build
|
||||
do
|
||||
dir="`echo $d | sed 's/\/build$//'`"
|
||||
if [ ! -f $pdir/$dir.tar.gz ]
|
||||
then
|
||||
echo " * $dir"
|
||||
binpackage $dir $pdir
|
||||
fi
|
||||
done
|
|
@ -1,4 +0,0 @@
|
|||
PROG= chmem
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,148 +0,0 @@
|
|||
/* chmem - set total memory size for execution Author: Andy Tanenbaum */
|
||||
|
||||
#include <minix/config.h>
|
||||
#include <sys/types.h>
|
||||
#include <a.out.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAX_8086 0x10000L /* maximum allocation size for 8086 */
|
||||
#define MAX_386 0x7FFFFFFFL /* etc */
|
||||
#define MAX_68K 0x7FFFFFFFL
|
||||
#define MAX_SPARC 0x20000000L /* No more than 512MB on a SparcStation! */
|
||||
|
||||
char *progname;
|
||||
|
||||
_PROTOTYPE(int main, (int argc, char **argv));
|
||||
_PROTOTYPE(void error, (char *s1, char *s2));
|
||||
_PROTOTYPE(void usage, (void));
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
/* The 8088 architecture does not make it possible to catch stacks that grow
|
||||
* big. The only way to deal with this problem is to let the stack grow down
|
||||
* towards the data segment and the data segment grow up towards the stack.
|
||||
* Normally, a total of 64K is allocated for the two of them, but if the
|
||||
* programmer knows that a smaller amount is sufficient, he can change it
|
||||
* using chmem.
|
||||
*
|
||||
* chmem =4096 prog sets the total space for stack + data growth to 4096
|
||||
* chmem +200 prog increments the total space for stack + data growth by 200
|
||||
*/
|
||||
|
||||
char *p;
|
||||
int fd = -1, separate;
|
||||
size_t s;
|
||||
long lsize, olddynam, newdynam, newtot, overflow;
|
||||
struct exec exec;
|
||||
char cpu;
|
||||
long max;
|
||||
int last_failed = 0, any_failed = 0;
|
||||
|
||||
progname = argv[0];
|
||||
if (argc < 3) usage();
|
||||
p = argv[1];
|
||||
if (*p != '=' && *p != '+' && *p != '-') usage();
|
||||
lsize = atol(p + 1);
|
||||
s = sizeof(struct exec);
|
||||
|
||||
if (lsize < 0) {
|
||||
error(p + 1, "is negative");
|
||||
exit(1);
|
||||
}
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
|
||||
while (--argc) {
|
||||
if(last_failed) any_failed = 1;
|
||||
|
||||
/* Unless we reach the end of this loop, this one failed. */
|
||||
last_failed = 1;
|
||||
++argv;
|
||||
if(fd != -1) close(fd);
|
||||
fd = open(*argv, O_RDWR);
|
||||
if (fd < 0) {
|
||||
error("can't open", *argv);
|
||||
continue;
|
||||
}
|
||||
if (read(fd, (char *) &exec, s) != s) {
|
||||
error("can't read header in", *argv);
|
||||
continue;
|
||||
}
|
||||
if (BADMAG(exec)) {
|
||||
error(*argv, "is not executable");
|
||||
continue;
|
||||
}
|
||||
separate = (exec.a_flags & A_SEP ? 1 : 0);
|
||||
cpu = exec.a_cpu;
|
||||
|
||||
#if (CHIP == M68000)
|
||||
if (cpu == A_I8086) cpu = A_M68K;
|
||||
#endif
|
||||
|
||||
switch (cpu) {
|
||||
case A_I8086: max = MAX_8086; break;
|
||||
case A_I80386: max = MAX_386; break;
|
||||
case A_M68K: max = MAX_68K; break;
|
||||
case A_SPARC: max = MAX_SPARC; break;
|
||||
default:
|
||||
error("bad CPU type in", *argv);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lsize > max) {
|
||||
error("size is too large for", *argv);
|
||||
continue;
|
||||
}
|
||||
olddynam = exec.a_total - exec.a_data - exec.a_bss;
|
||||
if (separate == 0) olddynam -= exec.a_text;
|
||||
|
||||
if (*p == '=')
|
||||
newdynam = lsize;
|
||||
else if (*p == '+')
|
||||
newdynam = olddynam + lsize;
|
||||
else if (*p == '-')
|
||||
newdynam = olddynam - lsize;
|
||||
|
||||
newtot = exec.a_data + exec.a_bss + newdynam;
|
||||
if (separate == 0) newtot += exec.a_text;
|
||||
overflow = (newtot > max ? newtot - max : 0);
|
||||
newdynam -= overflow;
|
||||
newtot -= overflow;
|
||||
exec.a_total = newtot;
|
||||
lseek(fd, (long) 0, SEEK_SET);
|
||||
if (write(fd, (char *) &exec, s) != s) {
|
||||
error("can't modify", *argv);
|
||||
continue;
|
||||
}
|
||||
printf("%s: Stack+malloc area changed from %ld to %ld bytes.\n",
|
||||
*argv, olddynam, newdynam);
|
||||
|
||||
/* This one didn't fail. */
|
||||
last_failed = 0;
|
||||
}
|
||||
return(any_failed || last_failed ? 1 : 0);
|
||||
}
|
||||
|
||||
void error(s1, s2)
|
||||
char *s1;
|
||||
char *s2;
|
||||
{
|
||||
fprintf(stderr, "%s: %s ", progname, s1);
|
||||
if (errno != 0)
|
||||
perror(s2);
|
||||
else
|
||||
fprintf(stderr, "%s\n", s2);
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s {=+-} amount file\n", progname);
|
||||
exit(1);
|
||||
}
|
|
@ -3,12 +3,7 @@
|
|||
|
||||
PROG= cut
|
||||
|
||||
.if ${COMPILER_TYPE} != "gnu"
|
||||
LDADD+= -lminixutil
|
||||
DPADD+= ${LIBMINIXUTIL}
|
||||
.else
|
||||
LDADD+= -lutil
|
||||
DPADD+= ${LIBUTIL}
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
.include <bsd.own.mk>
|
||||
|
||||
PROG= date
|
||||
SRCS= date.c logwtmp.c
|
||||
TZDIR= /usr/share/zoneinfo
|
||||
CPPFLAGS+= -DHAVE_ADJTIME=0 -DTZDIR=\"$(TZDIR)\"
|
||||
BINDIR= /bin
|
||||
|
||||
.PATH: ${MINIXSRCDIR}/lib/libc/stdtime
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,9 +0,0 @@
|
|||
# Makefile for dis386
|
||||
|
||||
PROGS= dis386e dis386o
|
||||
SRCS.dis386e=dise.c misc.c unasm.c
|
||||
SRCS.dis386o=diso.c misc.c unasm.c
|
||||
MAN.dis386e=
|
||||
MAN.dis386o=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,56 +0,0 @@
|
|||
/* const.h - constants for db.
|
||||
*
|
||||
* $Id: const.h,v 1.0 1990/10/06 12:00:00 cwr Exp cwr $
|
||||
*/
|
||||
|
||||
/* general constants */
|
||||
#define FALSE 0
|
||||
#undef NULL
|
||||
#define NULL 0
|
||||
#define TRUE 1
|
||||
|
||||
/* C tricks */
|
||||
#define EXTERN extern
|
||||
#define FORWARD static
|
||||
#define PRIVATE static
|
||||
#define PUBLIC
|
||||
|
||||
/* ASCII codes */
|
||||
#define CAN 24
|
||||
#define CR 13
|
||||
#define EOF (-1)
|
||||
#define LF 10
|
||||
#define XOFF 19
|
||||
|
||||
/* hardware processor-specific for 8088 through 80386 */
|
||||
#ifndef HCLICK_SIZE
|
||||
#define HCLICK_SIZE 0x10
|
||||
#endif
|
||||
#define IF 0x0200 /* interrupt disable bit in flags */
|
||||
#define INT_BREAKPOINT 0xCC /* byte for breakpoint interrupt */
|
||||
#define LINEARADR(seg, off) \
|
||||
(HCLICK_SIZE * (physoff_t) (segment_t) (seg) + (off))
|
||||
#define TF 0x0100 /* trap bit in flags */
|
||||
|
||||
/* hardware processor-specific for 80386 and emulated for others */
|
||||
#define BS 0x4000 /* single-step bit in dr6 */
|
||||
|
||||
/* use hardware codes for segments for simplest decoding */
|
||||
#define CSEG 0x2E /* 8088 through 80386 */
|
||||
#define DSEG 0x3E
|
||||
#define ESEG 0x26
|
||||
#define FSEG 0x64
|
||||
#define GSEG 0x65 /* 80386 only */
|
||||
#define SSEG 0x36
|
||||
|
||||
/* software machine-specific for PC family */
|
||||
#define BIOS_DATA_SEG 0x40
|
||||
# define KB_FLAG 0x17 /* offset to 16-bits of keyboard shift flags */
|
||||
|
||||
/* switches to handle non-conforming compilers */
|
||||
#define UCHAR_BUG /* compiler converts unsigned chars wrong */
|
||||
|
||||
#ifdef UCHAR_BUG
|
||||
# define UCHAR(x) ((x) & 0xFF)
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue