os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclLoadAout.c
First public contribution.
4 * This procedure provides a version of the TclLoadFile that
5 * provides pseudo-static linking using version-7 compatible
6 * a.out files described in either sys/exec.h or sys/a.out.h.
8 * Copyright (c) 1995, by General Electric Company. All rights reserved.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * This work was supported in part by the ARPA Manufacturing Automation
14 * and Design Engineering (MADE) Initiative through ARPA contract
17 * RCS: @(#) $Id: tclLoadAout.c,v 1.14 2002/10/10 12:25:53 vincentdarley Exp $
22 #ifdef HAVE_EXEC_AOUT_H
23 # include <sys/exec_aout.h>
28 # include "../compat/unistd.h"
32 * Some systems describe the a.out header in sys/exec.h, and some in
42 #ifdef USE_SYS_EXEC_AOUT_H
43 #include <sys/exec_aout.h>
44 #define a_magic a_midmag
48 * TCL_LOADSHIM is the amount by which to shim the break when loading
52 #define TCL_LOADSHIM 0x4000L
56 * TCL_LOADALIGN must be a power of 2, and is the alignment to which
57 * to force the origin of load modules
61 #define TCL_LOADALIGN 0x4000L
65 * TCL_LOADMAX is the maximum size of a load module, and is used as
66 * a sanity check when loading
70 #define TCL_LOADMAX 2000000L
74 * Kernel calls that appear to be missing from the system .h files:
77 extern char * brk _ANSI_ARGS_((char *));
78 extern char * sbrk _ANSI_ARGS_((size_t));
81 * The static variable SymbolTableFile contains the file name where the
82 * result of the last link was stored. The file is kept because doing so
83 * allows one load module to use the symbols defined in another.
86 static char * SymbolTableFile = NULL;
89 * Type of the dictionary function that begins each load module.
92 typedef Tcl_PackageInitProc * (* DictFn) _ANSI_ARGS_ ((CONST char * symbol));
95 * Prototypes for procedures referenced only in this file:
98 static int FindLibraries _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr,
100 static void UnlinkSymbolTable _ANSI_ARGS_((void));
103 *----------------------------------------------------------------------
107 * Dynamically loads a binary code file into memory and returns
108 * a handle to the new code.
111 * A standard Tcl completion code. If an error occurs, an error
112 * message is left in the interp's result.
115 * New code suddenly appears in memory.
119 * This function does not attempt to handle the case where the
120 * BSS segment is not executable. It will therefore fail on
121 * Encore Multimax, Pyramid 90x, and similar machines. The
122 * reason is that the mprotect() kernel call, which would
123 * otherwise be employed to mark the newly-loaded text segment
124 * executable, results in a system crash on BSD/386.
126 * In an effort to make it fast, this function eschews the
127 * technique of linking the load module once, reading its header
128 * to determine its size, allocating memory for it, and linking
129 * it again. Instead, it `shims out' memory allocation by
130 * placing the module TCL_LOADSHIM bytes beyond the break,
131 * and assuming that any malloc() calls required to run the
132 * linker will not advance the break beyond that point. If
133 * the break is advanced beyonnd that point, the load will
134 * fail with an `inconsistent memory allocation' error.
135 * It perhaps ought to retry the link, but the failure has
136 * not been observed in two years of daily use of this function.
137 *----------------------------------------------------------------------
141 TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
142 Tcl_Interp *interp; /* Used for error reporting. */
143 Tcl_Obj *pathPtr; /* Name of the file containing the desired
145 Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded
146 * file which will be passed back to
147 * (*unloadProcPtr)() to unload the file. */
148 Tcl_FSUnloadFileProc **unloadProcPtr;
149 /* Filled with address of Tcl_FSUnloadFileProc
150 * function which should be used for
153 char * inputSymbolTable; /* Name of the file containing the
154 * symbol table from the last link. */
155 Tcl_DString linkCommandBuf; /* Command to do the run-time relocation
158 char relocatedFileName [L_tmpnam];
159 /* Name of the file holding the relocated */
160 /* text of the module */
161 int relocatedFd; /* File descriptor of the file holding
163 struct exec relocatedHead; /* Header of the relocated text */
164 unsigned long relocatedSize;/* Size of the relocated text */
165 char * startAddress; /* Starting address of the module */
166 int status; /* Status return from Tcl_ calls */
169 /* Find the file that contains the symbols for the run-time link. */
171 if (SymbolTableFile != NULL) {
172 inputSymbolTable = SymbolTableFile;
173 } else if (tclExecutableName == NULL) {
174 Tcl_SetResult (interp, "can't find the tclsh executable", TCL_STATIC);
177 inputSymbolTable = tclExecutableName;
180 /* Construct the `ld' command that builds the relocated module */
182 tmpnam (relocatedFileName);
183 Tcl_DStringInit (&linkCommandBuf);
184 Tcl_DStringAppend (&linkCommandBuf, "exec ld -o ", -1);
185 Tcl_DStringAppend (&linkCommandBuf, relocatedFileName, -1);
186 #if defined(__mips) || defined(mips)
187 Tcl_DStringAppend (&linkCommandBuf, " -G 0 ", -1);
189 Tcl_DStringAppend (&linkCommandBuf, " -u TclLoadDictionary_", -1);
190 TclGuessPackageName(Tcl_GetString(pathPtr), &linkCommandBuf);
191 Tcl_DStringAppend (&linkCommandBuf, " -A ", -1);
192 Tcl_DStringAppend (&linkCommandBuf, inputSymbolTable, -1);
193 Tcl_DStringAppend (&linkCommandBuf, " -N -T XXXXXXXX ", -1);
194 Tcl_DStringAppend (&linkCommandBuf, Tcl_GetString(pathPtr), -1);
195 Tcl_DStringAppend (&linkCommandBuf, " ", -1);
197 if (FindLibraries (interp, pathPtr, &linkCommandBuf) != TCL_OK) {
198 Tcl_DStringFree (&linkCommandBuf);
202 linkCommand = Tcl_DStringValue (&linkCommandBuf);
204 /* Determine the starting address, and plug it into the command */
206 startAddress = (char *) (((unsigned long) sbrk (0)
207 + TCL_LOADSHIM + TCL_LOADALIGN - 1)
208 & (- TCL_LOADALIGN));
209 p = strstr (linkCommand, "-T") + 3;
210 sprintf (p, "%08lx", (long) startAddress);
215 status = Tcl_Eval (interp, linkCommand);
216 Tcl_DStringFree (&linkCommandBuf);
221 /* Open the linker's result file and read the header */
223 relocatedFd = open (relocatedFileName, O_RDONLY);
224 if (relocatedFd < 0) {
227 status= read (relocatedFd, (char *) & relocatedHead, sizeof relocatedHead);
228 if (status < sizeof relocatedHead) {
232 /* Check the magic number */
234 if (relocatedHead.a_magic != OMAGIC) {
235 Tcl_AppendResult (interp, "bad magic number in intermediate file \"",
236 relocatedFileName, "\"", (char *) NULL);
240 /* Make sure that memory allocation is still consistent */
242 if ((unsigned long) sbrk (0) > (unsigned long) startAddress) {
243 Tcl_SetResult (interp, "can't load, memory allocation is inconsistent.",
248 /* Make sure that the relocated module's size is reasonable */
250 relocatedSize = relocatedHead.a_text + relocatedHead.a_data
251 + relocatedHead.a_bss;
252 if (relocatedSize > TCL_LOADMAX) {
253 Tcl_SetResult (interp, "module too big to load", TCL_STATIC);
257 /* Advance the break to protect the loaded module */
259 (void) brk (startAddress + relocatedSize);
262 * Seek to the start of the module's text.
264 * Note that this does not really work with large files (i.e. where
265 * lseek64 exists and is different to lseek), but anyone trying to
266 * dynamically load a binary that is larger than what can fit in
267 * addressable memory is in trouble anyway...
270 #if defined(__mips) || defined(mips)
271 status = lseek (relocatedFd,
272 (off_t) N_TXTOFF (relocatedHead.ex_f, relocatedHead.ex_o),
275 status = lseek (relocatedFd, (off_t) N_TXTOFF (relocatedHead), SEEK_SET);
281 /* Read in the module's text and data */
283 relocatedSize = relocatedHead.a_text + relocatedHead.a_data;
284 if (read (relocatedFd, startAddress, relocatedSize) < relocatedSize) {
287 Tcl_AppendResult (interp, "error on intermediate file \"",
288 relocatedFileName, "\": ", Tcl_PosixError (interp),
291 (void) unlink (relocatedFileName);
295 /* Close the intermediate file. */
297 (void) close (relocatedFd);
299 /* Arrange things so that intermediate symbol tables eventually get
302 if (SymbolTableFile != NULL) {
303 UnlinkSymbolTable ();
305 atexit (UnlinkSymbolTable);
307 SymbolTableFile = ckalloc (strlen (relocatedFileName) + 1);
308 strcpy (SymbolTableFile, relocatedFileName);
310 *loadHandle = startAddress;
315 *----------------------------------------------------------------------
319 * Looks up a symbol, by name, through a handle associated with
320 * a previously loaded piece of code (shared library).
323 * Returns a pointer to the function associated with 'symbol' if
324 * it is found. Otherwise returns NULL and may leave an error
325 * message in the interp's result.
327 *----------------------------------------------------------------------
330 TclpFindSymbol(interp, loadHandle, symbol)
332 Tcl_LoadHandle loadHandle;
335 /* Look up the entry point in the load module's dictionary. */
336 DictFn dictionary = (DictFn) loadHandle;
337 return (Tcl_PackageInitProc*) dictionary(sym1);
342 *------------------------------------------------------------------------
346 * Find the libraries needed to link a load module at run time.
349 * A standard Tcl completion code. If an error occurs,
350 * an error message is left in the interp's result. The -l and -L
351 * flags are concatenated onto the dynamic string `buf'.
353 *------------------------------------------------------------------------
357 FindLibraries (interp, pathPtr, buf)
358 Tcl_Interp * interp; /* Used for error reporting */
359 Tcl_Obj * pathPtr; /* Name of the load module */
360 Tcl_DString * buf; /* Buffer where the -l an -L flags */
362 FILE * f; /* The load module */
363 int c = 0; /* Byte from the load module */
367 char *fileName = Tcl_GetString(pathPtr);
369 /* Open the load module */
371 native = Tcl_FSGetNativePath(pathPtr);
372 f = fopen(native, "rb"); /* INTL: Native. */
375 Tcl_AppendResult (interp, "couldn't open \"", fileName, "\": ",
376 Tcl_PosixError (interp), (char *) NULL);
380 /* Search for the library list in the load module */
383 while (*p != '\0' && (c = getc (f)) != EOF) {
395 /* No library list -- this must be an ill-formed module */
398 Tcl_AppendResult (interp, "File \"", fileName,
399 "\" is not a Tcl load module.", (char *) NULL);
404 /* Accumulate the library list */
406 while ((c = getc (f)) != '\0' && c != EOF) {
408 Tcl_DStringAppend (buf, &cc, 1);
413 Tcl_AppendResult (interp, "Library directory in \"", fileName,
414 "\" ends prematurely.", (char *) NULL);
422 *------------------------------------------------------------------------
424 * UnlinkSymbolTable --
426 * Remove the symbol table file from the last dynamic link.
432 * The symbol table file from the last dynamic link is removed.
433 * This function is called when (a) a new symbol table is present
434 * because another dynamic link is complete, or (b) the process
436 *------------------------------------------------------------------------
442 (void) unlink (SymbolTableFile);
443 ckfree (SymbolTableFile);
444 SymbolTableFile = NULL;
448 *----------------------------------------------------------------------
452 * Unloads a dynamically loaded binary code file from memory.
453 * Code pointers in the formerly loaded file are no longer valid
454 * after calling this function.
460 * Does nothing. Can anything be done?
462 *----------------------------------------------------------------------
466 TclpUnloadFile(loadHandle)
467 Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call
468 * to TclpDlopen(). The loadHandle is
469 * a token that represents the loaded
475 *----------------------------------------------------------------------
477 * TclGuessPackageName --
479 * If the "load" command is invoked without providing a package
480 * name, this procedure is invoked to try to figure it out.
483 * Always returns 0 to indicate that we couldn't figure out a
484 * package name; generic code will then try to guess the package
485 * from the file name. A return value of 1 would have meant that
486 * we figured out the package name and put it in bufPtr.
491 *----------------------------------------------------------------------
495 TclGuessPackageName(fileName, bufPtr)
496 CONST char *fileName; /* Name of file containing package (already
497 * translated to local form if needed). */
498 Tcl_DString *bufPtr; /* Initialized empty dstring. Append
499 * package name to this if possible. */
504 if ((q = strrchr(fileName,'/'))) {
509 if (!strncmp(q,"lib",3)) {
513 while ((*p) && (*p != '.') && ((*p<'0') || (*p>'9'))) {
516 if ((p>q+2) && !strncmp(p-2,"_G0.",4)) {
523 Tcl_DStringAppend(bufPtr,q, p-q);
525 r = Tcl_DStringValue(bufPtr);
526 r += strlen(r) - (p-q);
529 * Capitalize the string and then recompute the length.
533 Tcl_DStringSetLength(bufPtr, strlen(Tcl_DStringValue(bufPtr)));