(3b2) functions in data space

Paul A. Sherman sherm at poseidon.UUCP
Fri Mar 28 08:15:21 AEST 1986


While I can't bring back the original article on this subject (it seems
to have been expired) I can shed a little more light on the subject of
executing code out of data space on the 3B2/300 and the 3B5.  The way
memory management is set up a memory region can be either READ/WRITE or
READ/EXECUTE but not READ/WRITE/EXECUTE.  There is a way around the
problem, however, by dual mapping a region.  You can use the sys3b(2)
call with first argument "S3BDMM" to get a dual mapped region.  The
returned value will point to a different memory map to an executable
segment that is actually at the same location as your writable segment.
You can compute the offset between the two representations and then
call a funtion in the executable segment.

See sys3b(2) in the programmers manual for more details.
I haven't tried the same program on a 3b2/400.  Perhaps the MMU has
been changed so these machinations are no longer necessary.

The following is a detailed example of how to execute code from data
space.  Read no further if you don't want some nitty-gritty stuff.
Although this example shows execution from the stack, the same arguments
apply for execution out of other data space.

The algorithm in the manual page for computing the origin of the 
read/write data segment doesn't seem to work properly for either 
machine, however.  The start of the data segment seems to be 
0x80880000, so I have used this as an absolute value.  

If you wish an executable that is read into data space to use subroutines
already compiled into the main program, you must link edit the executable
with knowledge of the symbol locations in the main program and you must
know at what address it is going to be loaded.  This allows proper symbol
relocation.  The file dmm.stb is an example of a loader directive file
used to link edit the test program q.c.  Since printf() is the only external
routine that q() must get from main(), it is the only symbol that appears.

The loader directive file can be produced by first getting a namelist of
the main program (with "nm -ex dmmtest> dmm.stb") and then editing the output
with the editor script "ex.script" (use "ex - dmm.stb < ex.script").
The script will produce addresses for all external variables.  It can
be manually edited to leave only the necessary ones.  It is in the proper
format to be used as a link editor directive file.  This script uses the
address of the variable "buf" for the location that q() will be linked at.
This should be changed as appropriate.

To generate a dynamically loadable routine "q.out" you first compile
q.o with "cc -c q.c".  Then link edit with "ld -o q.out q.o dmm.stb

The main program must be linked with the "ld" library to get the
object file access routines (use "cc dmmtest.c -lld -o dmmtest").  The
magic number 44 in the program is the size of the output module q.o.

--------------------------

/*	dmmtest.c	
 *		Test dual mapped memory feature
 *		Compile with "cc dmmtest.c -lld -o dmmtest"
 *		Paul Sherman (poseidon!sherm)
 */

# include	<stdio.h>
# include	<filehdr.h>
# include	<ldfcn.h>
# include	<sys/sys3b.h>
# include	<sys/param.h>
main()
{
	printf("In main before P\n");
	P();
	printf("In main after P\n");
}
# define 	QSIZE	44	/* Size of output module	*/
	char buf[QSIZE];
P()
{
	LDFILE	*f;
	int	bytes;
	extern	int	etext;
	long	rw_data, re_data;
	long	offset;
	int	(*callq)();

	/*	compute R/W data origin	*/
	/*	fake with known magic number	*/
	rw_data = 0x80880000;

	/*	attach R/E segment and get origin	*/
	re_data = sys3b(S3BDMM, 1);

	/*	compute offset	*/
	offset = re_data - rw_data;

	/*	calculate "virtual" address of executable routine	*/

	callq = (int (*)()) (buf + offset);
	
	printf("In P before Q\n");

	/*	read routine Q into buf	*/

	f = ldopen("q.out", NULL);
	ldnsseek(f, "outsec");
	fread(buf, 1, QSIZE, IOPTR(f));
	ldclose(f);

	/*	now jump to data space	*/

	(*callq)();

	/*	hopefully we returned back here	*/

	printf ("In P after Q\n");
}

-----------------------------

/*	File q.c
 *		Compile separately and read into data space of main routine
 *		Build q.o with "cc -c q.c"
 *		Then link edit with "ld -o q.out q.o dmm.stb
 *		Create dmm.stb from nm output of dmmtest and ex.script
 */

q()
{
	printf("I'm in Q now\n");
}

-----------------------------
# Ex script to take namelist output and massage it into a loader
# directive file for dynamic linking.

se ws
1,6d
g/static/d
/\<etext\>/d
/\<edata\>/d
/\<end\>/d
g/|/s// = /
g/|.*$/s//;/
/\<buf\>/
yank a
$
s/;/&\
\
SECTIONS {\
	outsec /
put a
s/^.*=//
.-1,.j
s/;/: {q.o}\
}/
wq


-----------------------------
# dmm.stb
#
# Loader directive file for building q.out
#

printf	=	0x80800774;

SECTIONS	{
	outsec	0x80880ae8:	{q.o}
}



-----------------------------

Sample output from successful run of dmmtest:


In main before P
In P before Q
I'm in Q now
In P after Q
In main after P
-- 

			Paul Sherman
			AT&T Information Systems, Lincroft, NJ
			{pegasus!phoenix}!poseidon!sherm
			(201) 576-6316



More information about the Comp.unix.wizards mailing list