tclLoadAout.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:15k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclLoadAout.c --
  3.  *
  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.
  7.  *
  8.  * Copyright (c) 1995, by General Electric Company. All rights reserved.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * This work was supported in part by the ARPA Manufacturing Automation
  14.  * and Design Engineering (MADE) Initiative through ARPA contract
  15.  * F33615-94-C-4400.
  16.  *
  17.  * RCS: @(#) $Id: tclLoadAout.c,v 1.14 2002/10/10 12:25:53 vincentdarley Exp $
  18.  */
  19. #include "tclInt.h"
  20. #include <fcntl.h>
  21. #ifdef HAVE_EXEC_AOUT_H
  22. #   include <sys/exec_aout.h>
  23. #endif
  24. #ifdef HAVE_UNISTD_H
  25. #   include <unistd.h>
  26. #else
  27. #   include "../compat/unistd.h"
  28. #endif
  29. /*
  30.  * Some systems describe the a.out header in sys/exec.h, and some in
  31.  * a.out.h.
  32.  */
  33. #ifdef USE_SYS_EXEC_H
  34. #include <sys/exec.h>
  35. #endif
  36. #ifdef USE_A_OUT_H
  37. #include <a.out.h>
  38. #endif
  39. #ifdef USE_SYS_EXEC_AOUT_H
  40. #include <sys/exec_aout.h>
  41. #define a_magic a_midmag
  42. #endif
  43. /*
  44.  * TCL_LOADSHIM is the amount by which to shim the break when loading
  45.  */
  46. #ifndef TCL_LOADSHIM
  47. #define TCL_LOADSHIM 0x4000L
  48. #endif
  49. /*
  50.  * TCL_LOADALIGN must be a power of 2, and is the alignment to which
  51.  * to force the origin of load modules
  52.  */
  53. #ifndef TCL_LOADALIGN
  54. #define TCL_LOADALIGN 0x4000L
  55. #endif
  56. /*
  57.  * TCL_LOADMAX is the maximum size of a load module, and is used as
  58.  * a sanity check when loading
  59.  */
  60. #ifndef TCL_LOADMAX
  61. #define TCL_LOADMAX 2000000L
  62. #endif
  63. /*
  64.  * Kernel calls that appear to be missing from the system .h files:
  65.  */
  66. extern char * brk _ANSI_ARGS_((char *));
  67. extern char * sbrk _ANSI_ARGS_((size_t));
  68. /*
  69.  * The static variable SymbolTableFile contains the file name where the
  70.  * result of the last link was stored.  The file is kept because doing so
  71.  * allows one load module to use the symbols defined in another.
  72.  */
  73. static char * SymbolTableFile = NULL;
  74. /*
  75.  * Type of the dictionary function that begins each load module.
  76.  */
  77. typedef Tcl_PackageInitProc * (* DictFn) _ANSI_ARGS_ ((CONST char * symbol));
  78. /*
  79.  * Prototypes for procedures referenced only in this file:
  80.  */
  81. static int FindLibraries _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr,
  82.       Tcl_DString * buf));
  83. static void UnlinkSymbolTable _ANSI_ARGS_((void));
  84. /*
  85.  *----------------------------------------------------------------------
  86.  *
  87.  * TclpDlopen --
  88.  *
  89.  * Dynamically loads a binary code file into memory and returns
  90.  * a handle to the new code.
  91.  *
  92.  * Results:
  93.  * A standard Tcl completion code.  If an error occurs, an error
  94.  * message is left in the interp's result. 
  95.  *
  96.  * Side effects:
  97.  * New code suddenly appears in memory.
  98.  *
  99.  *
  100.  * Bugs:
  101.  * This function does not attempt to handle the case where the
  102.  * BSS segment is not executable.  It will therefore fail on
  103.  * Encore Multimax, Pyramid 90x, and similar machines.  The
  104.  * reason is that the mprotect() kernel call, which would
  105.  * otherwise be employed to mark the newly-loaded text segment
  106.  * executable, results in a system crash on BSD/386.
  107.  *
  108.  * In an effort to make it fast, this function eschews the
  109.  * technique of linking the load module once, reading its header
  110.  * to determine its size, allocating memory for it, and linking
  111.  * it again.  Instead, it `shims out' memory allocation by
  112.  * placing the module TCL_LOADSHIM bytes beyond the break,
  113.  * and assuming that any malloc() calls required to run the
  114.  * linker will not advance the break beyond that point.  If
  115.  * the break is advanced beyonnd that point, the load will
  116.  * fail with an `inconsistent memory allocation' error.
  117.  * It perhaps ought to retry the link, but the failure has
  118.  * not been observed in two years of daily use of this function.
  119.  *----------------------------------------------------------------------
  120.  */
  121. int
  122. TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
  123.     Tcl_Interp *interp; /* Used for error reporting. */
  124.     Tcl_Obj *pathPtr; /* Name of the file containing the desired
  125.  * code (UTF-8). */
  126.     Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded
  127.  * file which will be passed back to 
  128.  * (*unloadProcPtr)() to unload the file. */
  129.     Tcl_FSUnloadFileProc **unloadProcPtr;
  130. /* Filled with address of Tcl_FSUnloadFileProc
  131.  * function which should be used for
  132.  * this file. */
  133. {
  134.     char * inputSymbolTable; /* Name of the file containing the 
  135.  * symbol table from the last link. */
  136.     Tcl_DString linkCommandBuf; /* Command to do the run-time relocation
  137.  * of the module.*/
  138.     char * linkCommand;
  139.     char relocatedFileName [L_tmpnam];
  140. /* Name of the file holding the relocated */
  141. /* text of the module */
  142.     int relocatedFd; /* File descriptor of the file holding
  143.  * relocated text */
  144.     struct exec relocatedHead; /* Header of the relocated text */
  145.     unsigned long relocatedSize;/* Size of the relocated text */
  146.     char * startAddress; /* Starting address of the module */
  147.     int status; /* Status return from Tcl_ calls */
  148.     char * p;
  149.     /* Find the file that contains the symbols for the run-time link. */
  150.     
  151.     if (SymbolTableFile != NULL) {
  152. inputSymbolTable = SymbolTableFile;
  153.     } else if (tclExecutableName == NULL) {
  154. Tcl_SetResult (interp, "can't find the tclsh executable", TCL_STATIC);
  155. return TCL_ERROR;
  156.     } else {
  157. inputSymbolTable = tclExecutableName;
  158.     }
  159.     
  160.     /* Construct the `ld' command that builds the relocated module */
  161.     
  162.     tmpnam (relocatedFileName);
  163.     Tcl_DStringInit (&linkCommandBuf);
  164.     Tcl_DStringAppend (&linkCommandBuf, "exec ld -o ", -1);
  165.     Tcl_DStringAppend (&linkCommandBuf, relocatedFileName, -1);
  166. #if defined(__mips) || defined(mips)
  167.     Tcl_DStringAppend (&linkCommandBuf, " -G 0 ", -1);
  168. #endif
  169.     Tcl_DStringAppend (&linkCommandBuf, " -u TclLoadDictionary_", -1);
  170.     TclGuessPackageName(Tcl_GetString(pathPtr), &linkCommandBuf);
  171.     Tcl_DStringAppend (&linkCommandBuf, " -A ", -1);
  172.     Tcl_DStringAppend (&linkCommandBuf, inputSymbolTable, -1);
  173.     Tcl_DStringAppend (&linkCommandBuf, " -N -T XXXXXXXX ", -1);
  174.     Tcl_DStringAppend (&linkCommandBuf, Tcl_GetString(pathPtr), -1);
  175.     Tcl_DStringAppend (&linkCommandBuf, " ", -1);
  176.     
  177.     if (FindLibraries (interp, pathPtr, &linkCommandBuf) != TCL_OK) {
  178. Tcl_DStringFree (&linkCommandBuf);
  179. return TCL_ERROR;
  180.     }
  181.     
  182.     linkCommand = Tcl_DStringValue (&linkCommandBuf);
  183.     
  184.     /* Determine the starting address, and plug it into the command */
  185.     
  186.     startAddress = (char *) (((unsigned long) sbrk (0)
  187.       + TCL_LOADSHIM + TCL_LOADALIGN - 1)
  188.      & (- TCL_LOADALIGN));
  189.     p = strstr (linkCommand, "-T") + 3;
  190.     sprintf (p, "%08lx", (long) startAddress);
  191.     p [8] = ' ';
  192.     
  193.     /* Run the linker */
  194.     
  195.     status = Tcl_Eval (interp, linkCommand);
  196.     Tcl_DStringFree (&linkCommandBuf);
  197.     if (status != 0) {
  198. return TCL_ERROR;
  199.     }
  200.     
  201.     /* Open the linker's result file and read the header */
  202.     
  203.     relocatedFd = open (relocatedFileName, O_RDONLY);
  204.     if (relocatedFd < 0) {
  205. goto ioError;
  206.     }
  207.     status= read (relocatedFd, (char *) & relocatedHead, sizeof relocatedHead);
  208.     if (status < sizeof relocatedHead) {
  209. goto ioError;
  210.     }
  211.     
  212.     /* Check the magic number */
  213.     
  214.     if (relocatedHead.a_magic != OMAGIC) {
  215. Tcl_AppendResult (interp, "bad magic number in intermediate file "",
  216.   relocatedFileName, """, (char *) NULL);
  217. goto failure;
  218.     }
  219.     
  220.     /* Make sure that memory allocation is still consistent */
  221.     
  222.     if ((unsigned long) sbrk (0) > (unsigned long) startAddress) {
  223. Tcl_SetResult (interp, "can't load, memory allocation is inconsistent.",
  224.        TCL_STATIC);
  225. goto failure;
  226.     }
  227.     
  228.     /* Make sure that the relocated module's size is reasonable */
  229.     
  230.     relocatedSize = relocatedHead.a_text + relocatedHead.a_data
  231.       + relocatedHead.a_bss;
  232.     if (relocatedSize > TCL_LOADMAX) {
  233. Tcl_SetResult (interp, "module too big to load", TCL_STATIC);
  234. goto failure;
  235.     }
  236.     
  237.     /* Advance the break to protect the loaded module */
  238.     
  239.     (void) brk (startAddress + relocatedSize);
  240.     
  241.     /*
  242.      * Seek to the start of the module's text.
  243.      *
  244.      * Note that this does not really work with large files (i.e. where
  245.      * lseek64 exists and is different to lseek), but anyone trying to
  246.      * dynamically load a binary that is larger than what can fit in
  247.      * addressable memory is in trouble anyway...
  248.      */
  249.     
  250. #if defined(__mips) || defined(mips)
  251.     status = lseek (relocatedFd,
  252.     (off_t) N_TXTOFF (relocatedHead.ex_f, relocatedHead.ex_o),
  253.     SEEK_SET);
  254. #else
  255.     status = lseek (relocatedFd, (off_t) N_TXTOFF (relocatedHead), SEEK_SET);
  256. #endif
  257.     if (status < 0) {
  258. goto ioError;
  259.     }
  260.     
  261.     /* Read in the module's text and data */
  262.     
  263.     relocatedSize = relocatedHead.a_text + relocatedHead.a_data;
  264.     if (read (relocatedFd, startAddress, relocatedSize) < relocatedSize) {
  265. brk (startAddress);
  266.       ioError:
  267. Tcl_AppendResult (interp, "error on intermediate file "",
  268.   relocatedFileName, "": ", Tcl_PosixError (interp),
  269.   (char *) NULL);
  270.       failure:
  271. (void) unlink (relocatedFileName);
  272. return TCL_ERROR;
  273.     }
  274.     
  275.     /* Close the intermediate file. */
  276.     
  277.     (void) close (relocatedFd);
  278.     
  279.     /* Arrange things so that intermediate symbol tables eventually get
  280.     * deleted. */
  281.     
  282.     if (SymbolTableFile != NULL) {
  283. UnlinkSymbolTable ();
  284.     } else {
  285. atexit (UnlinkSymbolTable);
  286.     }
  287.     SymbolTableFile = ckalloc (strlen (relocatedFileName) + 1);
  288.     strcpy (SymbolTableFile, relocatedFileName);
  289.     
  290.     *loadHandle = startAddress;
  291.     return TCL_OK;
  292. }
  293. /*
  294.  *----------------------------------------------------------------------
  295.  *
  296.  * TclpFindSymbol --
  297.  *
  298.  * Looks up a symbol, by name, through a handle associated with
  299.  * a previously loaded piece of code (shared library).
  300.  *
  301.  * Results:
  302.  * Returns a pointer to the function associated with 'symbol' if
  303.  * it is found.  Otherwise returns NULL and may leave an error
  304.  * message in the interp's result.
  305.  *
  306.  *----------------------------------------------------------------------
  307.  */
  308. Tcl_PackageInitProc*
  309. TclpFindSymbol(interp, loadHandle, symbol) 
  310.     Tcl_Interp *interp;
  311.     Tcl_LoadHandle loadHandle;
  312.     CONST char *symbol;
  313. {
  314.     /* Look up the entry point in the load module's dictionary. */
  315.     DictFn dictionary = (DictFn) loadHandle;
  316.     return (Tcl_PackageInitProc*) dictionary(sym1);
  317. }
  318. /*
  319.  *------------------------------------------------------------------------
  320.  *
  321.  * FindLibraries --
  322.  *
  323.  * Find the libraries needed to link a load module at run time.
  324.  *
  325.  * Results:
  326.  * A standard Tcl completion code.  If an error occurs,
  327.  * an error message is left in the interp's result.  The -l and -L
  328.  * flags are concatenated onto the dynamic string `buf'.
  329.  *
  330.  *------------------------------------------------------------------------
  331.  */
  332. static int
  333. FindLibraries (interp, pathPtr, buf)
  334.     Tcl_Interp * interp; /* Used for error reporting */
  335.     Tcl_Obj * pathPtr; /* Name of the load module */
  336.     Tcl_DString * buf; /* Buffer where the -l an -L flags */
  337. {
  338.     FILE * f; /* The load module */
  339.     int c = 0; /* Byte from the load module */
  340.     char * p;
  341.     CONST char *native;
  342.     char *fileName = Tcl_GetString(pathPtr);
  343.   
  344.     /* Open the load module */
  345.     
  346.     native = Tcl_FSGetNativePath(pathPtr);
  347.     f = fopen(native, "rb"); /* INTL: Native. */
  348.     
  349.     if (f == NULL) {
  350. Tcl_AppendResult (interp, "couldn't open "", fileName, "": ",
  351.   Tcl_PosixError (interp), (char *) NULL);
  352. return TCL_ERROR;
  353.     }
  354.     
  355.     /* Search for the library list in the load module */
  356.     
  357.     p = "@LIBS: ";
  358.     while (*p != '' && (c = getc (f)) != EOF) {
  359. if (c == *p) {
  360.     ++p;
  361. }
  362. else {
  363.     p = "@LIBS: ";
  364.     if (c == *p) {
  365. ++p;
  366.     }
  367. }
  368.     }
  369.     
  370.     /* No library list -- this must be an ill-formed module */
  371.     
  372.     if (c == EOF) {
  373. Tcl_AppendResult (interp, "File "", fileName,
  374.   "" is not a Tcl load module.", (char *) NULL);
  375. (void) fclose (f);
  376. return TCL_ERROR;
  377.     }
  378.     
  379.     /* Accumulate the library list */
  380.     
  381.     while ((c = getc (f)) != '' && c != EOF) {
  382. char cc = c;
  383. Tcl_DStringAppend (buf, &cc, 1);
  384.     }
  385.     (void) fclose (f);
  386.     
  387.     if (c == EOF) {
  388. Tcl_AppendResult (interp, "Library directory in "", fileName,
  389.   "" ends prematurely.", (char *) NULL);
  390. return TCL_ERROR;
  391.     }
  392.     return TCL_OK;
  393. }
  394. /*
  395.  *------------------------------------------------------------------------
  396.  *
  397.  * UnlinkSymbolTable --
  398.  *
  399.  * Remove the symbol table file from the last dynamic link.
  400.  *
  401.  * Results:
  402.  * None.
  403.  *
  404.  * Side effects:
  405.  * The symbol table file from the last dynamic link is removed.
  406.  * This function is called when (a) a new symbol table is present
  407.  * because another dynamic link is complete, or (b) the process
  408.  * is exiting.
  409.  *------------------------------------------------------------------------
  410.  */
  411. static void
  412. UnlinkSymbolTable ()
  413. {
  414.     (void) unlink (SymbolTableFile);
  415.     ckfree (SymbolTableFile);
  416.     SymbolTableFile = NULL;
  417. }
  418. /*
  419.  *----------------------------------------------------------------------
  420.  *
  421.  * TclpUnloadFile --
  422.  *
  423.  * Unloads a dynamically loaded binary code file from memory.
  424.  * Code pointers in the formerly loaded file are no longer valid
  425.  * after calling this function.
  426.  *
  427.  * Results:
  428.  * None.
  429.  *
  430.  * Side effects:
  431.  * Does nothing.  Can anything be done?
  432.  *
  433.  *----------------------------------------------------------------------
  434.  */
  435. void
  436. TclpUnloadFile(loadHandle)
  437.     Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call
  438.  * to TclpDlopen().  The loadHandle is 
  439.  * a token that represents the loaded 
  440.  * file. */
  441. {
  442. }
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * TclGuessPackageName --
  447.  *
  448.  * If the "load" command is invoked without providing a package
  449.  * name, this procedure is invoked to try to figure it out.
  450.  *
  451.  * Results:
  452.  * Always returns 0 to indicate that we couldn't figure out a
  453.  * package name;  generic code will then try to guess the package
  454.  * from the file name.  A return value of 1 would have meant that
  455.  * we figured out the package name and put it in bufPtr.
  456.  *
  457.  * Side effects:
  458.  * None.
  459.  *
  460.  *----------------------------------------------------------------------
  461.  */
  462. int
  463. TclGuessPackageName(fileName, bufPtr)
  464.     CONST char *fileName; /* Name of file containing package (already
  465.  * translated to local form if needed). */
  466.     Tcl_DString *bufPtr; /* Initialized empty dstring.  Append
  467.  * package name to this if possible. */
  468. {
  469.     CONST char *p, *q;
  470.     char *r;
  471.     if ((q = strrchr(fileName,'/'))) {
  472. q++;
  473.     } else {
  474. q = fileName;
  475.     }
  476.     if (!strncmp(q,"lib",3)) {
  477. q+=3;
  478.     }
  479.     p = q;
  480.     while ((*p) && (*p != '.') && ((*p<'0') || (*p>'9'))) {
  481. p++;
  482.     }
  483.     if ((p>q+2) && !strncmp(p-2,"_G0.",4)) {
  484. p-=2;
  485.     }
  486.     if (p<q) {
  487. return 0;
  488.     }
  489.     Tcl_DStringAppend(bufPtr,q, p-q);
  490.     r = Tcl_DStringValue(bufPtr);
  491.     r += strlen(r) - (p-q);
  492.     /*
  493.      * Capitalize the string and then recompute the length.
  494.      */
  495.     Tcl_UtfToTitle(r);
  496.     Tcl_DStringSetLength(bufPtr, strlen(Tcl_DStringValue(bufPtr)));
  497.     return 1;
  498. }