| /* |
| * Android "Almost" C Compiler. |
| * This is a compiler for a small subset of the C language, intended for use |
| * in scripting environments where speed and memory footprint are important. |
| * |
| * This code is based upon the "unobfuscated" version of the |
| * Obfuscated Tiny C compiler, see the file LICENSE for details. |
| * |
| */ |
| |
| #include <ctype.h> |
| #include <dlfcn.h> |
| #include <stdarg.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #if defined(__arm__) |
| #include <unistd.h> |
| #endif |
| |
| #if defined(__arm__) |
| #define PROVIDE_ARM_DISASSEMBLY |
| #endif |
| |
| #ifdef PROVIDE_ARM_DISASSEMBLY |
| #include "disassem.h" |
| #endif |
| |
| #include <acc/acc.h> |
| |
| |
| typedef int (*MainPtr)(int, char**); |
| // This is a separate function so it can easily be set by breakpoint in gdb. |
| int run(MainPtr mainFunc, int argc, char** argv) { |
| return mainFunc(argc, argv); |
| } |
| |
| ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) { |
| return (ACCvoid*) dlsym(RTLD_DEFAULT, name); |
| } |
| |
| #ifdef PROVIDE_ARM_DISASSEMBLY |
| |
| static FILE* disasmOut; |
| |
| static u_int |
| disassemble_readword(u_int address) |
| { |
| return(*((u_int *)address)); |
| } |
| |
| static void |
| disassemble_printaddr(u_int address) |
| { |
| fprintf(disasmOut, "0x%08x", address); |
| } |
| |
| static void |
| disassemble_printf(const char *fmt, ...) { |
| va_list ap; |
| va_start(ap, fmt); |
| vfprintf(disasmOut, fmt, ap); |
| va_end(ap); |
| } |
| |
| static int disassemble(ACCscript* script, FILE* out) { |
| disasmOut = out; |
| disasm_interface_t di; |
| di.di_readword = disassemble_readword; |
| di.di_printaddr = disassemble_printaddr; |
| di.di_printf = disassemble_printf; |
| |
| ACCvoid* base; |
| ACCsizei length; |
| |
| accGetProgramBinary(script, &base, &length); |
| unsigned long* pBase = (unsigned long*) base; |
| unsigned long* pEnd = (unsigned long*) (((unsigned char*) base) + length); |
| |
| for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) { |
| fprintf(out, "%08x: %08x ", (int) pInstruction, (int) *pInstruction); |
| ::disasm(&di, (uint) pInstruction, 0); |
| } |
| return 0; |
| } |
| |
| #endif // PROVIDE_ARM_DISASSEMBLY |
| |
| int main(int argc, char** argv) { |
| const char* inFile = NULL; |
| bool printListing; |
| bool runResults = false; |
| FILE* in = stdin; |
| int i; |
| for (i = 1; i < argc; i++) { |
| char* arg = argv[i]; |
| if (arg[0] == '-') { |
| switch (arg[1]) { |
| case 'S': |
| printListing = true; |
| break; |
| case 'R': |
| runResults = true; |
| break; |
| default: |
| fprintf(stderr, "Unrecognized flag %s\n", arg); |
| return 3; |
| } |
| } else if (inFile == NULL) { |
| inFile = arg; |
| } else { |
| break; |
| } |
| } |
| |
| if (! inFile) { |
| fprintf(stderr, "input file required\n"); |
| return 2; |
| } |
| |
| if (inFile) { |
| in = fopen(inFile, "r"); |
| if (!in) { |
| fprintf(stderr, "Could not open input file %s\n", inFile); |
| return 1; |
| } |
| } |
| |
| fseek(in, 0, SEEK_END); |
| size_t fileSize = (size_t) ftell(in); |
| rewind(in); |
| ACCchar* text = new ACCchar[fileSize + 1]; |
| size_t bytesRead = fread(text, 1, fileSize, in); |
| if (bytesRead != fileSize) { |
| fprintf(stderr, "Could not read all of file %s\n", inFile); |
| } |
| |
| text[fileSize] = '\0'; |
| |
| ACCscript* script = accCreateScript(); |
| |
| const ACCchar* scriptSource[] = {text}; |
| accScriptSource(script, 1, scriptSource, NULL); |
| delete[] text; |
| |
| accRegisterSymbolCallback(script, symbolLookup, NULL); |
| |
| accCompileScript(script); |
| int result = accGetError(script); |
| MainPtr mainPointer = 0; |
| if (result != 0) { |
| ACCsizei bufferLength; |
| accGetScriptInfoLog(script, 0, &bufferLength, NULL); |
| char* buf = (char*) malloc(bufferLength + 1); |
| if (buf != NULL) { |
| accGetScriptInfoLog(script, bufferLength + 1, NULL, buf); |
| fprintf(stderr, "%s", buf); |
| free(buf); |
| } else { |
| fprintf(stderr, "Out of memory.\n"); |
| } |
| goto exit; |
| } |
| |
| { |
| ACCsizei numPragmaStrings; |
| accGetPragmas(script, &numPragmaStrings, 0, NULL); |
| if (numPragmaStrings) { |
| char** strings = new char*[numPragmaStrings]; |
| accGetPragmas(script, NULL, numPragmaStrings, strings); |
| for(ACCsizei i = 0; i < numPragmaStrings; i += 2) { |
| fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]); |
| } |
| delete[] strings; |
| } |
| } |
| |
| if (printListing) { |
| #ifdef PROVIDE_ARM_DISASSEMBLY |
| disassemble(script, stderr); |
| #endif |
| } |
| |
| if (runResults) { |
| accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer); |
| |
| result = accGetError(script); |
| if (result != ACC_NO_ERROR) { |
| fprintf(stderr, "Could not find main: %d\n", result); |
| } else { |
| fprintf(stderr, "Executing compiled code:\n"); |
| int codeArgc = argc - i + 1; |
| char** codeArgv = argv + i - 1; |
| codeArgv[0] = (char*) (inFile ? inFile : "stdin"); |
| result = run(mainPointer, codeArgc, codeArgv); |
| fprintf(stderr, "result: %d\n", result); |
| } |
| } |
| |
| exit: |
| |
| accDeleteScript(script); |
| |
| return result; |
| } |