{"id":13782872,"url":"https://github.com/till-s/cexpsh","last_synced_at":"2025-05-11T16:33:18.699Z","repository":{"id":138444495,"uuid":"49543539","full_name":"till-s/cexpsh","owner":"till-s","description":"C-expression interpreter/shell and run-time linker/loader","archived":false,"fork":false,"pushed_at":"2020-02-28T10:10:56.000Z","size":1260,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-03T18:16:56.339Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/till-s.png","metadata":{"files":{"readme":"README","changelog":"ChangeLog","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-01-13T02:26:10.000Z","updated_at":"2020-12-26T02:52:48.000Z","dependencies_parsed_at":"2024-01-07T23:08:19.144Z","dependency_job_id":"340ba476-d1d4-47c8-aa60-cd901e922258","html_url":"https://github.com/till-s/cexpsh","commit_stats":null,"previous_names":[],"tags_count":101,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/till-s%2Fcexpsh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/till-s%2Fcexpsh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/till-s%2Fcexpsh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/till-s%2Fcexpsh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/till-s","download_url":"https://codeload.github.com/till-s/cexpsh/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253595991,"owners_count":21933489,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T18:01:46.799Z","updated_at":"2025-05-11T16:33:18.313Z","avatar_url":"https://github.com/till-s.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"What is Cexp?\n-------------\n\n -- Brought to you by Till Straumann \u003cstrauman@slac.stanford.edu\u003e --\n\nThe Cexp utility is a C-expression interpreter which\ngives its user access to all symbols present in the currently\nexecuting program. Its primary target is RTEMS, an open source\nRTOS, but Cexp should compile and run on virtually any platform\nsupported by the BFD library.\n\nIf Cexp is linked to an executable, it is\npossible to invoke arbitrary functions and to\nread/write variables (and hence virtually any\nmemory location) by interpreting C-style expressions.\n\nCexp can access object files using either the pmbfd/pmelf\nlibraries ('poor-man's BFD) that comes with Cexp or libbfd.\nThe latter is more powerful:\n - not limited to the ELF object format.\n - supports many more machine types (pmbfd currently \n   only supports 32-bit powerpc, m68k, i386, x86_64\n   and sparc [32-bit] -- in decreasing order of testing\n   that has been done).\n - using BFD / libopcodes, a disassembler comes for free.\n\nOtoh, using pmbfd/pmelf has the following advantages:\n - much smaller memory footprint.\n - less restrictive license. Linking against the BFD\n   library is subject to the GPL. See LICENSING\n   below for more information.\n\nWhat is New?\n------------\n\n - for later versions, consult the ChangeLog file.\n\n - 2003/02/14: CEXP_1.2.beta (\"Valentine\") released.\n   It supports G++ prioritized execution of static\n   constructors/destructors.\n\n - 2003/02/13: CEXP_1.1.beta is released. It fixes a bug\n   of the exception handler registration.\n   \n   Makefile.syms has been added and modularized copies\n   of the RTEMS 'cdtest' sample program.\n\nDescription\n-----------\n\nCEXP is a simple utility featuring\n - symbol table\n - C expression parser/interpreter\n - type \"engine\"\n - user definable variables\n - recursive invocation/simple scripts\n - runtime 'module' loader/linker\n - disassembler (only if linked with BFD)\n - CEXP is reentrant\n\nCexp knows about the basic C types (no aggregates), i.e.\n\nchar,   char*\nshort,  short*\nlong,   long*\nfloat,  float*\ndouble, double*\nlong    (*)()\ndouble  (*)()\n\nand interprets C-style expressions, e.g.\n\n  Cexp\u003e printf(\"Hello world\")\n\n  Cexp\u003e some_variable = 0xdeadbeef\n\n  Cexp\u003e some_double_variable = *(double*)\u0026some_variable\n\n  Cexp\u003e a=printf, a \u0026\u0026 a(\"The square root of 2 is %g\\n\",sqrt(2.0))\n\nSymbol Table\n------------\nA) Using a Symbol Table File\n- - - - - - - - - - - - - - -\nOn startup, Cexp reads the 'system' symbol table either from \nthe executable itself, or from a stripped-down '.sym'\nfile - such a stripped-down symbol file can be created using\nthe 'objcopy' (preferred, but needs binutils 2.18 or later)\nor 'xsyms' (deprecated; comes with Cexp) utilities.\n\nB) Builtin Symbol Table File\n- - - - - - - - - - - - - - -\nThe 'xsyms' tool can be used to generate\na symbol table in C-source form for subsequent compilation and\nlinkage into the final executable. This usually involves linking\nthe executable twice:\n  1) compile and link all sources, libraries etc.; build an executable\n  2) xsyms -C executable  mysymtab.c\n  3) compile mysymtab.c (set -I to Cexp installation 'include' directory\n     or Cexp source directory, since \u003ccexpsyms.h\u003e is included)\n  4) link application again, but this time add 'mysymtab.c' to the\n     list of sources.\n  NOTES: Step 1) linking succeeds without a symtab.o because there's\n         a weak NULL-ptr alias for the builtin symtab.\n\t\t When building the demo program you can use a builtin symbol\n\t\t table:\n\t\t   a) build demo the normal way (corresponds to step 1 above)\n\t\t   b) type 'make builtin-symtab'\n\t\t      this extracts symbol table info from the executable\n\t\t\t  created in step a) and creates an object file\n\t\t\t  'cexp-builtin-symtab.o' (steps 2+3 above).\n\t\t   c) type 'make' again. This re-links the demo program\n\t\t      now using the 'cexp-builtin-symtab.o' object\n\t\t\t  (corresponds to step 4 above).\nA similar source file can also be generated using the 'ldep' utility\n(discussed elsewhere, it is part of RTEMS-GeSys).\n\nWithout access to a symbol table file which also provides Cexp\nwith information about the architecture it is executing on, Cexp\nmight fail to detect the correct BFD CPU architecture which is\nneeded for the disassembler. In such cases, the '-a' command\nline option can be used to specify the architecture (arch string\ncan be obtained by running 'objdump -f' on the ELF executable).\n\nSymbol Type\n- - - - - -\n\nOnce the symbol table is read, Cexp guesses the symbol/variable\ntypes from the symbol sizes. (Guess is only supported on ELF targets.)\n\nIn some cases, this guess is obviously wrong, but you can \nalways cast the symbol to the correct type.\n\nArrays are normally 'void' like every symbol for which's\ntype Cexp cannot make a guess. It is still possible, however, to\nuse such a symbol, simply by taking its address and\ncasting to a different pointer type:\n    \nCexp\u003e *(((long*)\u0026some_array)+25)\n\nevaluates to the unsigned long array element\nsome_array[25]. Alternatively, you can redeclare\nits type:\n\nCexp\u003e long *some_array !\nCexp\u003e *(some_array + 25)\n\nNote the exclamation mark: terminating a variable declaration with an\nexclamation mark allows you to redefine its type. Only new variables\nmay be declared without the '!'. This protects you from erroneously\nuse existing symbols.\n\nCexp provides a series of lookup functions\nfor symbols. Most noteworthy:\n\nlkup(char *regexp)\nlkaddr(unsigned long addr)\n\nThese are just normal C functions which can be\ninvoked by Cexp. Note that lkup() takes a regular\nexpression argument allowing for powerful searching.\n\nC-Expression Parser / Interpreter\n---------------------------------\nThe C expression parser has some restrictions:\n  - no '?' ':' expression\n  - no [], '-\u003e'\n  - the '.' operator has a special meaning - see below\n  - no multilevel pointer dereferencing (since e.g. char**\n    is not a valid type, Cexp cannot dereference \n    **addr. You must explicitly cast this:\n\n      Cexp\u003e *(char*)*(long*)some_char_pointer_pointer\n\nwhich assumes that sizeof(long) == sizeof(char*)\nfor the particular machine.\n\nHowever, most of the other operators are available, including\nthe 'comma' operator and the logical '\u0026\u0026' and '||' with the\ncorrect semantics, i.e. conditional evaluation of expression\nparts e.g.\n\n  Cexp\u003e (dd=deviceDetect(_some_device_address)) \u0026\u0026 driverInit(dd)\n\nwill call the driverInit() function only if deviceDetect()\nreturns a nonzero value.\n\nThe '.' operator (structure field access) has a special\nmeaning to Cexp: symbol \"member\" (in an OOP sense) access.\nCurrently, the only member function defined is 'help'. Consult\nthe 'Help' section about details.\n\nFunction calling:\nThe user is responsible for feeding properly typed arguments;\nunused arguments will be filled with integral/scalar 0, which on \nmost ABIs is safe.\nSince the symbol table (on ELF, Cexp is not using .stab but .symtab)\nprovides no info about a function's return type, Cexp assumes\nall functions to return long. Floating point functions\nmust be cast appropriately:\n\n  Cexp\u003e ((double(*)())sqrt)(2.345)\n\nOr\n\n  Cexp\u003e double (*sqrt)()\n  Cexp\u003e sqrt(2.345)\n\nA lot of type casting can be avoided by re-declaring or\nusing user defined variables, see below.\n\n\nType Engine\n-----------\nCexp knows about (and only about) the primitive types listed\nabove.\nNOTE: Cexp treats ALL integral types as UNSIGNED although\nno 'unsigned' keyword is used or recognized. The main\nreason for this is to save typing. Hence\nchar is in fact unsigned char etc.\n\nAn 'int' type is missing (but could easily added) which\nmeans that on some machines (e.g. 64-bit cpus) no 32bit\ntype is currently available...\n\nUser Variables\n--------------\nCexp supports (fully typed) user variables which are\nvisible in a global namespace (i.e. visible to other\ninstances of Cexp). The name of user variables must\nnot collide with symbols present in the symbol table.\n(When loading object files [AKA 'modules'], name clashes\nare ignored. A symbol in a newly loaded module that\nconflicts with an already defined user variable silently\ntakes precedence [object file symbols have a higher\npriority than user variables]. However, after unloading\nthe conflicting module, the user variable becomes again\n'visible'.)\n\nA user variable is created simply by assigning it\na value which also automatically defines its type.\n\n    hallo=\"hallo\"\n\ncreates a 'char*' and assigns it the address of a\nstring constant. The string is stored in 'malloc()ated'\nmemory and 'lives' forever. Subsequent use of the\nsame string (strcmp(a,b)==0) results in re-using the\nalready stored instance of the string.\nString constants must not be written-to!\n\nAlternatively, a user variable can be introduced\nby declaring it:\n\n   char *hallo\n\nThis method is useful if you use identifiers that\ncould already exist in the application's symbol table\n-- if this is the case then the declaration will fail\nand thus warn you.\n\nThe type of user variables can be modifed, simply\nby re-declaring them, in a C-style manner (the\nexclamation mark actually deviates from strict\nC syntax. It is required when re-declaring to\navoid accidential re-declaring of existing\nvariables):\n\n    long hallo !\n\nresults in 'hallo' maintaining its value (the address\nof the string constant) but interpreting it as a long.\nHence\n\n    chppt = \u0026hallo\n\nis an 'disguised' char** and\n\n    *(char*)*chppt\n\nyields 'h'\n\nUser variables can also hold function pointers and hence\ncan be handy abbreviations for long names and casts.\nE.g. a convenient variable can be set for 'sqrt()'\n(which returns a double value):\n\n    s=((double(*)())sqrt)\n\nIt is then possible to automatically get the correct\nreturn type:\n\n    printf(\"Let's print a double: %g\\n\",s(44.34))\n\nThe special user variable 'ans' stores the result\nof the last successfully evaluated expression. E.g:\n\n    Cexp\u003e 3+4\n\t0x00000007 (7)\n\tCexp\u003e ++ans\n\t0x00000008 (8)\n\tCexp\u003e printf(\"%u\\n\",ans)\n\t8\n\t0x00000002 (2)\n\tCexp\u003e\n\nThe 'ans' variable is special in the sense that unlike\nother user variables it is not global but local to the\nexecuting parser, i.e., parsers running in different\ntask contexts each maintain their own instances of\n'ans'.\n\nHelp Facility\n-------------\n\nThe '.' operator (structure field access) has a special\nmeaning to Cexp: symbol \"member\" (in an OOP sense) access.\nCurrently, the only member function defined is 'help'. I.e.\nby typing\n\nCexp\u003e  some_symbol.help()\n\nYou get help information about that symbol. If no help\nis defined, or if you request 'verbose' help:\n\nCexp\u003e some_symbol.help(1)\n\nthe symbol address, value and type information are printed\n(same format as the 'lkup' output).\n\nYou can add/modify help information to a symbol (e.g. a user\ndefined variable) simply by providing a string argument to\nthe symbol's help member:\n\nCexp\u003e long myvar\nCexp\u003e myvar.help(\"I just created a 'long' variable\")\n\nNote that help is stored 'per symbol', i.e. when creating\nan 'alias' as in the example above:\n\nCexp\u003e s=(double (*)())sqrt\n\nthe help information is not propagated to 's'. If 'sqrt'\nhad help information, it would have to be copied:\n\nCexp\u003e s.help(sqrt.help())\n\nThis example shows that the return value of the 'help() member'\nis the address of the (static) help text string.\n\nHow to Start/Invoke Cexp - Simple Scripts\n-----------------------------------------\nCexp has two entry points,\n\n    cexp_main(int argc, char **argv)\n\nand\n\n    cexpsh(char *arg1,...)\n\ni.e. a 'main' style and a 'vararg' style. The\n'vararg' version ends up building an argument list\nand calling cexp_main(). It is mainly intended\nfor recursively invoking 'cexpsh()' e.g. for \nreading a series of lines from a file.\nNote that the string argument list submitted to\ncexpsh() must be NULL terminated. When calling\ncexpsh() from cexpsh() (e.g. to interpret a script),\nthis is not necessary, however, because any unused\narguments (up to the internal maximum of 10 args)\nare filled with zeroes...\n\nThe calling syntax of cexp_main/cexpsh is as follows:\n\ncexpsh [-s \u003csymbolfile\u003e] [-c \u003cexpression\u003e] [-h] [-d] [-q] [\u003cscriptfile\u003e]\n\n-h and -d have the obvious effect of printing usage\ninfo and enabling debugging information (only available\nif configured with --enable-YYDEBUG).\n\nThe -q ('quiet') flag instructs Cexp not to print\nany normal output (errors are still reported to stderr)\non stdout. This behavior can be desirable when evaluating\nscripts. Note, however, that this affects only output\ngenerated by Cexp itself; output produced by functions\nwhich are called during expression evaluation is \nunaffected by the '-q' flag. Consult the section about\n'Redirection' for further information.\n\nNote that (unless you are using a built-in symbol\ntable) the -s option MUST be used the first time\n'Cexp' is started and it must be provided with an\nappropriate symbol file. This can be the executable\nitself of a stripped version (use the 'xsyms' utility)\nto reduce memory usage and loading time on RTEMS systems.\nA basic check is made to protect against version mismatch\nbetween the symbol file and the executable.\n\nOnce Cexp has loaded the system's symbol table, further\ninstances will simply use the global system table if\nthe -s argument is missing.\n\nCexp then reads commands from stdin (using the TECLA\nlibrary) or alternatively from a script file or\nfrom a string argument (-c option).\n\nCexp ignores any characters present on a line\nafter it scans the comment tokens\n'#' or '//'.\n\nExample for invoking Cexp from Cexp to evaluate\na script:\n\n  Cexp\u003e cexpsh(\"script_file\")\n\nWhile the former syntax involves recursive execution of\nCexp, it is now also possible to let the current instance\ndivert its input to read from a script using the\n'.' operator:\n\n  Cexp\u003e . script_file\n\nThere are slight syntactic differences when using this syntax,\nthough. Evaluation of the file name is not performed by\nthe parser but by a simple preprocessor. The filename doesn't have\nto be embedded in double quotes (but it can be). Note that\nno escape sequences are recognized. It is possible, however,\nto use filenames with embedded whitespace by enclosing the\nscript name in single or double quotes. In this case, the\nentire string between matching quotes is used. E.g., (RHS\nstring delimiter is '\"' -- remember that there are no escape\nsequences...):\n\n  . a b c     --\u003e read from file \"a\"\n  . 'a b' \"c\" --\u003e read from file \"a b\"\n  . \"a'b\"     --\u003e read from file \"a'b\"\n  . \"a\\\"b\"    --\u003e read from file \"a\\\\\" (a followed by a single backslash)\n\nNote that the '. infile' notation differs from 'true'\nstdin redirection (as described under 'Redirection'). The\nfunctionality described here instructs the interpreter to\nread expressions from a file. However, the 'stdin' stream\nused by any functions that are called during expression\nevaluation still is unchanged (i.e., the console).\n\nRedirection\n-----------\nThe stdio streams (and only these -- the underlying file\ndescriptors are unchanged; in a multithreaded system like\nRTEMS file descriptors are global entities anyways whereas the\nstdio streams are 'per-thread' objects so that it makes\nmore sense to redirect these rather than descriptors)\nused during expression evaluation may be redirected to\narbitrary files.\nThe syntax is similar to redirection under 'csh' but the\nredirection operators must *precede* the expression that\nis to be evaluated (this is necessary because e.g.,\n\n       printf(\"Hello\\n\") \u003e \"some_file\"\n\nwould be a valid C-expression (comparison of return\nvalue of 'printf()' with character pointer).\n\nHence, the following syntax was chosen:\n\ncexp_input_line:  [ redirectors ]   expression\n\nredirectors: inp_redir | out_redir | inp_redir out_redir | out_redir inp_redir\n\nout_redir:  ( '\u003e' | '\u003e\u003e' | '\u003e\u0026' | '\u003e\u003e\u0026' ) redirarg ':'\ninp_redir:    '\u003c'                         redirarg ':'\n\nredirarg:  \u003cstring_constant\u003e | \u003cstring_variable\u003e\n\nExamples:\n\na) Redirect output of expression 'printf(\"Hello\\n\")' to file \"hellof\"\n\n   Cexp\u003e \u003e \"hellof\" : printf(\"Hello\\n\")\n\nb) Use a string variable to store path to a file, redirect\n   stdin so that 'scanf' reads a string from the file.\n\n   #allocate a buffer\n   Cexp\u003e  buf    = malloc(1000)\n   0x00031423 (201763)\n   Cexp\u003e  mypath = \"/a/b/c/d/infile\"\n   0x00040567 (263527)\n   Cexp\u003e \u003c mypath : scanf(\"%s\",buf)\n   0x00000001 (1)\n\nc) Append first string from 'infile' to 'outfile'\n\n   Cexp\u003e \u003c mypath : \u003e\u003e \"outfile : scanf(\"%s\",buf), printf(\"%s\",buf)\n\nOutput redirection operators\n- - - - - - - - - - - - - - -\nAs in 'csh' the operators have the following semantics:\n  '\u003e'   truncate file and redirect stdout to it\n  '\u003e\u0026'  truncate file and redirect both, stdout and stderr to it\n  '\u003e\u003e'  open or create file and redirect stdout to append to the file\n  '\u003e\u003e\u0026' open or create file and redirect both, stdout and stderr\n        to append to the file\n\nNote that it is not directly possible to redirect stderr independently\nfrom stdout but the standard csh workaround can be used: Redirect\nstdout of a subshell to file 'a' and redirect stdout+stderr of\nthe parent to file 'b':\n\n   Cexp\u003e \u003e\u0026 \"errfile\" : cexpsh(\"-c\",\"\u003e \\\"outfile\\\" : \u003cquoted_expression\u003e\")\n\nNote regarding input redirection\n- - - - - - - - - - - - - - - - -\nNote that the '\u003c' operator can have two different meanings:\n\n \u003c \"filename\"\n\ninstructs the interpreter to read expressions from \"filename\"\n(this syntax is equivalent to '. \"filename\"' but DEPRECATED\n-- use '.' to 'source' scripts) whereas\n\n \u003c \"filename\" : \u003cexpression\u003e\n\nredirects 'stdin' during the evaluation of \u003cexpression\u003e\n\nLoadable Modules / Runtime Loader\n---------------------------------\n\nWhen built aginst the pmbfd or BFD library, Cexp is capable of\ndynamically loading object files into a running program.\nCexp keeps track of module dependencies. Note that this\nonly covers symbol table dependencies. Cexp rejects\nunloading a module 'A' if there is still another module,\n'B' loaded which had undefined symbols resolved against 'A's\nsymbols. Obviously, more subtle dependencies, such as\nthreads using a modules text or data cannot be tracked\neasily and are ignored.\n\nAn object file (AKA 'module') can be loaded invoking the\ncommand:\n\n  Cexp\u003e someModule=cexpModuleLoad(\"someModule.o\")\n\nThe loader returns a 'module ID', which in this example\nis stored in the user variable 'someModule'. If errors\noccur during the load (such as undefined references or\nmultiple symbol definitions), they are reported and a NULL\nmodule ID is returned.\n\nAfter loading, C++ static constructors are executed and\nexception handler frames are registered. Note that these\nfeatures are probably only supported on ELF and, especially\nthe exception handling, might only work for gcc compiled\ncode. Unfortunately, even different versions of gcc and/or\ntarget architectures involve varying implementations of\nexception handling - YMMV...\n\nAn (unused) module can be unloaded by passing its ID to\ncexpModuleUnload() (prior to unloading, the C++ static\ndestructors are executed):\n\n  Cexp\u003e cexpModuleUnload(someModule)\n\nTwo more routines are useful in this context:\n\n  cexpModuleInfo([ID])\n\nprints info about a specific module (ID) or all currently\nloaded modules if passed NULL ID.\n\n  cexpModuleFindByName(\"regexp\")\n\nsearches the list of modules for a regular expression and\nreports the IDs of all matches. It returns the first ID\nfound (or NULL if there was no match).\n\nSearch Path for Loadable Modules\n- - - - - - - - - - - - - - - - -\nIf set, the PATH environment variable is consulted\nby the loader when it tries to locate object files\nby subsequently prepending colon-separated search\npaths as listed in PATH to the file name. The search\nstarts with the first component and stops as soon\nas the file is found. An empty search path (two colons\nin a row or a leading or trailing colon) is equivalent\nto the current directory ('.'). Note that the current\ndirectory is not searched if PATH is set but does not\ncontain the CWD. PATH is ignored if the object name\ncontains a (relative or absolute) directory path already.\n\nExample: search '/tmp', '/TFTP/BOOTP_HOST/blah/bin' and\nfinally the CWD:\n\nsetenv(\"PATH\",\"/tmp:/TFTP/BOOTP_HOST/blah/bin:\",1)\n\nBuilding loadable modules\n- - - - - - - - - - - - -\nNote the important difference between a run-time loaded/linked\nobject and a _shared_ object (such as a shared library). The \nlatter, although also 'run-time loaded' is different from\nthe former. A shared object is shared among several entities\nusing disjunct address spaces (e.g. different UNIX processes).\nSupporting shared objects involves PIC and GOTs.\n\n***********************************************************\n\nCEXP does _not_ support shared libraries! An attempt to run\na loaded module that was compiled with '-fpic', '-fPIC'\nand/or linked with the '-shared' options will crash hard.\n\n***********************************************************\n\n\nTo illustrate the difference, consider a LINUX system\nrunning two instances of the 'cexp' demo. 'cexp' is linked\nagainst glibc which is a shared library - both instances\nof 'cexp' use the _same_ copy of libc residing in physical memory.\nLet's now assume the both of the demo programs issue\n\n\tcexpModuleLoad(\"someObjectFile.o\")\n\nCexp's run-time loader doesn't support shared objects - hence\nboth instances of 'cexp' will end up with their own copy of\n'someObjectFile' which will get loaded twice to physical memory.\n\nThe main target of Cexp is RTEMS, a real-time OS which has\na global address space shared by all threads. Hence, there is\nno need for shared object support but run-time loading\ncode is still very desirable.\n\nThe Cexp run-time loader simply accepts _any_ relocatable object file.\nThe simplest modules are just object files:\n\n\tcross-gcc -c -O some_object.c\n\nMultiple objects can be combined using the '-r' linker option\n\n\tcross-ld  -o some_object.o -r some1.o some2.o some3.o\n\nIt is also possible to convert entire (static) libraries into\nloadable objects:\n\n\tcross-ld  -o lib_object.o -r --whole-archive libSome.a\n\nThe 'system' symbol table is itself an object file from where\nCexp loads the initial symbol table at startup. The executable\nitself may be used for that purpose (unless it is a pure binary\nas it is the case on some embedded systems). Alternatively\n(for saving memory and time), a stripped-down object file containing\nonly the symbol table may be generated using the 'objcopy'\ntool, e.g:\n\n\tcross-objcopy --extract-symbol cexp cexp.sym\n\tcexp -s cexp.sym\n\nThis requires binutils 2.18 or later. Alternatively, the\n'xsyms' utility that comes with CEXP may be used\n\n\txsyms cexp cexp.sym\n\nbut this is deprecated.\n\nWeak Symbol Support\n- - - - - - - - - -\nCexp can handle weak symbol references (including weak\nundefined symbols). HOWEVER, this works only one-way:\nIf a module with a strong symbol is already loaded\n(or if the base system exports a strong definition)\nthen loading a module with a weak reference works as\nexpected, i.e., the references are bound to the existing\nstrong definition.\n\nOTOH, if a weak definition exists (either in the system\nsymbol table or a previosly loaded module) then it is\nNOT possible to load another module with a strong\ndefinition. (If you think about it: all relocations of\nthe already linked and loaded stuff would have to be\nredone -- including the relocations within the base\nexecutable...).\n\nWhen a module with a weak undefined reference is loaded\nthen (provided that no existing definition is found in\nthe system or other modules) a new NULL symbol is created\nwhich is otherwise treated like a newly defined COMMON\nsymbol.\n\n\nLoadable Modules 'Magic'\n- - - - - - - - - - - - -\nWhen loading modules, 'Cexp' does some magic operations on\nspecial symbols it recognizes. Note that the all-capital names\ngiven here are macros - the actual names can be found in the\nheader.\n\n\tCEXPMOD_INITIALIZER_SYM (defined in cexpmodP.h), when\n\t\tpresent in a loaded module, a routine with this\n\t\tname is invoked by cexpModuleLoad() just after calling\n\t\tC++ constructors.\n\t\tThis 'module-constructor' routine [for C++ information\n\t\tsee below] can be used to initialize a (non-C++) module.\n\n\tCEXPMOD_FINALIZER_SYM, when present in a loaded module,\n\t\ta routine with this name is invoked just prior to calling\n\t\tC++ destructors and unloading the module.\n\t\tThe FINALIZER may reject the unloading attempt by\n\t\treturning a nonzero value.\n\n\tCEXP_HELP_TAB (defined in cexpHelp.h). A module may define\n\t\t(multiple) 'help' tables (their name must begin with\n\t\tthe magic CEXP_HELP_TAB string) for providing help\n\t\tinformation about specific symbols contained in a module.\n\t\tSee cexpHelp.h for more information about the help information.\n\t\tcexpModuleLoad() automatically registers this data.\n\nBuilding the 'Main' Application\n- - - - - - - - - - - - - - - -\n\nWhen linking a traditional application, only objects referenced by the\napplication will be linked into the executable. E.g. an application which\ndoes not use 'printf()' will not have that routine available. In the\nnormal case, this is fine. When using a runtime loader like CEXP, there\narises a problem: imagine you want to load a piece of code which _does_\nuse 'printf()':\n\n  - Cexp resolves the module's undefined symbols, encounters 'printf'\n    but doesn't find it in its symbol table - it rejects loading your\n    module.\n\n  - It is not possible either to simply link your module against libc!\n    The module might reference other libc objects which _are_ present\n    in the application already - Cexp would complain that their symbols\n    are already defined.\n\nTherefore, the 'primary' or 'system' application should be built to \ninclude ALL parts of the core libraries (such as the C-library, the\nRTEMS executive managers etc.) which will possibly be used by modules\nloaded into the running system.\n\nHence, there is a new task for the system designer which (for a statically\nlinked application) would be automatically performed by the linker:\nYou must now tailor/configure the core parts of your system. This\nis essentially a memory/functionality tradeoff (Sidenote: vxWorks\nis configured in such a way, too). This 'tailoring' essentially\nmeans that you have to tell the linker what parts of the basic\nsystem libraries (RTEMS managers, CPU/BSP support, libc, networking\netc.) should forcibly be included into the link.\n\nNote that it is only necessary to take into account the libraries\nneeded by CEXP and the OS itself during this process.\nAny library CEXP does _not_ depend on, directly or indirectly, can\nof course be dynamically loaded any time later.\n\nA new tool 'ldep' is available greatly alleviating the task\nof analyzing link file interdependency and generating symbol\nlists etc. It is available as part of the 'GeSys' package\n(www.slac.stanford.edu/~strauman/rtems/gesys) and comes with\nmore documentation. Some info is available here:\nhttp://www/~strauman/rtems/epics/README.config\n\nUsing the Parser from a Program\n- - - - - - - - - - - - - - - -\n\nIn some cases, you might want to access/use symbols in loaded modules from \na program rather than through the Cexp shell or a shell script. If the\nmodule providing the 'caller' is loaded after the module defining the 'callee'\nthis is transparent. E.g., let a module 'A' define a function 'a()' and module\n'B' define a routine 'b()' which shall call 'a()'. If module 'A' was loaded\nbefore 'B' then Cexp's linker will resolve the reference and no special\ntreatment is required.\n\nIf, however, module 'B' must for some reason be loaded before 'A' then\n'B' cannot simply call 'a()' since that would result in a linker error.\n\nHere's how you can load a module from a program and use symbols exported by\nthat (or any other) module (no error checking shown):\n\nvoid (*p_a)();             /* declare function pointer to 'a()'              */\n\tcexpModuleLoad(\"A\",0); /* use file name as module name; PATH is searched */\n\n    /* lookup the symbol */\n\tp_a = cexpSymValue(cexpSymLookup(\"a\",0));\n\t/* call function     */\t\n\tif ( !p_a )\n\t\t/* error; symbol not found */\n\telse\n\t\tp_a();\n\n\nAnother method is using the interpreter (slower, of course). Since the\ninterpreter is re-entrant, this involves dragging around context information:\n\nCexpParserCtx c = cexpCreateParserCtx(0,0,0,0);\n\n\t/* these two calls could/should be wrapped into 'cexpParseLine'... */\n\tcexpResetParserCtx(c, \"a()\");\n\tcexpparse(c);\n\nNote that more documentation about these calls can be found in 'cexp.h'.\nNote also that some of the Cexp library calls require more arguments\nthan apparent from the examples in other sections of this document where\nthe shell is explained!  Most routines are geared for shell use and declare\nthe most important arguments first, followed by optional arguments and they\nuse defaults when these optional arguments are NULL. The shell implicitely\nsets extra arguments to zero so that when you type e.g.,\n\n  'cexpModuleLoad(\"file.o\")'\n\nthis effectively is expanded to 'cexpModuleLoad(\"file.o\",NULL)' since\ncexpModuleLoad() expects two parameters. OTOH, if you code\ncexpModuleLoad(\"file.o\") in a program then the compiler will warn you\nand the second argument will be undefined. Therefore, if you want to use\nlibrary calls from a program you should consult 'cexp.h' for reference.\n\nBefore you can use the Cexp library, it must be properly initialized:\n\nCEXP Liberary Initialization\n- - - - - - - - - - - - - - -\nWhen using the 'cexp_main()' AKA shell entry point, the library is initialized\nautomatically (you might still want to use cexpInit() if you intend to use your\nown signal handler...).\nIf you want to use Cexp from a program as shown in the examples above, the library\nmust be initialized before using it:\n\n\tcexpInit(0);            /* initialize internal data; use default signal handling   */\n\tcexpModuleLoad(0,0);\t/* attach built-in symbol table. If you dont have a built- */\n\t                        /* in table, you must pass a filename argument (see cexp.h)*/\n\nC++ Information\n- - - - - - - -\n\nDynamically loading C++ modules requires additional support.\n\n\t1) static constructors and destructors\n\t2) multiply defined instances of code (templates, multiple inclusion of headers)\n\t3) exception handling\n\nUnfortunately, all of these items are highly implementation dependent and it is therefore\nunlikely that C++ support works for compilers other than gcc. Alas, there are even\nsignificant differences between different versions of gcc and target ABI's.\n\nIMHO, C++ is unreadable, unportable, bloat-prone and should be avoided if at all\npossible. That said, let's dive into the details:\n\n\t1) static constructors and destructors take care of initializing/finalizing\n\t   static objects such as:\n\n\t\tBlahClass\tblahObj(a,b,c);\n\t\tint\t\t\ttest=testInitialize(x,y);\n\n\t   gcc creates code for initializing/finalizing these kinds of objects and\n\t   tags this code with symbols similar to '__GLOBAL__.I.xxx' / '__GLOBAL__.D.xxx'.\n\t   If Cexp encounters such symbols, it builds constructor/destructor lists when\n\t   loading the module and executes the respective code after loading / prior to\n\t   unloading.\n\t   Later versions of gcc use the '__cxa_atexit' callback mechanism which requires\n\t   CEXP to call '__cxa_finalize()' when a module is unloaded. This seems to be\n\t   a C++ ABI standard and is supported by Cexp.\n\t   There are other possible implementations (such as creating special ctor/dtor\n\t   sections) which are not supported - as I said, there is no general way for \n\t   handling C++ :-(\n\n\t2) C++ allows for multiple definitions/instantiations of code (a header included\n\t   by more than one 'xxx.cc' file may define class members) plus there is the\n\t   'template' ''feature'' of C++.\n\t   These let C++ code size _explode_ keeping hardware manufacturers happy.\n\t   Gcc deals with this problem by putting every piece and bit of (possibly\n\t   redundant code and/or data) into a separate '.gnu.linkonce.t.xyzkljsbjj783c'\n\t   SECTION. The idea is that the linker (which is in our case 'Cexp') eliminates\n\t   redundant sections. The sad result are bloated object files and Cexp symbol\n\t   tables (Unfortunately, Cexp must keep _all_ of the zillions of\n\t   '.gnu.linkonce.x.yzu' symbols around since a redundant copy might be\n\t   loaded/linked at any time :-0 )\n\n       You can help CEXP, however by using proper linker scripts when linking\n       large C++ applications (such as EPICS).\n       If you are sure that your large application is the only (C++) object (sharing\n       common code), you may provide the linker with a script which instructs it\n       to integrate _all_ the \"gnu.linkonce.t.xxx\" sections into \".text\" etc.\n\n       If you don't believe me - just let CEXP load an EPICS IOC and list all the\n       'linkonce' symbols:\n\n         lkup(\"linkonce\")\n\n       you will be surprised!\n\t   \n\t3) exception handling (while nice at the abstracion level) is another field\n\t   that is highly architecture/compiler/version dependent and a seed to bloat.\n\t   Even reentrancy might not be taken for granted.\n\t   Gcc uses two flavors of exception handling 'longjmp' and 'eh_frame' style\n\t   which are (to some extent) both supported by Cexp...\n\nAs is said: C++ IS THE DEVIL in the detail. While linking C (and even fortran etc.)\ncode compiled with different compilers (e.g. libraries) is seamless under a common\nABI, it is very complex if not impossible with C++.\n\nImportant PowerPC ABI Information\n---------------------------------\nCexp currently does not support the short data areas according to the SYSV/EABI\nspecifications. Short data sections are merged by Cexp into the normal data\nsegment and hence cannot be accessed via R13/R2. Hence, when compiling loadable\nmodules, the compiler's -msdata flag must not be set to either of 'eabi', 'sysv'\nor 'use'. If you try to load code compiled with an improper -msdata setting,\nyou will get a 'Relocation of unsupported size/type requested' error for the\nrelocation type 'R_PPC_EMB_SDA21' or 'R_PPC_SDAREL16' or similar.\n\nPowerPC Branch Relocation Information\n-------------------------------------\nWhen generating PPC code, gcc usually (i.e., unless giving the -mlongcall\noption which -- according to the gcc documentation -- may some day\ndisappear) emits branch instructions which cannot jump farther than\n+/-32MB from the current PC location. This is a problem on systems with\nmore that 64MB of memory. Since the space required for loadable modules\nis allocated from the regular 'malloc'-heap there is no guarantee\nthat all modules (and the base executable) are all located closely\nenough together to be reachable and the loader may thus fail\ncomplaining that a R_PPC_REL24 relocation cannot be resolved.\n\nIn order to solve this problem, Cexp now supports 'memory segments'\nand tries to load all text sections into a separate segment which\nis smaller than 32M and entirely reachable from the base executable.\n\nThere are different ways for configuring Cexp's PPC text segment:\n\n 1) Do not reserve/use a dedicated text segment (OK for boards\n    with less than 32M of memory).\n 2) Automatically reserve memory for the text segment within the \n    base executable's '.bss' section.\n 3) Application provides memory via a two global variables\n 4) Application provides memory via linker script.\n\nThe Cexp '--enable-text-segment' configuration option is used\nto define the desired behavior when Cexp is 'configure'd.\n\n 1) Configure with '--enable-text-segment=no'\n\n 2) Specify the desired amount of memory to be automatically\n    reserved (in bytes):\n\n\t  --enable-text-segment=\u003cnumber_gt_zero\u003e\n\n\te.g.\n\n\t  --enable-text-segment=0x800000\n\n\tor simply (for a default of 8MB)\n\n\t  --enable-text-segment=yes\n\n 3) Configure with --enable-text-segment=0 (which is also\n    the default, i.e, you may omit the configuration option).\n\n\tThe application must provide two variables\n\n\t  unsigned long cexpTextRegionSize = \u003cdesired size\u003e;\n\t  unsigned char cexpTextRegion[\u003cdesired size\u003e];\n\n 4) Configure with --enable-text-segment=0 (which is also\n    the default, i.e, you may omit the configuration option).\n\n    The application provides two symbols (most likely from\n\ta linker script) defining the start and end of the\n\ttext segment (keep in mind that this region AND the \n\ttext sections of the base executable MUST be closer\n\tthan 32MB together)\n\n\t_cexpTextRegionStart, _cexpTextRegionEnd\n\t\nNOTE: Some BSP's linker script ('linkcmds') for no good reason\n      limit the size of an executable to \u003c4MB by defining a\n\t  MEMORY {} region -- often named 'CODE' -- in the linker\n\t  script which is only 4MB in size. \n\t  When you try to reserve a reasonably sized text segment\n\t  on such a system (e.g., 16MB on a board with 512MB of \n\t  memory) then linking the application will fail because\n\t  it wouldn't fit into the small 'CODE' region.\n\t  You can simply fix this by increasing the size of this\n\t  region to 32MB, e.g., the fixed MEMORY definition of the\n\t  powerpc/shared linkcmds would look like this:\n\n        MEMORY {\n          VECTORS : ORIGIN = 0x0 ,    LENGTH = 0x3000\n             CODE : ORIGIN = 0x3000 , LENGTH = 32M - 0x3000\n        }\n\n\t  (the original LENGTH of CODE was 4MB.)\n\n\nLICENSING \u0026 DISCLAIMERS\n-----------------------\n\nConsult the separate LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftill-s%2Fcexpsh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftill-s%2Fcexpsh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftill-s%2Fcexpsh/lists"}