Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site poseidon.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxt!houxm!ihnp4!poseidon!sherm From: sherm@poseidon.UUCP (Paul A. Sherman) Newsgroups: net.lang.c,net.unix-wizards Subject: Re: (3b2) functions in data space Message-ID: <1434@poseidon.UUCP> Date: Thu, 27-Mar-86 17:15:21 EST Article-I.D.: poseidon.1434 Posted: Thu Mar 27 17:15:21 1986 Date-Received: Sun, 30-Mar-86 02:35:38 EST References: <728@petsd.UUCP> <1486@devwrl.DEC.COM> <622@bentley.UUCP> <802@ttrdc.UUCP> <803@ttrdc.UUCP> <804@ttrdc.UUCP> Reply-To: sherm@poseidon.UUCP (60545456-Paul A. Sherman;LZ 3C-319;6316) Organization: AT&T Information Systems, Lincroft NJ Lines: 183 Xref: watmath net.lang.c:8305 net.unix-wizards:17382 Summary: 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 # include # include # include # include 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 /\/d /\/d /\/d g/|/s// = / g/|.*$/s//;/ /\/ 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