From: Ray.Nickson@comp.vuw.ac.nz (Ray Nickson)
Subject: Dynamic loading under MORE/bsd
Organization: Victoria University of Wellington, Wellington, New Zealand
Distribution: comp
Date: Thu, 9 Apr 1992 01:57:29 GMT

I am experiencing problems loading and calling dynamic code on HP 9000
series 300 and 400 systems using Mt Xinu's MORE/bsd.  (Does anyone
know of an active mailing list for discussing that OS?).

The following program (excuse the lack of error checking, please!)
takes two arguments; the first is the name of an object file, and the
second the external name of an entry function (assumed to take no
arguments and return int) in that object file.  The program invokes
the system loader to create an `ext.o' file using its own symbol table
and augmenting it with the named object file.  It then opens ext.o,
gets the text size and entry point from the header, then allocates
memory and reads the text into that memory.  Finally, it calls the
entry function.

The program typically crashes with a bus error or illegal instruction
inside the dynamically loaded function; examining the core dump shows
that it crashes with the program counter pointing to the middle of an
instruction (e.g. if a four-byte instruction starts at address X, the
PC might be pointing at X+2).

If I insert a delay immediately prior to calling the function (i.e.
-DHACKIT when compiling the source below), the program appears to work
correctly.  If I move the delay two lines up to before the fread(),
the same incorrect behaviour is experienced.  This suggests to me some
sort of race between reading the text in and having it available for
execution; I cannot imagine what.  The debugger isn't much help, since
by the time I get to see the offending code, it isn't offensive any
more!

I include both the loader program (tryld.c) and a sample c file
(try.c) to dynamically load below.  The following script demonstrates
the incorrect and correct bahaviour.  If anyone can reproduce the
behaviour or suggest what causes it, I'd love to hear about it.

$ gcc -c try.c
$ gcc -o tryld tryld.c
$ ./tryld try.o _try
Bus error (core dumped)
$ gcc -DHACKIT -o tryld tryld.c
$ ./tryld try.o _try
called try!
got 11



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  tryld.c try.c
# Wrapped by nickson@turakirae.comp.vuw.ac.nz on Thu Apr  9 13:48:41 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'tryld.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tryld.c'\"
else
echo shar: Extracting \"'tryld.c'\" \(752 characters\)
sed "s/^X//" >'tryld.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <a.out.h>
X
Xextern char *sbrk(int);
X
Xint 
Xmain (int argc, char *argv[])
X{
X  char *codeptr = sbrk (0), *cp = codeptr;
X  char cmd[1024];
X  FILE *op;
X  struct exec header;
X  int size;
X  int (*funcp)();
X  
X  printf ("loading %s with entry %s at 0x%lx\n", 
X          argv[1], argv[2], (long)codeptr);
X  
X  sprintf (cmd, "ld -N -A %s -e %s -T %lx -o ext.o %s", 
X           argv[0], argv[2], codeptr, argv[1]);
X  system (cmd);
X
X  op = fopen ("ext.o", "r");
X  fread (&header, sizeof(header), 1, op);
X  size = header.a_text;
X  funcp = (int(*)())(header.a_entry);
X  
X  sbrk (size);
X  fseek (op, N_TXTOFF(header), 0);
X  fread (codeptr, size, 1, op);
X  fclose (op);
X#ifdef HACKIT
X  sleep (1);
X#endif
X  printf ("got %d\n", (*funcp)());
X}
END_OF_FILE
if test 752 -ne `wc -c <'tryld.c'`; then
    echo shar: \"'tryld.c'\" unpacked with wrong size!
fi
# end of 'tryld.c'
fi
if test -f 'try.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'try.c'\"
else
echo shar: Extracting \"'try.c'\" \(60 characters\)
sed "s/^X//" >'try.c' <<'END_OF_FILE'
Xint
Xtry (void)
X{
X  printf ("called try!\n");
X  return 11;
X}
END_OF_FILE
if test 60 -ne `wc -c <'try.c'`; then
    echo shar: \"'try.c'\" unpacked with wrong size!
fi
# end of 'try.c'
fi
echo shar: End of shell archive.
exit 0
Newsgroups: comp.unix.programmer