vxWorks includes a command shell that inserts a character table and implements a C expression evaluator so you can call functions, evaluate expressions, and access global characters at runtime. The expression evaluator supports integer and string constants.
When I was working on a project migrated from vxWorks to embOS, I implemented the same functionality. Inserting a symbol table required a bit of gymnastics, as it does not exist until it contacts. I used the post build step to analyze the output of the GNU nm tool to create a symbol table as a separate loading module. In an earlier version, I didn’t insert a character table at all, but rather I created a host shell program that ran on the development node where the character table was located and passed using a debugging stub to a target that could make arbitrary address and read / write function calls arbitrary memory. This approach is better for devices with memory limitations, but you should be careful that the character table you use and the target code are for the same assembly. Again, this was an idea I borrowed from vxWorks that supports both a shell with a target and a host server with the same functionality. For the host shell, vxWorks checks the code to ensure that the symbol table matches; in my case it was a manual (and error prone) process, so I implemented a built-in symbol table.
Although initially I only implemented the read / write capabilities of memory and functions, I later added an expression evaluator based on the algorithm (but not the code) described here . Then after that I added simple scripting capabilities in the form of if-else, while constructs and procedures (using a very simple non-C syntax). Therefore, if you need new functions or tests, you can either write a new function or create a script (if performance was not a problem), so the functions were more like “built-in” scripting languages.
To make arbitrary function calls, I used a typedef function pointer, which took an arbitrarily large (24) number of arguments, then, using the character table, you find the address of the function, sketch it on the type of the function pointer and pass it the real arguments, plus enough dummy arguments to make up the expected number and thus create a suitable (if wasteful) stop frame.
On other systems, I implemented the Forth interpreter, which is a very simple language to implement, but may have less user-friendly syntax. You can also embed an existing solution, such as Lua or Ch.