• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
run(MainPtr mainFunc,int argc,char ** argv)36 int run(MainPtr mainFunc, int argc, char** argv) {
37     return mainFunc(argc, argv);
38 }
39 
symbolLookup(ACCvoid * pContext,const ACCchar * name)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
disassemble_readword(u_int address)49 disassemble_readword(u_int address)
50 {
51     return(*((u_int *)address));
52 }
53 
54 static void
disassemble_printaddr(u_int address)55 disassemble_printaddr(u_int address)
56 {
57     fprintf(disasmOut, "0x%08x", address);
58 }
59 
60 static void
disassemble_printf(const char * fmt,...)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 
disassemble(ACCscript * script,FILE * out)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 
main(int argc,char ** argv)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