dslinux/user/perl/mpeix mpeix.c mpeix_setjmp.c mpeixish.h nm relink
cayenne
dslinux_cayenne at user.in-berlin.de
Mon Dec 4 18:01:20 CET 2006
Update of /cvsroot/dslinux/dslinux/user/perl/mpeix
In directory antilope:/tmp/cvs-serv17422/mpeix
Added Files:
mpeix.c mpeix_setjmp.c mpeixish.h nm relink
Log Message:
Adding fresh perl source to HEAD to branch from
--- NEW FILE: relink ---
#!/bin/sh
# The MPE POSIX libc archive library contains rand(), but this function has
# been omitted from the libc shared library on the mistaken assumption that
# the rand() function in the kernel library /SYS/PUB/XL could be used instead.
# However, rand() in /SYS/PUB/XL is a Fortran function with different semantics
# from the C version that we expect.
# So in order to get the correct rand() function and to make it available to
# the dynamically loaded perl extensions, we will build our own mini rand()
# shared library and add this to the perl NMPRG's XL list.
RAND=/$HPACCOUNT/$HPGROUP/libcrand
echo "Creating $RAND.sl...\n"
TEMP=perlmpe.$$
rm -f $TEMP $RAND.a $RAND.sl
/bin/cat - >$TEMP <<EOF
buildrl $RAND.a
copyrl from=/lib/libc.a;to=$RAND.a;module=rand
revealrl rl=$RAND.a;all
buildxl $RAND.sl;limit=1
addxl from=$RAND.a;to=$RAND.sl;share
listxl xl=$RAND.sl
EOF
callci "xeq LINKEDIT.PUB.SYS <$TEMP"
rm -f $TEMP $RAND.a
# MPE/iX as of 5.5 does not yet properly support linking against dynamic
# libraries via gcc or ld. For now, re-run gcc without the external library
# list, and then run the native linker with the list of dynamic libraries.
echo "Creating the perl executable NMPRG..."
gcc -o perl perlmain.o \
lib/auto/DynaLoader/DynaLoader.a \
libperl.a \
`cat ext.libs` \
-L/BINDFW/CURRENT/lib -lbind \
-L/SYSLOG/PUB -lsyslog
echo "Modifying the perl executable NMPRG XL list...\n"
callci "xeq LINKEDIT.PUB.SYS 'altprog ./perl;xl=/usr/lib/libcurses.sl,/lib/libsvipc.sl,/usr/lib/libsocket.sl,/usr/lib/libstr.sl,/lib/libm.sl,$RAND.sl,/lib/libc.sl'"
--- NEW FILE: mpeix.c ---
/*
* gcc long pointer support code for HPPA.
* Copyright 1998, DIS International, Ltd.
* This code is free software; you may redistribute it and/or modify
* it under the same terms as Perl itself. (Relicensed for Perl in
* in April 2002 by Mark Klein.)
*/
typedef struct {
int spaceid;
unsigned int offset;
} LONGPOINTER, longpointer;
/*
* gcc long pointer support code for HPPA.
* Copyright 1998, DIS International, Ltd.
* This code is free software; you may redistribute it and/or modify
* it under the same terms as Perl itself. (Relicensed for Perl in
* in April 2002 by Mark Klein.)
*/
int __perl_mpe_getspaceid(void *source)
{
int val;
/*
* Given the short pointer, determine it's space ID.
*/
/*
* The colons separate output from input parameters. In this case,
* the output of the instruction (output indicated by the "=" in the
* constraint) is to a memory location (indicated by the "m"). The
* input constraint indicates that the source to the instruction
* is a register reference (indicated by the "r").
* The general format is:
* asm("<instruction template>" : <output> : <input> : <clobbers>);
* where <output> and <input> are:
* "<constraint>" (<token>)
* <instruction template> is the PA-RISC instruction in template fmt.
* <clobbers> indicates those registers clobbered by the instruction
* and provides hints to the optimizer.
*
* Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html
*/
__asm__ __volatile__ (
" comiclr,= 0,%1,%%r28\n"
"\t ldsid (%%r0,%1),%%r28\n"
"\t stw %%r28, %0"
: "=m" (val) // Output to val
: "r" (source) // Source must be gen reg
: "%r28"); // Clobbers %r28
return (val);
};
LONGPOINTER __perl_mpe_longaddr(void *source)
{
LONGPOINTER lptr;
/*
* Return the long pointer for the address in sr5 space.
*/
__asm__ __volatile__ (
" comiclr,= 0,%2,%%r28\n"
"\t ldsid (%%r0,%2),%%r28\n"
"\t stw %%r28, %0\n"
"\t stw %2, %1"
: "=m" (lptr.spaceid),
"=m" (lptr.offset) // Store to lptr
: "r" (source) // Source must be gen reg
: "%r28"); // Clobbers %r28
return (lptr);
};
LONGPOINTER __perl_mpe_addtopointer(LONGPOINTER source, // %r26 == source offset
// %r25 == source space
int len) // %r24 == length in bytes
{
/*
* Increment a longpointer.
*/
__asm__ __volatile__ (
" copy %0,%%r28\n" // copy space to r28
"\t add %1,%2,%%r29" // Increment the pointer
: // No output
: "r" (source.spaceid), // Source address
"r" (source.offset),
"r" (len) // Length
: "%r28", // Clobbers
"%r29");
};
void __perl_mpe_longmove(int len, // %r26 == byte length
LONGPOINTER source, // %r23 == source space, %r24 == off
LONGPOINTER target) // sp-#56 == target space, sp-#52== off
{
/*
* Move data between two buffers in long pointer space.
*/
__asm__ __volatile__ (
" .import $$lr_unk_unk_long,MILLICODE\n"
"\t mtsp %0,%%sr1\n" // copy source space to sr1
"\t copy %1,%%r26\n" // load source offset to r26
"\t copy %4,%%r24\n" // load length to r24
"\t copy %3,%%r25\n" // load target offset to r25
"\t bl $$lr_unk_unk_long,%%r31\n" // start branch to millicode
"\t mtsp %2,%%sr2" // copy target space to sr2
: // No output
: "r" (source.spaceid), // Source address
"r" (source.offset),
"r" (target.spaceid), // Target address
"r" (target.offset),
"r" (len) // Byte length
: "%r1", // Clobbers
"%r24",
"%r25",
"%r26",
"%r31");
};
int __perl_mpe_longpeek(LONGPOINTER source)
{
/*
* Fetch the int in long pointer space.
*/
unsigned int val;
__asm__ __volatile__ (
" mtsp %1, %%sr1\n"
"\t copy %2, %%r28\n"
"\t ldw 0(%%sr1, %%r28), %%r28\n"
"\t stw %%r28, %0"
: "=m" (val) // Output val
: "r" (source.spaceid), // Source space ID
"r" (source.offset) // Source offset
: "%r28"); // Clobbers %r28
return (val);
};
void __perl_mpe_longpoke(LONGPOINTER target, // %r25 == spaceid, %r26 == offset
unsigned int val) // %r24 == value
{
/*
* Store the val into long pointer space.
*/
__asm__ __volatile__ (
" mtsp %0,%%sr1\n"
"\t copy %1, %%r28\n"
"\t stw %2, 0(%%sr1, %%r28)"
: // No output
: "r" (target.spaceid), // Target space ID
"r" (target.offset), // Target offset
"r" (val) // Value to store
: "%r28" // Clobbers %r28
); // Copy space to %sr1
};
void __perl_mpe_move_fast(int len, // %r26 == byte length
void *source, // %r25 == source addr
void *target) // %r24 == target addr
{
/*
* Move using short pointers.
*/
__asm__ __volatile__ (
" .import $$lr_unk_unk,MILLICODE\n"
"\t copy %1, %%r26\n" // Move source addr into pos
"\t copy %2, %%r25\n" // Move target addr into pos
"\t bl $$lr_unk_unk,%%r31\n" // Start branch to millicode
"\t copy %0, %%r24" // Move length into position
: // No output
: "r" (len), // Byte length
"r" (source), // Source address
"r" (target) // Target address
: "%r24", // Clobbers
"%r25",
"%r26",
"%r31");
};
/*
* ftruncate - set file size, BSD Style
*
* shortens or enlarges the file as neeeded
* uses some undocumented locking call. It is known to work on SCO unix,
* other vendors should try.
* The #error directive prevents unsupported OSes
*
* ftruncate/truncate code by Mark Bixby.
* This code is free software; you may redistribute it and/or modify
* it under the same terms as Perl itself.
*
*/
#ifndef _POSIX_SOURCE
# define _POSIX_SOURCE
#endif
#ifndef _SOCKET_SOURCE
# define _SOCKET_SOURCE
#endif
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <limits.h>
#include <mpe.h>
extern void FCONTROL(short, short, longpointer);
extern void PRINTFILEINFO(int);
int ftruncate(int fd, long wantsize);
int
ftruncate(int fd, long wantsize)
{
int ccode_return,dummy=0;
if (lseek(fd, wantsize, SEEK_SET) < 0)
{
return (-1);
}
FCONTROL(_mpe_fileno(fd),6,__perl_mpe_longaddr(&dummy)); /* Write new EOF */
if ((ccode_return=ccode()) != CCE)
{
fprintf(stderr,
"MPE ftruncate failed, ccode=%d, wantsize=%ld\n",
ccode_return, wantsize);
PRINTFILEINFO(_mpe_fileno(fd));
errno = ESYSERR;
return (-1);
}
return (0);
}
/*
wrapper for truncate():
truncate() is UNIX, not POSIX.
This function requires ftruncate().
NAME
truncate -
SYNOPSIS
#include <unistd.h>
int truncate(const char *pathname, off_t length);
Returns: 0 if OK, -1 on error
from: Stevens' Advanced Programming in the UNIX Environment, p. 92
ERRORS
EACCES
EBADF
EDQUOT (not POSIX) <- not implemented here
EFAULT
EINVAL
EISDIR
ELOOP (not POSIX) <- not implemented here
ENAMETOOLONG
ENOTDIR
EROFS
ETXTBSY (not POSIX) <- not implemented here
from: HP-UX man page
Compile directives:
PRINT_ERROR - make this function print an error message to stderr
*/
#include <sys/types.h> /* off_t, required by open() */
#include <sys/stat.h> /* required by open() */
#include <fcntl.h> /* open() */
#include <unistd.h> /* close() */
#include <stdio.h> /* perror(), sprintf() */
int
truncate(const char *pathname, off_t length)
{
int fd;
#ifdef PRINT_ERROR
char error_msg[80+1];
#endif
if (length == 0)
{
if ( (fd = open(pathname, O_WRONLY | O_TRUNC)) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
sprintf(error_msg,
"truncate(): open(%s, O_WRONLY | OTRUNC)\0",
pathname);
perror(error_msg);
#endif
return -1;
}
}
else
{
if ( (fd = open(pathname, O_WRONLY)) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
sprintf(error_msg,
"truncate(): open(%s, O_WRONLY)\0",
pathname);
perror(error_msg);
#endif
return -1;
}
if (ftruncate(fd, length) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
perror("truncate(): ftruncate()");
#endif
return -1;
}
}
if (close(fd) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
perror("truncate(): close()");
#endif
return -1;
}
return 0;
} /* truncate() */
/*
wrapper for gettimeofday():
gettimeofday() is UNIX, not POSIX.
gettimeofday() is a BSD function.
NAME
gettimeofday -
SYNOPSIS
#include <sys/time.h>
int gettimeofday(struct timeval *tp, struct timezone *tzp);
DESCRIPTION
This function returns seconds and microseconds since midnight
January 1, 1970. The microseconds is actually only accurate to
the millisecond.
Note: To pick up the definitions of structs timeval and timezone
from the <time.h> include file, the directive
_SOCKET_SOURCE must be used.
RETURN VALUE
A 0 return value indicates that the call succeeded. A -1 return
value indicates an error occurred; errno is set to indicate the
error.
ERRORS
EFAULT not implemented
Changes:
2-91 DR. Created.
*/
/* need _SOCKET_SOURCE to pick up structs timeval and timezone in time.h */
#ifndef _SOCKET_SOURCE
# define _SOCKET_SOURCE
#endif
#include <time.h> /* structs timeval & timezone,
difftime(), localtime(), mktime(), time() */
extern int TIMER();
/*
* gettimeofday code by Mark Bixby.
* This code is free software; you may redistribute it and/or modify
* it under the same terms as Perl itself.
*/
#ifdef __STDC__
int gettimeofday( struct timeval *tp, struct timezone *tpz )
#else
int gettimeofday( tp, tpz )
struct timeval *tp;
struct timezone *tpz;
#endif
{
static unsigned long basetime = 0;
static int dsttime = 0;
static int minuteswest = 0;
static int oldtime = 0;
register int newtime;
/*-------------------------------------------------------------------*/
/* Setup a base from which all future time will be computed. */
/*-------------------------------------------------------------------*/
if ( basetime == 0 )
{
time_t gmt_time;
time_t loc_time;
struct tm *loc_time_tm;
gmt_time = time( NULL );
loc_time_tm = localtime( &gmt_time ) ;
loc_time = mktime( loc_time_tm );
oldtime = TIMER();
basetime = (unsigned long) ( loc_time - (oldtime/1000) );
/*----------------------------------------------------------------*/
/* The calling process must be restarted if timezone or dst */
/* changes. */
/*----------------------------------------------------------------*/
minuteswest = (int) (difftime( loc_time, gmt_time ) / 60);
dsttime = loc_time_tm->tm_isdst;
}
/*-------------------------------------------------------------------*/
/* Get the new time value. The timer value rolls over every 24 days, */
/* so if the delta is negative, the basetime value is adjusted. */
/*-------------------------------------------------------------------*/
newtime = TIMER();
if ( newtime < oldtime ) basetime += 2073600;
oldtime = newtime;
/*-------------------------------------------------------------------*/
/* Return the timestamp info. */
/*-------------------------------------------------------------------*/
tp->tv_sec = basetime + newtime/1000;
tp->tv_usec = (newtime%1000) * 1000; /* only accurate to milli */
if (tpz)
{
tpz->tz_minuteswest = minuteswest;
tpz->tz_dsttime = dsttime;
}
return 0;
} /* gettimeofday() */
/*
** MPE_FCNTL -- shadow function for fcntl()
**
** MPE requires sfcntl() for sockets, and fcntl() for everything
** else. This shadow routine determines the descriptor type and
** makes the appropriate call.
**
** Parameters:
** same as fcntl().
**
** Returns:
** same as fcntl().
*/
#include <stdarg.h>
#include <sys/socket.h>
int
mpe_fcntl(int fildes, int cmd, ...)
{
int len, result;
struct sockaddr sa;
void *arg;
va_list ap;
va_start(ap, cmd);
arg = va_arg(ap, void *);
va_end(ap);
len = sizeof sa;
if (getsockname(fildes, &sa, &len) == -1)
{
if (errno == EAFNOSUPPORT)
/* AF_UNIX socket */
return sfcntl(fildes, cmd, arg);
if (errno == ENOTSOCK)
/* file or pipe */
return fcntl(fildes, cmd, arg);
/* unknown getsockname() failure */
return (-1);
}
else
{
/* AF_INET socket */
if ((result = sfcntl(fildes, cmd, arg)) != -1 && cmd == F_GETFL)
result |= O_RDWR; /* fill in some missing flags */
return result;
}
}
/*
* Stuff from here on down is written by Ken Hirsch
* and you may use it for any purpose.
* No warranty, express or implied.
*/
#include <stddef.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#ifndef _SOCKLEN_T
typedef unsigned int socklen_t;
#define _SOCKLEN_T
#endif
static int max_io_size(int filedes);
ssize_t
mpe_read(int filedes, void *buffer, size_t len)
{
int maxio;
if (len > 4096 && (len > (maxio = max_io_size(filedes))))
len = maxio;
return read(filedes, buffer, len);
}
ssize_t
mpe_write(int filedes, const void *buffer, size_t len)
{
int written = 0;
int orig_len = len;
int maxio = (len>4096)?max_io_size(filedes):INT_MAX;
const char *buf = (const char *)buffer;
do {
written = write(filedes, buf, len>maxio?maxio:len);
if (written < 0)
break;
len -= written;
buf += written;
} while (len > 0);
if (written < 0 && len == orig_len)
return -1;
else
return orig_len - len;
}
ssize_t
mpe_send(int socket, const void *buffer, size_t len, int flags)
{
int written = 0;
int orig_len = len;
int maxio = (len>4096)?max_io_size(socket):INT_MAX;
const char *buf = (const char *)buffer;
do {
written = send(socket, buf, len>maxio?maxio:len, flags);
if (written < 0)
break;
len -= written;
buf += written;
} while (len > 0);
if (written < 0 && len == orig_len)
return -1;
else
return orig_len - len;
}
ssize_t
mpe_sendto(int socket, const void *buffer, size_t len,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len)
{
int written = 0;
int orig_len = len;
int maxio = (len>4096)?max_io_size(socket):INT_MAX;
const char *buf = (const char *)buffer;
do {
written =
sendto(socket, buf, len>maxio?maxio:len, flags, dest_addr, dest_len);
if (written < 0)
break;
len -= written;
buf += written;
} while (len > 0);
if (written < 0 && len == orig_len)
return -1;
else
return orig_len - len;
}
ssize_t
mpe_recv(int socket, void *buffer, size_t len, int flags)
{
int maxio;
if (len > 4096 && (len > (maxio = max_io_size(socket))))
len = maxio;
return recv(socket, buffer, len, flags);
}
ssize_t
mpe_recvfrom(int socket, void *buffer, size_t len,
int flags, struct sockaddr *address,
socklen_t *address_len)
{
int maxio;
if (len > 4096 && (len > (maxio = max_io_size(socket))))
len = maxio;
return recvfrom(socket, buffer, len, flags, address, address_len);
}
/*
I didn't do thse two:
ssize_t mpe_recvmsg(int, struct msghdr *, int);
ssize_t mpe_sendmsg(int, const struct msghdr *, int);
*/
/*
* On MPE/iX (at least version 6.0), a getsockname()
* performed on a socket that is listening
* will return INADDR_ANY, even if you used
* bind to bind it to a particular IP address.
*
* (In fact, it appears that the socket always acts as
* if you used INADDR_ANY.)
*
* Here I save the IP address used in bind
* So I can get it in getsockname()
*
*/
/* I just save 40. Usually one or two should be enough
*/
int
mpe_connect(int socket,
const struct sockaddr *address,
socklen_t address_len)
{
int ret = connect(socket, address, address_len);
if (ret < 0 && errno == EINPROGRESS)
{
/* Need to call getsockopt to clear socket error */
int socket_error;
socklen_t err_size = sizeof(socket_error);
(void)getsockopt(socket, SOL_SOCKET, SO_ERROR,
&socket_error, &err_size);
errno = EINPROGRESS;
}
return ret;
}
static struct {
int fd;
struct in_addr holdaddr;
} holdbind[40];
#define HOLDBINDLAST ((sizeof(holdbind))/(sizeof(holdbind[0])))
static int nextbind;
/*
* Fix peculiarities of bind() on MPE
* 1. call GETPRIVMODE to bind to ports < 1024
* 2. save IP address for future calls to getsockname
* 3. set IP address to 0 (INADDR_ANY)
*/
int
mpe_bind(int socket, const struct sockaddr *address, socklen_t address_len)
{
int i;
int result;
int mpeprivmode=0;
extern void GETPRIVMODE(void);
extern void GETUSERMODE(void);
for (i = 0; i<HOLDBINDLAST; i++) {
if (holdbind[i].fd == socket)
break;
}
/* If we didn't find previously used slot, use next */
if (i == HOLDBINDLAST)
i = nextbind;
holdbind[i].fd = socket;
memset(&holdbind[i].holdaddr, '\0', sizeof(holdbind[i].holdaddr));
if (address->sa_family == AF_INET
&& address_len >= offsetof(struct sockaddr_in, sin_addr)
+sizeof(struct in_addr)) {
holdbind[i].holdaddr = ((struct sockaddr_in *)address)->sin_addr;
}
if (i == nextbind)
{
if (++nextbind >= HOLDBINDLAST)
nextbind = 0;
}
if (address->sa_family == AF_INET)
{
/* The address *MUST* stupidly be zero. */
((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_ANY;
/* PRIV mode is required to bind() to ports < 1024. */
if (((struct sockaddr_in *)address)->sin_port < 1024 &&
((struct sockaddr_in *)address)->sin_port > 0) {
GETPRIVMODE(); /* If this fails, we are aborted by MPE/iX. */
mpeprivmode = 1;
}
}
result = bind(socket, address, address_len);
if (mpeprivmode)
{
GETUSERMODE();
}
return result;
}
int
mpe_getsockname(int socket, struct sockaddr *address, socklen_t *address_len)
{
int ret;
ret = getsockname(socket, address, address_len);
if (ret == 0
&& address->sa_family == AF_INET
&& *address_len >= offsetof(struct sockaddr_in, sin_addr)
+sizeof(struct in_addr)
&& ((struct sockaddr_in *)address)->sin_addr.s_addr == INADDR_ANY) {
int i;
for (i=0; i<HOLDBINDLAST; i++) {
if (holdbind[i].fd == socket)
{
((struct sockaddr_in *)address)->sin_addr.s_addr
= holdbind[i].holdaddr.s_addr;
break;
}
}
}
return ret;
}
int
mpe_getpeername(int socket, struct sockaddr *address, socklen_t *address_len)
{
int ret;
ret = getpeername(socket, address, address_len);
if (ret == 0)
{
/* Try a zero-length write to see if socket really connected */
int written = write(socket, "", 0);
if (written < 0)
ret = -1;
}
return ret;
}
static int
max_io_size(int filedes)
{
int save_errno;
struct sockaddr sa;
int len;
int result = INT_MAX; /* all other files */
save_errno = errno;
len = sizeof sa;
if (getsockname(filedes, &sa, &len) == -1)
{
if (errno == EAFNOSUPPORT) /* AF_UNIX socket */
result = 4096;
errno = save_errno;
} else {
result = 30000; /* AF_INET sock max */
}
return result;
}
--- NEW FILE: mpeix_setjmp.c ---
/* Workaround for CR JAGab60546 setjmp/longjmp and
JAGad55982 sigsetjmp/siglongjmp from shared libraries. */
/*
* tabstop=4
*
* _setjmp/setjmp/sigsetjmp and
*_longjmp/longjmp/siglongjmp.
*
* Written by Mark Klein, 10 October, 2000
* Updated for gcc 3.x 6 October, 2005
*
* These routines are GCC specific and MUST BE COMPILED
* WITH -O2
*
* The existing setjmp/longjmp code in both libc.a and XL.PUB.SYS
* are not SR4 aware and cause problems when working with shared
* libraries (XLs), especially when executing a longjmp between
* XLs. This code preserves SR4 and will successfully handle
* a cross space longjmp. However, the setjmp code must be
* bound into each XL from which it will be called as well as
* being bound into the main program.
*/
/*
* The following macro takes the contents of the jmpbuf and
* restores the registers from them. There is other code
* elsewhere that ensures that __jmpbuf is %r26 at this
* point in time. If it becomes some other register, that
* register must be the last restored. At the end will
* be a branch external that will cause a cross space
* return if needed.
*/
#define RESTORE_REGS_AND_RETURN(__jmpbuf, __retval) \
({ \
__asm__ __volatile__ ( \
" ldw 0(%%sr0, %0), %%rp\n" \
"\t ldw 4(%%sr0, %0), %%sp\n" \
"\t ldw 16(%%sr0, %0), %%r3\n" \
"\t ldw 20(%%sr0, %0), %%r4\n" \
"\t ldw 24(%%sr0, %0), %%r5\n" \
"\t ldw 28(%%sr0, %0), %%r6\n" \
"\t ldw 32(%%sr0, %0), %%r7\n" \
"\t ldw 36(%%sr0, %0), %%r8\n" \
"\t ldw 40(%%sr0, %0), %%r9\n" \
"\t ldw 44(%%sr0, %0), %%r10\n" \
"\t ldw 48(%%sr0, %0), %%r11\n" \
"\t ldw 52(%%sr0, %0), %%r12\n" \
"\t ldw 56(%%sr0, %0), %%r13\n" \
"\t ldw 60(%%sr0, %0), %%r14\n" \
"\t ldw 64(%%sr0, %0), %%r15\n" \
"\t ldw 68(%%sr0, %0), %%r16\n" \
"\t ldw 72(%%sr0, %0), %%r17\n" \
"\t ldw 76(%%sr0, %0), %%r18\n" \
"\t ldw 80(%%sr0, %0), %%r19\n" \
"\t ldw 84(%%sr0, %0), %%r20\n" \
"\t ldw 88(%%sr0, %0), %%r21\n" \
"\t ldw 92(%%sr0, %0), %%r22\n" \
"\t ldw 96(%%sr0, %0), %%r23\n" \
"\t ldw 100(%%sr0, %0), %%r24\n" \
"\t ldw 104(%%sr0, %0), %%r25\n" \
"\t ldw 112(%%sr0, %0), %%r27\n" \
"\t ldw 116(%%sr0, %0), %%r1\n" \
"\t mtsp %%r1, %%sr3\n" \
"\t ldw 120(%%sr0, %0), %%r1\n" \
"\t mtsp %%r1, %%sr1\n" \
"\t or,<> %%r0, %1, %%r0\n" \
"\t ldi 1, %%r28\n" \
"\t ldw 108(%%sr0, %0), %%r26\n" \
"\t be 0(%%sr1, %%rp)\n" \
"\t mtsp %%r1, %%sr4\n" \
: \
: "r" (__jmpbuf), \
"r" (__retval)); \
})
/*
* The following macro extracts the signal mask
* from __jmpbuf from the 3rd and 4th words and
* if non-zero, calls sigprocmask with that value
* to set the signal mask. This macro is usually
* invoked before the registers are restored in
* the longjmp routines and it can clobber things
* without needing to spill them as a result.
* A quick frame is built before making the
* call and cut back just afterwards.
* The ldi 2, %r26 is actually SIG_SETMASK from
* /usr/include/signal.h.
*/
#define RESTORE_SIGNAL_MASK(__jmpbuf) \
({ \
__asm__ __volatile__ ( \
" ldw 8(%0), %%r26\n" \
"\t comibt,=,n 0,%%r26,.+36\n" \
"\t ldo 64(%%sp), %%sp\n" \
"\t stw %0, -28(%%sp)\n" \
"\t ldi 0, %%r24\n" \
"\t ldo 8(%0), %%r25\n" \
"\t .import sigprocmask,code\n" \
"\t bl sigprocmask,%%rp\n" \
"\t ldi 2, %%r26\n" \
"\t ldw -28(%%sr0, %%sp), %0\n" \
"\t ldo -64(%%sp), %%sp\n" \
: \
: "r" (__jmpbuf)); \
})
/*
* This macro saves the current contents of the
* registers to __jmpbuf. Note that __jmpbuf is
* guaranteed elsewhere to be in %r26. We do not
* want it spilled, nor do we want a new frame
* built.
*/
#define SAVE_REGS(__jmpbuf) \
({ \
__asm__ __volatile__ ( \
" stw %%rp, 0(%%sr0, %0)\n" \
"\t stw %%sp, 4(%%sr0, %0)\n" \
"\t stw %%r0, 8(%%sr0, %0)\n" \
"\t stw %%r3, 16(%%sr0, %0)\n" \
"\t stw %%r4, 20(%%sr0, %0)\n" \
"\t stw %%r5, 24(%%sr0, %0)\n" \
"\t stw %%r6, 28(%%sr0, %0)\n" \
"\t stw %%r7, 32(%%sr0, %0)\n" \
"\t stw %%r8, 36(%%sr0, %0)\n" \
"\t stw %%r9, 40(%%sr0, %0)\n" \
"\t stw %%r10, 44(%%sr0, %0)\n" \
"\t stw %%r11, 48(%%sr0, %0)\n" \
"\t stw %%r12, 52(%%sr0, %0)\n" \
"\t stw %%r13, 56(%%sr0, %0)\n" \
"\t stw %%r14, 60(%%sr0, %0)\n" \
"\t stw %%r15, 64(%%sr0, %0)\n" \
"\t stw %%r16, 68(%%sr0, %0)\n" \
"\t stw %%r17, 72(%%sr0, %0)\n" \
"\t stw %%r18, 76(%%sr0, %0)\n" \
"\t stw %%r19, 80(%%sr0, %0)\n" \
"\t stw %%r20, 84(%%sr0, %0)\n" \
"\t stw %%r21, 88(%%sr0, %0)\n" \
"\t stw %%r22, 92(%%sr0, %0)\n" \
"\t stw %%r23, 96(%%sr0, %0)\n" \
"\t stw %%r24, 100(%%sr0, %0)\n" \
"\t stw %%r25, 104(%%sr0, %0)\n" \
"\t stw %%r26, 108(%%sr0, %0)\n" \
"\t stw %%r27, 112(%%sr0, %0)\n" \
"\t mfsp %%sr3, %%r1\n" \
"\t stw %%r1, 116(%%sr0, %0)\n" \
"\t mfsp %%sr4, %%r1\n" \
"\t stw %%r1, 120(%%sr0, %0)\n" \
: \
: "r" (__jmpbuf)); \
})
/*
* This macro will save the signal mask to the
* __jmpbuf if __savemask is non-zero. By this
* point in time, the other resisters have been
* saved into the __jmpbuf.
* The ldi 0, %r26 is actually SIG_BLOCK from
* /usr/include/signal.h. Since the block is
* an OR of the bits, this does not change the
* mask, but returns it into the double word at
* the address in %r24.
*/
#define SAVE_SIGNAL_MASK(__jmpbuf,__savemask) \
({ \
__asm__ __volatile__ ( \
" comibt,=,n 0,%1,.+36\n" \
"\t stw %%rp, -20(%%sr0, %%sp)\n" \
"\t ldo 64(%%sp), %%sp\n" \
"\t ldo 8(%0), %%r24\n" \
"\t ldi 0, %%r25\n" \
"\t .import sigprocmask,code\n" \
"\t bl sigprocmask,%%rp\n" \
"\t ldi 0, %%r26\n" \
"\t ldo -64(%%sp), %%sp\n" \
"\t ldw -20(%%sr0, %%sp), %%rp\n" \
: \
: "r" (__jmpbuf), \
"r" (__savemask)); \
})
/*
* Construct a jump buffer and unconditionally save
* the signal mask. Return a 0 unconditinoally.
* Care is taken here and in the macros to assume
* the __jumpbuf is in %r26 and that the return
* value will be in %r28. It is done this way to
* prevent a frame from being built and any registers
* from being spilled.
*/
int setjmp(register void *jmpbuf)
{
register int __jmpbuf asm ("%r26");
SAVE_REGS(__jmpbuf);
SAVE_SIGNAL_MASK(__jmpbuf, 1);
return 0;
}
/*
* Construct a jump buffer but do not save the
* signal mask.
*/
int _setjmp(register void *jmpbuf)
{
register int __jmpbuf asm ("%r26");
SAVE_REGS(__jmpbuf);
return 0;
}
/*
* Construct a jump buffer and conditionally save
* the signal mask. The mask is saved if the
* savemask parameter is non-zero.
*/
int sigsetjmp(register void *jmpbuf, register int savemask)
{
register int __jmpbuf asm ("%r26");
register int __savemask asm ("%r25");
SAVE_REGS(__jmpbuf);
SAVE_SIGNAL_MASK(__jmpbuf, __savemask);
return 0;
}
/*
* Return to the location established in the jmpbuf,
* and place the value in i2 in %r28. Registers
* %r4 and %r5 are co-opted to save the address and
* value of jmpbuf and the return value. The signal
* mask is re-established if needed, then the
* address of jmpbuf and value of retval are placed
* into %r26 and %r28 correspondingly. This routine
* will never return to its caller and the stack
* will be cut back to whatever exists in the jmpbuf.
*/
void longjmp(register void *jmpbuf, register int i2)
{
register int __jmpbuf asm ("%r26");
register int __retval asm ("%r28");
__asm__ __volatile__ (
" copy %0, %%r4\n"
"\t copy %1, %%r5\n"
:
: "r" (jmpbuf),
"r" (i2));
RESTORE_SIGNAL_MASK (__jmpbuf);
__asm__ __volatile__ (
" copy %%r4, %0\n"
"\t copy %%r5, %1\n"
: "=r" (__jmpbuf),
"=r" (__retval));
RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}
/*
* Return to the location established in the jmpbuf,
* but do not restore the signal mask.
*/
void _longjmp(register void *jmpbuf, register int i2)
{
register int __retval asm ("%r28");
register int __jmpbuf asm ("%r26");
__jmpbuf = (int)jmpbuf;
__retval = i2;
RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}
/*
* Return to the location establsihed in the jmpbuf,
* and conditionally re-establish the signal mask.
*/
void siglongjmp(register void *jmpbuf, register int i2)
{
register int __jmpbuf asm ("%r26");
register int __retval asm ("%r28");
__asm__ __volatile__ (
" copy %0, %%r4\n"
"\t copy %1, %%r5\n"
:
: "r" (jmpbuf),
"r" (i2));
RESTORE_SIGNAL_MASK (__jmpbuf);
__asm__ __volatile__ (
" copy %%r4, %0\n"
"\t copy %%r5, %1\n"
: "=r" (__jmpbuf),
"=r" (__retval));
RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}
#ifdef TEST
int buf1[50];
int buf2[50];
foo() {
printf("In routine foo(). Doing Longjmp.\n");
longjmp(buf1, 123);
printf("This is in foo after the longjmp() call. Should not reach here.\n");
}
bar(int ret) {
printf("In routine bar(%d). Doing siglongjmp.\n",ret);
siglongjmp(buf2, ret);
printf("This is in bar after the siglongjmp() call. Should not reach here.\n");
}
main() {
int i;
if ((i = setjmp(buf1)))
{
printf("This is the return from the longjmp. i: %d\n",i);
}
else
{
printf("Jump buffer established, i: %d. Calling foo()\n",i);
foo();
printf("This is in main after the foo() call. Should not reach here.\n ");
}
if ((i = sigsetjmp(buf2,0)))
{
printf("This is the return from the longjmp. i: %d\n",i);
}
else
{
printf("Jump buffer established, i: %d. Calling bar(456)\n",i);
bar(456);
printf("This is in main after the bar(456) call. Should not reach here.\n");
}
if ((i = sigsetjmp(buf2,1)))
{
printf("This is the return from the longjmp. i: %d\n",i);
}
else
{
printf("Jump buffer established, i: %d. Calling bar(789)\n",i);
bar(789);
printf("This is in main after the bar(789) call. Should not reach here.\n");
}
}
#endif
--- NEW FILE: nm ---
#!/bin/sh
# MPE doesn't have a native nm, and the gcc nm isn't quite fully functional.
#
# If Perl Configure is calling us, then use the native linker to extract the
# symbol table and reformat it into something nm-like.
#
# Else it must be gcc calling us during the final link phase, so call gcc nm.
if [ "$1" != "-configperl" ]; then
# Oops, the caller must be expecting gcc nm. Give it to them.
/usr/local/bin/nm $@
exit $?
fi
case $2 in
*.a) LIST="LISTRL RL=$2;DATA;ENTRYSYM" ;;
*.sl) LIST="LISTXL XL=$2;DATA;ENTRYSYM" ;;
*) exit 0 ;;
esac
# I wanted to pipe this into awk, but it fell victim to a known pipe/streams
# bug on my multiprocessor machine.
callci xeq linkedit.pub.sys \"$LIST\" >nm.$$
/bin/awk '\
/ data univ / { printf "%-20s|%10s|%-6s|%-7s|%s\n",$1,$5,"extern","data","?"} \
/ entry univ / { printf "%-20s|%10s|%-6s|%-7s|%s\n",$1,$7,"extern","entry","?"}' nm.$$
rm -f nm.$$
exit 0
--- NEW FILE: mpeixish.h ---
/*
* The following symbols are defined if your operating system supports
* functions by that name. All Unixes I know of support them, thus they
* are not checked by the configuration script, but are directly defined
* here.
*/
/* HAS_IOCTL:
* This symbol, if defined, indicates that the ioctl() routine is
* available to set I/O characteristics
*/
#define HAS_IOCTL /**/
/* HAS_UTIME:
* This symbol, if defined, indicates that the routine utime() is
* available to update the access and modification times of files.
*/
#define HAS_UTIME /**/
/* HAS_GROUP
* This symbol, if defined, indicates that the getgrnam() and
* getgrgid() routines are available to get group entries.
*/
#define HAS_GROUP /**/
/* HAS_PASSWD
* This symbol, if defined, indicates that the getpwnam() and
* getpwuid() routines are available to get password entries.
*/
#define HAS_PASSWD /**/
#define HAS_KILL
#define HAS_WAIT
/* USEMYBINMODE
* This symbol, if defined, indicates that the program should
* use the routine my_binmode(FILE *fp, char iotype, int mode) to insure
* that a file is in "binary" mode -- that is, that no translation
* of bytes occurs on read or write operations.
*/
#undef USEMYBINMODE
/* Stat_t:
* This symbol holds the type used to declare buffers for information
* returned by stat(). It's usually just struct stat. It may be necessary
* to include <sys/stat.h> and <sys/types.h> to get any typedef'ed
* information.
*/
#define Stat_t struct stat
/* USE_STAT_RDEV:
* This symbol is defined if this system has a stat structure declaring
* st_rdev
*/
#define USE_STAT_RDEV /**/
/* ACME_MESS:
* This symbol, if defined, indicates that error messages should be
* should be generated in a format that allows the use of the Acme
* GUI/editor's autofind feature.
*/
#undef ACME_MESS /**/
/* UNLINK_ALL_VERSIONS:
* This symbol, if defined, indicates that the program should arrange
* to remove all versions of a file if unlink() is called. This is
* probably only relevant for VMS.
*/
/* #define UNLINK_ALL_VERSIONS / **/
/* VMS:
* This symbol, if defined, indicates that the program is running under
* VMS. It is currently automatically set by cpps running under VMS,
* and is included here for completeness only.
*/
/* #define VMS / **/
/* ALTERNATE_SHEBANG:
* This symbol, if defined, contains a "magic" string which may be used
* as the first line of a Perl program designed to be executed directly
* by name, instead of the standard Unix #!. If ALTERNATE_SHEBANG
* begins with a character other then #, then Perl will only treat
* it as a command line if if finds the string "perl" in the first
* word; otherwise it's treated as the first line of code in the script.
* (IOW, Perl won't hand off to another interpreter via an alternate
* shebang sequence that might be legal Perl code.)
*/
/* #define ALTERNATE_SHEBANG "#!" / **/
#include <signal.h>
#ifndef SIGABRT
# define SIGABRT SIGILL
#endif
#ifndef SIGILL
# define SIGILL 6 /* blech */
#endif
#define ABORT() kill(PerlProc_getpid(),SIGABRT);
/*
* fwrite1() should be a routine with the same calling sequence as fwrite(),
* but which outputs all of the bytes requested as a single stream (unlike
* fwrite() itself, which on some systems outputs several distinct records
* if the number_of_items parameter is >1).
*/
#define fwrite1 fwrite
#define Stat(fname,bufptr) stat((fname),(bufptr))
#define Fstat(fd,bufptr) fstat((fd),(bufptr))
#define Fflush(fp) fflush(fp)
#define Mkdir(path,mode) mkdir((path),(mode))
#ifndef PERL_SYS_INIT
# define PERL_SYS_INIT(c,v) PERL_FPU_INIT MALLOC_INIT
#endif
#ifndef PERL_SYS_TERM
#define PERL_SYS_TERM() MALLOC_TERM
#endif
#define BIT_BUCKET "/dev/null"
#define dXSUB_SYS
/* pw_passwd, pw_gecos, pw_age, pw_comment exist in the struct passwd
* but they contain uninitialized (as in "accessing them will crash perl")
* pointers. Stay away from them. */
#undef PWGECOS
#undef PRPASSWD
#undef PWAGE
#undef PWCOMMENT
/* various missing external function declarations */
#include <sys/ipc.h>
extern key_t ftok (char *pathname, char id);
extern char *gcvt (double value, int ndigit, char *buf);
extern int isnan (double value);
extern void srand48(long int seedval);
extern double drand48(void);
extern double erand48(unsigned short xsubi[3]);
extern long jrand48(unsigned short xsubi[3]);
extern void lcong48(unsigned short param[7]);
extern long lrand48(void);
extern long mrand48(void);
extern long nrand48(unsigned short xsubi[3]);
extern unsigned short *seed48(unsigned short seed16v[3]);
/* various missing constants -- define 'em */
#define PF_UNSPEC 0
/* declarations for wrappers in mpeix.c */
#include <time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
extern int ftruncate(int fd, long wantsize);
extern int gettimeofday( struct timeval *tp, struct timezone *tpz );
extern int truncate(const char *pathname, off_t length);
extern int mpe_read(int filedes, void *buffer, size_t len);
extern int mpe_write(int filedes, const void *buffer, size_t len);
extern int mpe_send(int socket, const void *buffer, size_t len, int flags);
extern int mpe_sendto(int socket, const void *buffer, size_t len,
int flags, const struct sockaddr *dest_addr,
size_t dest_len);
extern int mpe_recv(int socket, void *buffer, size_t length, int flags);
extern int mpe_recvfrom(int socket, void *buffer, size_t length,
int flags, struct sockaddr *address,
size_t *address_len) ;
extern int mpe_bind(int socket, const struct sockaddr *address,
size_t address_len);
extern int mpe_getsockname(int socket, struct sockaddr *address,
size_t *address_len);
extern int mpe_getpeername(int socket, struct sockaddr *address,
size_t *address_len);
/* Replacements to fix various socket problems -- see mpeix.c */
#define fcntl mpe_fcntl
#define read mpe_read
#define write mpe_write
#define send mpe_send
#define sendto mpe_sendto
#define recv mpe_recv
#define recvfrom mpe_recvfrom
#define bind mpe_bind
#define getsockname mpe_getsockname
#define getpeername mpe_getpeername
More information about the dslinux-commit
mailing list