blob: 948f4cb47bce10be5aa20978de7cfa677eadfd11 [file] [log] [blame]
Jack Palevich1cdef202009-05-22 12:06:27 -07001/*
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
Jack Palevichd5315572009-09-09 13:19:34 -070023#if defined(__arm__)
24#define PROVIDE_ARM_DISASSEMBLY
25#endif
26
27#ifdef PROVIDE_ARM_DISASSEMBLY
28#include "disassem.h"
29#endif
30
Jack Palevich1cdef202009-05-22 12:06:27 -070031#include <acc/acc.h>
32
33
34typedef int (*MainPtr)(int, char**);
35// This is a separate function so it can easily be set by breakpoint in gdb.
36int run(MainPtr mainFunc, int argc, char** argv) {
37 return mainFunc(argc, argv);
38}
39
Jack Palevich8c246a92009-07-14 21:14:10 -070040ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) {
Jack Palevich66d48742009-10-27 13:58:08 -070041 // Call dlerror once to clear out any preexisting error condition.
42 (void) dlerror();
43 ACCvoid* result = (ACCvoid*) dlsym(RTLD_DEFAULT, name);
44 const char* error = dlerror();
45 if (error) {
46 fprintf(stderr, "%s\"%s\"\n", error, name);
47 }
48 return result;
Jack Palevich8c246a92009-07-14 21:14:10 -070049}
50
Jack Palevichd5315572009-09-09 13:19:34 -070051#ifdef PROVIDE_ARM_DISASSEMBLY
52
53static FILE* disasmOut;
54
55static u_int
56disassemble_readword(u_int address)
57{
58 return(*((u_int *)address));
59}
60
61static void
62disassemble_printaddr(u_int address)
63{
64 fprintf(disasmOut, "0x%08x", address);
65}
66
67static void
68disassemble_printf(const char *fmt, ...) {
69 va_list ap;
70 va_start(ap, fmt);
71 vfprintf(disasmOut, fmt, ap);
72 va_end(ap);
73}
74
75static int disassemble(ACCscript* script, FILE* out) {
76 disasmOut = out;
77 disasm_interface_t di;
78 di.di_readword = disassemble_readword;
79 di.di_printaddr = disassemble_printaddr;
80 di.di_printf = disassemble_printf;
81
82 ACCvoid* base;
83 ACCsizei length;
84
85 accGetProgramBinary(script, &base, &length);
86 unsigned long* pBase = (unsigned long*) base;
87 unsigned long* pEnd = (unsigned long*) (((unsigned char*) base) + length);
88
89 for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) {
Jack Palevich1c60e462009-09-18 15:03:03 -070090 fprintf(out, "%08x: %08x ", (int) pInstruction, (int) *pInstruction);
Jack Palevichd5315572009-09-09 13:19:34 -070091 ::disasm(&di, (uint) pInstruction, 0);
92 }
93 return 0;
94}
95
96#endif // PROVIDE_ARM_DISASSEMBLY
97
Jack Palevich1cdef202009-05-22 12:06:27 -070098int main(int argc, char** argv) {
99 const char* inFile = NULL;
100 bool printListing;
Jack Palevich36d94142009-06-08 15:55:32 -0700101 bool runResults = false;
Jack Palevich1cdef202009-05-22 12:06:27 -0700102 FILE* in = stdin;
103 int i;
104 for (i = 1; i < argc; i++) {
105 char* arg = argv[i];
106 if (arg[0] == '-') {
107 switch (arg[1]) {
108 case 'S':
109 printListing = true;
110 break;
Jack Palevich36d94142009-06-08 15:55:32 -0700111 case 'R':
112 runResults = true;
113 break;
Jack Palevich1cdef202009-05-22 12:06:27 -0700114 default:
115 fprintf(stderr, "Unrecognized flag %s\n", arg);
116 return 3;
117 }
118 } else if (inFile == NULL) {
119 inFile = arg;
120 } else {
121 break;
122 }
123 }
124
125 if (! inFile) {
126 fprintf(stderr, "input file required\n");
127 return 2;
128 }
129
130 if (inFile) {
131 in = fopen(inFile, "r");
132 if (!in) {
133 fprintf(stderr, "Could not open input file %s\n", inFile);
134 return 1;
135 }
136 }
137
138 fseek(in, 0, SEEK_END);
139 size_t fileSize = (size_t) ftell(in);
140 rewind(in);
Jack Palevichb7c81e92009-06-04 19:56:13 -0700141 ACCchar* text = new ACCchar[fileSize + 1];
Jack Palevich1cdef202009-05-22 12:06:27 -0700142 size_t bytesRead = fread(text, 1, fileSize, in);
143 if (bytesRead != fileSize) {
144 fprintf(stderr, "Could not read all of file %s\n", inFile);
145 }
146
Jack Palevichb7c81e92009-06-04 19:56:13 -0700147 text[fileSize] = '\0';
148
Jack Palevich1cdef202009-05-22 12:06:27 -0700149 ACCscript* script = accCreateScript();
150
151 const ACCchar* scriptSource[] = {text};
152 accScriptSource(script, 1, scriptSource, NULL);
153 delete[] text;
154
Jack Palevich8c246a92009-07-14 21:14:10 -0700155 accRegisterSymbolCallback(script, symbolLookup, NULL);
156
Jack Palevich1cdef202009-05-22 12:06:27 -0700157 accCompileScript(script);
Jack Palevichac0e95e2009-05-29 13:53:44 -0700158 int result = accGetError(script);
Jack Palevich1cdef202009-05-22 12:06:27 -0700159 MainPtr mainPointer = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700160 if (result != 0) {
Jack Palevich1c60e462009-09-18 15:03:03 -0700161 ACCsizei bufferLength;
162 accGetScriptInfoLog(script, 0, &bufferLength, NULL);
163 char* buf = (char*) malloc(bufferLength + 1);
164 if (buf != NULL) {
165 accGetScriptInfoLog(script, bufferLength + 1, NULL, buf);
166 fprintf(stderr, "%s", buf);
167 free(buf);
168 } else {
169 fprintf(stderr, "Out of memory.\n");
170 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700171 goto exit;
172 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700173
Jack Palevicheedf9d22009-06-04 16:23:40 -0700174 {
175 ACCsizei numPragmaStrings;
176 accGetPragmas(script, &numPragmaStrings, 0, NULL);
177 if (numPragmaStrings) {
178 char** strings = new char*[numPragmaStrings];
179 accGetPragmas(script, NULL, numPragmaStrings, strings);
180 for(ACCsizei i = 0; i < numPragmaStrings; i += 2) {
181 fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]);
182 }
183 delete[] strings;
184 }
185 }
186
-b master422972c2009-06-17 19:13:52 -0700187 if (printListing) {
Jack Palevichd5315572009-09-09 13:19:34 -0700188#ifdef PROVIDE_ARM_DISASSEMBLY
189 disassemble(script, stderr);
190#endif
-b master422972c2009-06-17 19:13:52 -0700191 }
192
Jack Palevich2db168f2009-06-11 14:29:47 -0700193 if (runResults) {
194 accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer);
Jack Palevich1cdef202009-05-22 12:06:27 -0700195
Jack Palevich2db168f2009-06-11 14:29:47 -0700196 result = accGetError(script);
197 if (result != ACC_NO_ERROR) {
198 fprintf(stderr, "Could not find main: %d\n", result);
199 } else {
200 fprintf(stderr, "Executing compiled code:\n");
201 int codeArgc = argc - i + 1;
202 char** codeArgv = argv + i - 1;
203 codeArgv[0] = (char*) (inFile ? inFile : "stdin");
204 result = run(mainPointer, codeArgc, codeArgv);
205 fprintf(stderr, "result: %d\n", result);
206 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700207 }
208
Jack Palevichac0e95e2009-05-29 13:53:44 -0700209exit:
210
Jack Palevich1cdef202009-05-22 12:06:27 -0700211 accDeleteScript(script);
212
213 return result;
214}