/* * 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; }