diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/Makefile | 3 | ||||
-rw-r--r-- | elf/eval.c | 110 |
2 files changed, 112 insertions, 1 deletions
diff --git a/elf/Makefile b/elf/Makefile index 4b970084af..13fced3b85 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -34,7 +34,7 @@ elide-routines.so = $(dl-routines) dl-support # interpreter and operating independent of libc. rtld-routines := rtld $(dl-routines) dl-sysdep dl-minimal distribute = $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \ - soinit.c sofini.c ldd.sh.in + soinit.c sofini.c ldd.sh.in eval.c extra-libs = libdl libdl-routines := dlopen dlclose dlsym dlerror dladdr @@ -108,4 +108,5 @@ $(objpfx)ldd: ldd.sh.in Makefile # muwahaha +LDFLAGS-dl.so = -Wl,-dynamic-linker,$(slibdir)/$(rtld-installed-name) $(objpfx)libdl.so: $(objpfx)eval.so diff --git a/elf/eval.c b/elf/eval.c new file mode 100644 index 0000000000..91415bb6b6 --- /dev/null +++ b/elf/eval.c @@ -0,0 +1,110 @@ +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <dlfcn.h> + +static void *funcall (char **stringp); +static void *eval (char **stringp); + +static void * +funcall (char **stringp) +{ + void *args[strlen (*stringp)], **ap = args; + void *argcookie = &args[1]; + + do + { + /* Evaluate the next token. */ + *ap++ = eval (stringp); + + /* Whitespace is irrelevant. */ + while (isspace (**stringp)) + ++*stringp; + + /* Terminate at closing paren or end of line. */ + } while (**stringp != '\0' && **stringp != ')'); + if (**stringp != '\0') + /* Swallow closing paren. */ + ++*stringp; + + /* Do it to it. */ + __builtin_return (__builtin_apply (args[0], + &argcookie, + (char *) ap - (char *) &args[1])); +} + +static void * +eval (char **stringp) +{ + void *value; + char *p = *stringp, c; + + /* Whitespace is irrelevant. */ + while (isspace (*p)) + ++p; + + switch (*p) + { + case '"': + /* String constant. */ + value = ++p; + do + if (*p == '\\') + { + switch (*strcpy (p, p + 1)) + { + case 't': + *p = '\t'; + break; + case 'n': + *p = '\n'; + break; + } + ++p; + } + while (*p != '\0' && *p++ != '"'); + if (p[-1] == '"') + p[-1] = '\0'; + break; + + case '(': + *stringp = ++p; + return funcall (stringp); + + default: + /* Try to parse it as a number. */ + value = (void *) strtol (p, stringp, 0); + if (*stringp != p) + return value; + + /* Anything else is a symbol that produces its address. */ + value = p; + do + ++p; + while (*p != '\0' && !isspace (*p) && !ispunct (*p)); + c = *p; + *p = '\0'; + value = dlsym (NULL, value); + *p = c; + break; + } + + *stringp = p; + return value; +} + + +void +_start (void) +{ + char *buf = NULL; + size_t bufsz = 0; + + while (getline (&buf, &bufsz, stdin) > 0) + { + char *p = buf; + eval (&p); + } + + exit (0); +} |