1 /* 2 * Android "Almost" C Compiler. 3 * This is a compiler for a small subset of the C language, intended for use 4 * in scripting environments where speed and memory footprint are important. 5 * 6 * This code is based upon the "unobfuscated" version of the 7 * Obfuscated Tiny C compiler, see the file LICENSE for details. 8 * 9 */ 10 11 #include <ctype.h> 12 #include <dlfcn.h> 13 #include <stdarg.h> 14 #include <stdint.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #if defined(__arm__) 20 #include <unistd.h> 21 #endif 22 23 #if defined(__arm__) 24 #define PROVIDE_ARM_DISASSEMBLY 25 #endif 26 27 #ifdef PROVIDE_ARM_DISASSEMBLY 28 #include "disassem.h" 29 #endif 30 31 #include <acc/acc.h> 32 33 34 typedef int (*MainPtr)(int, char**); 35 // This is a separate function so it can easily be set by breakpoint in gdb. 36 int run(MainPtr mainFunc, int argc, char** argv) { 37 return mainFunc(argc, argv); 38 } 39 40 ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) { 41 return (ACCvoid*) dlsym(RTLD_DEFAULT, name); 42 } 43 44 #ifdef PROVIDE_ARM_DISASSEMBLY 45 46 static FILE* disasmOut; 47 48 static u_int 49 disassemble_readword(u_int address) 50 { 51 return(*((u_int *)address)); 52 } 53 54 static void 55 disassemble_printaddr(u_int address) 56 { 57 fprintf(disasmOut, "0x%08x", address); 58 } 59 60 static void 61 disassemble_printf(const char *fmt, ...) { 62 va_list ap; 63 va_start(ap, fmt); 64 vfprintf(disasmOut, fmt, ap); 65 va_end(ap); 66 } 67 68 static int disassemble(ACCscript* script, FILE* out) { 69 disasmOut = out; 70 disasm_interface_t di; 71 di.di_readword = disassemble_readword; 72 di.di_printaddr = disassemble_printaddr; 73 di.di_printf = disassemble_printf; 74 75 ACCvoid* base; 76 ACCsizei length; 77 78 accGetProgramBinary(script, &base, &length); 79 unsigned long* pBase = (unsigned long*) base; 80 unsigned long* pEnd = (unsigned long*) (((unsigned char*) base) + length); 81 82 for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) { 83 fprintf(out, "%08x: %08x ", (int) pInstruction, (int) *pInstruction); 84 ::disasm(&di, (uint) pInstruction, 0); 85 } 86 return 0; 87 } 88 89 #endif // PROVIDE_ARM_DISASSEMBLY 90 91 int main(int argc, char** argv) { 92 const char* inFile = NULL; 93 bool printListing; 94 bool runResults = false; 95 FILE* in = stdin; 96 int i; 97 for (i = 1; i < argc; i++) { 98 char* arg = argv[i]; 99 if (arg[0] == '-') { 100 switch (arg[1]) { 101 case 'S': 102 printListing = true; 103 break; 104 case 'R': 105 runResults = true; 106 break; 107 default: 108 fprintf(stderr, "Unrecognized flag %s\n", arg); 109 return 3; 110 } 111 } else if (inFile == NULL) { 112 inFile = arg; 113 } else { 114 break; 115 } 116 } 117 118 if (! inFile) { 119 fprintf(stderr, "input file required\n"); 120 return 2; 121 } 122 123 if (inFile) { 124 in = fopen(inFile, "r"); 125 if (!in) { 126 fprintf(stderr, "Could not open input file %s\n", inFile); 127 return 1; 128 } 129 } 130 131 fseek(in, 0, SEEK_END); 132 size_t fileSize = (size_t) ftell(in); 133 rewind(in); 134 ACCchar* text = new ACCchar[fileSize + 1]; 135 size_t bytesRead = fread(text, 1, fileSize, in); 136 if (bytesRead != fileSize) { 137 fprintf(stderr, "Could not read all of file %s\n", inFile); 138 } 139 140 text[fileSize] = '\0'; 141 142 ACCscript* script = accCreateScript(); 143 144 const ACCchar* scriptSource[] = {text}; 145 accScriptSource(script, 1, scriptSource, NULL); 146 delete[] text; 147 148 accRegisterSymbolCallback(script, symbolLookup, NULL); 149 150 accCompileScript(script); 151 int result = accGetError(script); 152 MainPtr mainPointer = 0; 153 if (result != 0) { 154 ACCsizei bufferLength; 155 accGetScriptInfoLog(script, 0, &bufferLength, NULL); 156 char* buf = (char*) malloc(bufferLength + 1); 157 if (buf != NULL) { 158 accGetScriptInfoLog(script, bufferLength + 1, NULL, buf); 159 fprintf(stderr, "%s", buf); 160 free(buf); 161 } else { 162 fprintf(stderr, "Out of memory.\n"); 163 } 164 goto exit; 165 } 166 167 { 168 ACCsizei numPragmaStrings; 169 accGetPragmas(script, &numPragmaStrings, 0, NULL); 170 if (numPragmaStrings) { 171 char** strings = new char*[numPragmaStrings]; 172 accGetPragmas(script, NULL, numPragmaStrings, strings); 173 for(ACCsizei i = 0; i < numPragmaStrings; i += 2) { 174 fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]); 175 } 176 delete[] strings; 177 } 178 } 179 180 if (printListing) { 181 #ifdef PROVIDE_ARM_DISASSEMBLY 182 disassemble(script, stderr); 183 #endif 184 } 185 186 if (runResults) { 187 accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer); 188 189 result = accGetError(script); 190 if (result != ACC_NO_ERROR) { 191 fprintf(stderr, "Could not find main: %d\n", result); 192 } else { 193 fprintf(stderr, "Executing compiled code:\n"); 194 int codeArgc = argc - i + 1; 195 char** codeArgv = argv + i - 1; 196 codeArgv[0] = (char*) (inFile ? inFile : "stdin"); 197 result = run(mainPointer, codeArgc, codeArgv); 198 fprintf(stderr, "result: %d\n", result); 199 } 200 } 201 202 exit: 203 204 accDeleteScript(script); 205 206 return result; 207 } 208